OpenGL: Start modular renderer

This commit is contained in:
Jeffrey Pfau 2015-06-03 23:30:56 -07:00
parent 71e372bcf4
commit ea0b6a14cc
6 changed files with 206 additions and 95 deletions

117
src/platform/opengl/gl.c Normal file
View File

@ -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;
}

25
src/platform/opengl/gl.h Normal file
View File

@ -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

View File

@ -67,6 +67,7 @@ else()
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c) list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c)
if(BUILD_GL) if(BUILD_GL)
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-sdl.c) 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) add_definitions(-DBUILD_GL)
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR}) include_directories(${OPENGL_INCLUDE_DIR})

View File

@ -6,47 +6,22 @@
#include "main.h" #include "main.h"
#include "gba/supervisor/thread.h" #include "gba/supervisor/thread.h"
#include "platform/opengl/gl.h"
#ifdef __APPLE__ static void _sdlSwap(struct VideoBackend* context) {
#include <OpenGL/gl.h> struct SDLSoftwareRenderer* renderer = (struct SDLSoftwareRenderer*) context->user;
#else
#include <GL/gl.h>
#endif
#ifdef BUILD_GL
static const GLint _glVertices[] = {
0, 0,
256, 0,
256, 256,
0, 256
};
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);
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_GL_SwapWindow(renderer->window); SDL_GL_SwapWindow(renderer->window);
#else #else
SDL_GL_SwapBuffers(); SDL_GL_SwapBuffers();
#endif #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); static bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer);
@ -89,48 +64,24 @@ bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer) {
#endif #endif
#endif #endif
renderer->d.outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); renderer->d.outputBuffer = malloc(256 * 256 * BYTES_PER_PIXEL);
renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS; renderer->d.outputBufferStride = 256;
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
#ifdef COLOR_16_BIT GBAGLContextCreate(&renderer->gl);
#ifdef COLOR_5_6_5 renderer->gl.d.user = renderer;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio;
#else renderer->gl.d.filter = renderer->filter;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0); renderer->gl.d.swap = _sdlSwap;
#endif renderer->gl.d.init(&renderer->gl.d, 0);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
#endif
_doViewport(renderer->viewportWidth, renderer->viewportHeight, renderer); _doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
return true; return true;
} }
void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) { void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
SDL_Event event; 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 (context->state < THREAD_EXITING) {
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
GBASDLHandleEvent(context, &renderer->player, &event); GBASDLHandleEvent(context, &renderer->player, &event);
@ -138,37 +89,24 @@ void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* rend
// Event handling can change the size of the screen // Event handling can change the size of the screen
if (renderer->player.windowUpdated) { if (renderer->player.windowUpdated) {
SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight); SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
_doViewport(renderer->viewportWidth, renderer->viewportHeight, renderer); _doViewport(renderer->viewportWidth, renderer->viewportHeight, v);
renderer->player.windowUpdated = 0; renderer->player.windowUpdated = 0;
} }
#endif #endif
} }
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {
glBindTexture(GL_TEXTURE_2D, renderer->tex); v->postFrame(v, renderer->d.outputBuffer);
#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->drawFrame(v);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
GBASyncWaitFrameEnd(&context->sync); GBASyncWaitFrameEnd(&context->sync);
#if SDL_VERSION_ATLEAST(2, 0, 0) v->swap(v);
SDL_GL_SwapWindow(renderer->window);
#else
SDL_GL_SwapBuffers();
#endif
} }
} }
void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer) { void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer) {
if (renderer->gl.d.deinit) {
renderer->gl.d.deinit(&renderer->gl.d);
}
free(renderer->d.outputBuffer); free(renderer->d.outputBuffer);
} }

View File

@ -12,11 +12,7 @@
#include "sdl-events.h" #include "sdl-events.h"
#ifdef BUILD_GL #ifdef BUILD_GL
#ifdef __APPLE__ #include "platform/opengl/gl.h"
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif
#endif #endif
#ifdef BUILD_RASPI #ifdef BUILD_RASPI
@ -59,7 +55,7 @@ struct SDLSoftwareRenderer {
bool filter; bool filter;
#ifdef BUILD_GL #ifdef BUILD_GL
GLuint tex; struct GBAGLContext gl;
#endif #endif
#ifdef USE_PIXMAN #ifdef USE_PIXMAN

View File

@ -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