OpenGL: Start modular renderer
Jeffrey Pfau jeffrey@endrift.com
Wed, 03 Jun 2015 23:30:56 -0700
6 files changed,
206 insertions(+),
95 deletions(-)
A
src/platform/opengl/gl.c
@@ -0,0 +1,117 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "gl.h" + +#include "gba/video.h" + +static const GLint _glVertices[] = { + 0, 0, + 256, 0, + 256, 256, + 0, 256 +}; + +static const GLint _glTexCoords[] = { + 0, 0, + 1, 0, + 1, 1, + 0, 1 +}; + +static void GBAGLContextInit(struct VideoBackend* v, WHandle handle) { + UNUSED(handle); + struct GBAGLContext* context = (struct GBAGLContext*) v; + glGenTextures(1, &context->tex); + glBindTexture(GL_TEXTURE_2D, context->tex); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +#ifndef _WIN32 + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#endif + +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); +#else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0); +#endif +#else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); +#endif +} + +static void GBAGLContextDeinit(struct VideoBackend* v) { + struct GBAGLContext* context = (struct GBAGLContext*) v; + glDeleteTextures(1, &context->tex); +} + +static void GBAGLContextResized(struct VideoBackend* v, int w, int h) { + int drawW = w; + int drawH = h; + if (v->lockAspectRatio) { + if (w * 2 > h * 3) { + drawW = h * 3 / 2; + } else if (w * 2 < h * 3) { + drawH = w * 2 / 3; + } + } + glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH); +} + +static void GBAGLContextClear(struct VideoBackend* v) { + UNUSED(v); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); +} + +void GBAGLContextDrawFrame(struct VideoBackend* v) { + struct GBAGLContext* context = (struct GBAGLContext*) v; + glEnable(GL_TEXTURE_2D); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_INT, 0, _glVertices); + glTexCoordPointer(2, GL_INT, 0, _glTexCoords); + glMatrixMode (GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glBindTexture(GL_TEXTURE_2D, context->tex); + if (v->filter) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +} + +void GBAGLContextPostFrame(struct VideoBackend* v, const void* frame) { + struct GBAGLContext* context = (struct GBAGLContext*) v; + glBindTexture(GL_TEXTURE_2D, context->tex); +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame); +#else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); +#endif +#else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame); +#endif +} + +void GBAGLContextCreate(struct GBAGLContext* context) { + context->d.init = GBAGLContextInit; + context->d.deinit = GBAGLContextDeinit; + context->d.resized = GBAGLContextResized; + context->d.swap = 0; + context->d.clear = GBAGLContextClear; + context->d.postFrame = GBAGLContextPostFrame; + context->d.drawFrame = GBAGLContextDrawFrame; + context->d.setMessage = 0; + context->d.clearMessage = 0; +}
A
src/platform/opengl/gl.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GL_H +#define GL_H + +#ifdef __APPLE__ +#include <OpenGL/gl.h> +#else +#include <GL/gl.h> +#endif + +#include "platform/video-backend.h" + +struct GBAGLContext { + struct VideoBackend d; + + GLuint tex; +}; + +void GBAGLContextCreate(struct GBAGLContext*); + +#endif
M
src/platform/sdl/CMakeLists.txt
→
src/platform/sdl/CMakeLists.txt
@@ -67,6 +67,7 @@ else()
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c) if(BUILD_GL) list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-sdl.c) + list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c) add_definitions(-DBUILD_GL) find_package(OpenGL REQUIRED) include_directories(${OPENGL_INCLUDE_DIR})
M
src/platform/sdl/gl-sdl.c
→
src/platform/sdl/gl-sdl.c
@@ -6,47 +6,22 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "main.h" #include "gba/supervisor/thread.h" - -#ifdef __APPLE__ -#include <OpenGL/gl.h> -#else -#include <GL/gl.h> -#endif - -#ifdef BUILD_GL -static const GLint _glVertices[] = { - 0, 0, - 256, 0, - 256, 256, - 0, 256 -}; +#include "platform/opengl/gl.h" -static const GLint _glTexCoords[] = { - 0, 0, - 1, 0, - 1, 1, - 0, 1 -}; -#endif - -static void _doViewport(int w, int h, struct SDLSoftwareRenderer* renderer) { - int drawW = w; - int drawH = h; - if (renderer->lockAspectRatio) { - if (w * 2 > h * 3) { - drawW = h * 3 / 2; - } else if (w * 2 < h * 3) { - drawH = w * 2 / 3; - } - } - glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH); - glClear(GL_COLOR_BUFFER_BIT); +static void _sdlSwap(struct VideoBackend* context) { + struct SDLSoftwareRenderer* renderer = (struct SDLSoftwareRenderer*) context->user; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_GL_SwapWindow(renderer->window); #else SDL_GL_SwapBuffers(); #endif - glClear(GL_COLOR_BUFFER_BIT); +} + +static void _doViewport(int w, int h, struct VideoBackend* v) { + v->resized(v, w, h); + v->clear(v); + v->swap(v); + v->clear(v); } static bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer);@@ -89,48 +64,24 @@ SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 32, SDL_OPENGL);
#endif #endif - renderer->d.outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); - renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS; - glGenTextures(1, &renderer->tex); - glBindTexture(GL_TEXTURE_2D, renderer->tex); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - if (renderer->filter) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } else { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } -#ifndef _WIN32 - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -#endif + renderer->d.outputBuffer = malloc(256 * 256 * BYTES_PER_PIXEL); + renderer->d.outputBufferStride = 256; -#ifdef COLOR_16_BIT -#ifdef COLOR_5_6_5 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0); -#endif -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -#endif + GBAGLContextCreate(&renderer->gl); + renderer->gl.d.user = renderer; + renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio; + renderer->gl.d.filter = renderer->filter; + renderer->gl.d.swap = _sdlSwap; + renderer->gl.d.init(&renderer->gl.d, 0); - _doViewport(renderer->viewportWidth, renderer->viewportHeight, renderer); + _doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d); return true; } void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) { SDL_Event event; + struct VideoBackend* v = &renderer->gl.d; - glEnable(GL_TEXTURE_2D); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_INT, 0, _glVertices); - glTexCoordPointer(2, GL_INT, 0, _glTexCoords); - glMatrixMode (GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, 0, 1); while (context->state < THREAD_EXITING) { while (SDL_PollEvent(&event)) { GBASDLHandleEvent(context, &renderer->player, &event);@@ -138,37 +89,24 @@ #if SDL_VERSION_ATLEAST(2, 0, 0)
// Event handling can change the size of the screen if (renderer->player.windowUpdated) { SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight); - _doViewport(renderer->viewportWidth, renderer->viewportHeight, renderer); + _doViewport(renderer->viewportWidth, renderer->viewportHeight, v); renderer->player.windowUpdated = 0; } #endif } if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { - glBindTexture(GL_TEXTURE_2D, renderer->tex); -#ifdef COLOR_16_BIT -#ifdef COLOR_5_6_5 - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, renderer->d.outputBuffer); -#else - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, renderer->d.outputBuffer); -#endif -#else - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_BYTE, renderer->d.outputBuffer); -#endif - if (context->sync.videoFrameWait) { - glFlush(); - } + v->postFrame(v, renderer->d.outputBuffer); } - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + v->drawFrame(v); GBASyncWaitFrameEnd(&context->sync); -#if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_GL_SwapWindow(renderer->window); -#else - SDL_GL_SwapBuffers(); -#endif + v->swap(v); } } void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer) { + if (renderer->gl.d.deinit) { + renderer->gl.d.deinit(&renderer->gl.d); + } free(renderer->d.outputBuffer); }
M
src/platform/sdl/main.h
→
src/platform/sdl/main.h
@@ -12,11 +12,7 @@ #include "sdl-audio.h"
#include "sdl-events.h" #ifdef BUILD_GL -#ifdef __APPLE__ -#include <OpenGL/gl.h> -#else -#include <GL/gl.h> -#endif +#include "platform/opengl/gl.h" #endif #ifdef BUILD_RASPI@@ -59,7 +55,7 @@ bool lockAspectRatio;
bool filter; #ifdef BUILD_GL - GLuint tex; + struct GBAGLContext gl; #endif #ifdef USE_PIXMAN
A
src/platform/video-backend.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef VIDEO_BACKEND_H +#define VIDEO_BACKEND_H + +#include "util/common.h" + +#ifdef _WIN32 +typedef HWND WHandle; +#else +typedef void* WHandle; +#endif + +struct VideoBackend { + void (*init)(struct VideoBackend*, WHandle handle); + void (*deinit)(struct VideoBackend*); + void (*swap)(struct VideoBackend*); + void (*clear)(struct VideoBackend*); + void (*resized)(struct VideoBackend*, int w, int h); + void (*postFrame)(struct VideoBackend*, const void* frame); + void (*drawFrame)(struct VideoBackend*); + void (*setMessage)(struct VideoBackend*, const char* message); + void (*clearMessage)(struct VideoBackend*); + + void* user; + + bool filter; + bool lockAspectRatio; +}; + +#endif