Start GLSL renderer

This commit is contained in:
Jeffrey Pfau 2013-05-07 01:04:36 -07:00
parent db96be98dc
commit bb1e598a78
4 changed files with 453 additions and 79 deletions

View File

@ -0,0 +1,177 @@
#include "video-glsl.h"
#include <string.h>
#define UNIFORM_LOCATION(UNIFORM) (glGetUniformLocation(glslRenderer->program, UNIFORM))
static const GLfloat _vertices[4] = {
-1, 0,
1, 0
};
static const GLchar* _fragmentShader[] = {
"uniform float y;",
"uniform sampler2D palette;",
"void main() {",
" gl_FragColor = texture2D(palette, vec2(0, y / 256.0));",
"}"
};
static const GLchar* _vertexShader[] = {
"attribute vec2 vert;",
"uniform float y;",
"void main() {",
" gl_Position = vec4(vert.x, 1.0 - y / 80.0, 0, 1.0);",
"}"
};
static void GBAVideoGLSLRendererInit(struct GBAVideoRenderer* renderer);
static void GBAVideoGLSLRendererDeinit(struct GBAVideoRenderer* renderer);
static void GBAVideoGLSLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
static uint16_t GBAVideoGLSLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
static void GBAVideoGLSLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
static void GBAVideoGLSLRendererFinishFrame(struct GBAVideoRenderer* renderer);
void GBAVideoGLSLRendererCreate(struct GBAVideoGLSLRenderer* glslRenderer) {
glslRenderer->d.init = GBAVideoGLSLRendererInit;
glslRenderer->d.deinit = GBAVideoGLSLRendererDeinit;
glslRenderer->d.writeVideoRegister = GBAVideoGLSLRendererWriteVideoRegister;
glslRenderer->d.writePalette = GBAVideoGLSLRendererWritePalette;
glslRenderer->d.drawScanline = GBAVideoGLSLRendererDrawScanline;
glslRenderer->d.finishFrame = GBAVideoGLSLRendererFinishFrame;
glslRenderer->d.turbo = 0;
glslRenderer->d.framesPending = 0;
glslRenderer->d.frameskip = 0;
glslRenderer->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glslRenderer->vertexShader = glCreateShader(GL_VERTEX_SHADER);
glslRenderer->program = glCreateProgram();
glShaderSource(glslRenderer->fragmentShader, 5, _fragmentShader, 0);
glShaderSource(glslRenderer->vertexShader, 5, _vertexShader, 0);
glAttachShader(glslRenderer->program, glslRenderer->vertexShader);
glAttachShader(glslRenderer->program, glslRenderer->fragmentShader);
char log[1024];
glCompileShader(glslRenderer->fragmentShader);
glCompileShader(glslRenderer->vertexShader);
glGetShaderInfoLog(glslRenderer->fragmentShader, 1024, 0, log);
glGetShaderInfoLog(glslRenderer->vertexShader, 1024, 0, log);
glLinkProgram(glslRenderer->program);
glGenTextures(1, &glslRenderer->vramTexture);
glBindTexture(GL_TEXTURE_2D, glslRenderer->vramTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
memset(glslRenderer->vram, 0, sizeof (glslRenderer->vram));
{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
glslRenderer->mutex = mutex;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
glslRenderer->upCond = cond;
glslRenderer->downCond = cond;
}
}
void GBAVideoGLSLRendererProcessEvents(struct GBAVideoGLSLRenderer* glslRenderer) {
glUseProgram(glslRenderer->program);
glUniform1i(UNIFORM_LOCATION("palette"), 0);
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, glslRenderer->vramTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, glslRenderer->vram);
GLuint location = glGetAttribLocation(glslRenderer->program, "vert");
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
int y;
for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) {
glUniform1f(UNIFORM_LOCATION("y"), y);
glDrawArrays(GL_LINES, 0, 2);
}
glDisableVertexAttribArray(location);
glFlush();
}
static void GBAVideoGLSLRendererInit(struct GBAVideoRenderer* renderer) {
struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
glslRenderer->state = GLSL_NONE;
glslRenderer->y = 0;
pthread_mutex_init(&glslRenderer->mutex, 0);
pthread_cond_init(&glslRenderer->upCond, 0);
pthread_cond_init(&glslRenderer->downCond, 0);
}
static void GBAVideoGLSLRendererDeinit(struct GBAVideoRenderer* renderer) {
struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
/*glDeleteShader(glslRenderer->fragmentShader);
glDeleteShader(glslRenderer->vertexShader);
glDeleteProgram(glslRenderer->program);
glDeleteTextures(1, &glslRenderer->paletteTexture);*/
pthread_mutex_lock(&glslRenderer->mutex);
pthread_cond_broadcast(&glslRenderer->upCond);
pthread_mutex_unlock(&glslRenderer->mutex);
pthread_mutex_destroy(&glslRenderer->mutex);
pthread_cond_destroy(&glslRenderer->upCond);
pthread_cond_destroy(&glslRenderer->downCond);
}
static void GBAVideoGLSLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
GLshort color = 0;
color |= (value & 0x001F) << 11;
color |= (value & 0x03E0) << 1;
color |= (value & 0x7C00) >> 9;
glslRenderer->vram[(address >> 1) + glslRenderer->y * 512] = color;
}
static uint16_t GBAVideoGLSLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
(void)(glslRenderer);
(void)(address);
return value;
}
static void GBAVideoGLSLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
glslRenderer->y = y + 1;
if (y + 1 < VIDEO_VERTICAL_PIXELS) {
memcpy(&glslRenderer->vram[(y + 1) * 512], &glslRenderer->vram[y * 512], 1024);
} else {
glslRenderer->y = 0;
memcpy(&glslRenderer->vram[0], &glslRenderer->vram[y * 512], 1024);
}
}
static void GBAVideoGLSLRendererFinishFrame(struct GBAVideoRenderer* renderer) {
struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
pthread_mutex_lock(&glslRenderer->mutex);
glslRenderer->state = GLSL_NONE;
if (renderer->frameskip > 0) {
--renderer->frameskip;
} else {
renderer->framesPending++;
pthread_cond_broadcast(&glslRenderer->upCond);
if (!renderer->turbo) {
pthread_cond_wait(&glslRenderer->downCond, &glslRenderer->mutex);
}
}
pthread_mutex_unlock(&glslRenderer->mutex);
}

View File

@ -0,0 +1,39 @@
#ifndef VIDEO_GLSL_H
#define VIDEO_GLSL_H
#include "gba-video.h"
#include <pthread.h>
#ifdef __APPLE__
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif
struct GBAVideoGLSLRenderer {
struct GBAVideoRenderer d;
int y;
enum {
GLSL_NONE,
GLSL_DRAW_SCANLINE,
GLSL_FINISH_FRAME
} state;
GLuint fragmentShader;
GLuint vertexShader;
GLuint program;
GLuint vramTexture;
GLushort vram[512 * 256];
pthread_mutex_t mutex;
pthread_cond_t upCond;
pthread_cond_t downCond;
};
void GBAVideoGLSLRendererCreate(struct GBAVideoGLSLRenderer* renderer);
void GBAVideoGLSLRendererProcessEvents(struct GBAVideoGLSLRenderer* renderer);
#endif

View File

@ -1,7 +1,7 @@
#include "debugger.h" #include "debugger.h"
#include "gba-thread.h" #include "gba-thread.h"
#include "gba.h" #include "gba.h"
#include "renderers/video-software.h" #include "renderers/video-glsl.h"
#include <SDL.h> #include <SDL.h>
#ifdef __APPLE__ #ifdef __APPLE__
@ -16,30 +16,11 @@
#include <sys/time.h> #include <sys/time.h>
#include <unistd.h> #include <unistd.h>
struct GLSoftwareRenderer { static int _GBASDLInit(void);
struct GBAVideoSoftwareRenderer d; static void _GBASDLDeinit(void);
static void _GBASDLRunloop(struct GBAThread* context, struct GBAVideoGLSLRenderer* renderer);
GLuint tex;
};
static int _GBASDLInit(struct GLSoftwareRenderer* renderer);
static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer);
static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer* renderer);
static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_KeyboardEvent* event); static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_KeyboardEvent* event);
static const GLint _glVertices[] = {
0, 0,
256, 0,
256, 256,
0, 256
};
static const GLint _glTexCoords[] = {
0, 0,
1, 0,
1, 1,
0, 1
};
int main(int argc, char** argv) { int main(int argc, char** argv) {
const char* fname = "test.rom"; const char* fname = "test.rom";
@ -51,21 +32,16 @@ int main(int argc, char** argv) {
return 1; return 1;
} }
sigset_t signals;
sigaddset(&signals, SIGINT);
sigaddset(&signals, SIGTRAP);
pthread_sigmask(SIG_BLOCK, &signals, 0);
struct GBAThread context; struct GBAThread context;
struct GLSoftwareRenderer renderer; struct GBAVideoGLSLRenderer renderer;
GBAVideoSoftwareRendererCreate(&renderer.d);
if (!_GBASDLInit(&renderer)) { if (!_GBASDLInit()) {
return 1; return 1;
} }
GBAVideoGLSLRendererCreate(&renderer);
context.fd = fd; context.fd = fd;
context.renderer = &renderer.d.d; context.renderer = &renderer.d;
GBAThreadStart(&context); GBAThreadStart(&context);
_GBASDLRunloop(&context, &renderer); _GBASDLRunloop(&context, &renderer);
@ -73,12 +49,12 @@ int main(int argc, char** argv) {
GBAThreadJoin(&context); GBAThreadJoin(&context);
close(fd); close(fd);
_GBASDLDeinit(&renderer); _GBASDLDeinit();
return 0; return 0;
} }
static int _GBASDLInit(struct GLSoftwareRenderer* renderer) { static int _GBASDLInit() {
if (SDL_Init(SDL_INIT_VIDEO) < 0) { if (SDL_Init(SDL_INIT_VIDEO) < 0) {
return 0; return 0;
} }
@ -90,41 +66,21 @@ static int _GBASDLInit(struct GLSoftwareRenderer* renderer) {
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_SetVideoMode(240, 160, 32, SDL_OPENGL); SDL_SetVideoMode(240, 160, 32, SDL_OPENGL);
renderer->d.outputBuffer = malloc(256 * 256 * 4);
renderer->d.outputBufferStride = 256;
glGenTextures(1, &renderer->tex);
glBindTexture(GL_TEXTURE_2D, renderer->tex);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glViewport(0, 0, 240, 160); glViewport(0, 0, 240, 160);
return 1; return 1;
} }
static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer* renderer) { static void _GBASDLRunloop(struct GBAThread* context, struct GBAVideoGLSLRenderer* renderer) {
SDL_Event event; SDL_Event event;
int err;
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); while (context->started && context->debugger->state != DEBUGGER_EXITING) {
glEnableClientState(GL_VERTEX_ARRAY); GBAVideoGLSLRendererProcessEvents(renderer);
glVertexPointer(2, GL_INT, 0, _glVertices); pthread_mutex_lock(&renderer->mutex);
glTexCoordPointer(2, GL_INT, 0, _glTexCoords); if (renderer->d.framesPending) {
glMatrixMode (GL_PROJECTION); renderer->d.framesPending = 0;
glLoadIdentity(); pthread_mutex_unlock(&renderer->mutex);
glOrtho(0, 240, 160, 0, 0, 1);
while (context->started) {
pthread_mutex_lock(&renderer->d.mutex);
if (renderer->d.d.framesPending) {
renderer->d.d.framesPending = 0;
pthread_mutex_unlock(&renderer->d.mutex);
glBindTexture(GL_TEXTURE_2D, renderer->tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, renderer->d.outputBuffer);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
SDL_GL_SwapBuffers(); SDL_GL_SwapBuffers();
@ -140,29 +96,17 @@ static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer*
break; break;
} }
} }
pthread_mutex_lock(&renderer->d.mutex); pthread_mutex_lock(&renderer->mutex);
pthread_cond_broadcast(&renderer->d.downCond); pthread_cond_broadcast(&renderer->downCond);
pthread_mutex_unlock(&renderer->d.mutex);
} else { } else {
while (!renderer->d.d.framesPending) { pthread_cond_broadcast(&renderer->downCond);
struct timeval tv; pthread_cond_wait(&renderer->upCond, &renderer->mutex);
struct timespec ts;
gettimeofday(&tv, 0);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000 + 800000;
err = pthread_cond_timedwait(&renderer->d.upCond, &renderer->d.mutex, &ts);
if (err == ETIMEDOUT) {
break;
}
}
pthread_mutex_unlock(&renderer->d.mutex);
} }
pthread_mutex_unlock(&renderer->mutex);
} }
} }
static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer) { static void _GBASDLDeinit() {
free(renderer->d.outputBuffer);
SDL_Quit(); SDL_Quit();
} }

214
src/sdl/main.c Normal file
View File

@ -0,0 +1,214 @@
#include "debugger.h"
#include "gba-thread.h"
#include "gba.h"
#include "renderers/video-software.h"
#include <SDL.h>
#ifdef __APPLE__
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
struct GLSoftwareRenderer {
struct GBAVideoSoftwareRenderer d;
GLuint tex;
};
static int _GBASDLInit(struct GLSoftwareRenderer* renderer);
static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer);
static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer* renderer);
static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_KeyboardEvent* event);
static const GLint _glVertices[] = {
0, 0,
256, 0,
256, 256,
0, 256
};
static const GLint _glTexCoords[] = {
0, 0,
1, 0,
1, 1,
0, 1
};
int main(int argc, char** argv) {
const char* fname = "test.rom";
if (argc > 1) {
fname = argv[1];
}
int fd = open(fname, O_RDONLY);
if (fd < 0) {
return 1;
}
sigset_t signals;
sigaddset(&signals, SIGINT);
sigaddset(&signals, SIGTRAP);
pthread_sigmask(SIG_BLOCK, &signals, 0);
struct GBAThread context;
struct GLSoftwareRenderer renderer;
GBAVideoSoftwareRendererCreate(&renderer.d);
if (!_GBASDLInit(&renderer)) {
return 1;
}
context.fd = fd;
context.renderer = &renderer.d.d;
GBAThreadStart(&context);
_GBASDLRunloop(&context, &renderer);
GBAThreadJoin(&context);
close(fd);
_GBASDLDeinit(&renderer);
return 0;
}
static int _GBASDLInit(struct GLSoftwareRenderer* renderer) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
return 0;
}
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_SetVideoMode(240, 160, 32, SDL_OPENGL);
renderer->d.outputBuffer = malloc(256 * 256 * 4);
renderer->d.outputBufferStride = 256;
glGenTextures(1, &renderer->tex);
glBindTexture(GL_TEXTURE_2D, renderer->tex);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glViewport(0, 0, 240, 160);
return 1;
}
static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer* renderer) {
SDL_Event event;
int err;
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, 240, 160, 0, 0, 1);
while (context->started) {
pthread_mutex_lock(&renderer->d.mutex);
if (renderer->d.d.framesPending) {
renderer->d.d.framesPending = 0;
pthread_mutex_unlock(&renderer->d.mutex);
glBindTexture(GL_TEXTURE_2D, renderer->tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, renderer->d.outputBuffer);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
SDL_GL_SwapBuffers();
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
// FIXME: this isn't thread-safe
context->debugger->state = DEBUGGER_EXITING;
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
_GBASDLHandleKeypress(context, &event.key);
break;
}
}
pthread_mutex_lock(&renderer->d.mutex);
pthread_cond_broadcast(&renderer->d.downCond);
pthread_mutex_unlock(&renderer->d.mutex);
} else {
while (!renderer->d.d.framesPending) {
struct timeval tv;
struct timespec ts;
gettimeofday(&tv, 0);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000 + 800000;
err = pthread_cond_timedwait(&renderer->d.upCond, &renderer->d.mutex, &ts);
if (err == ETIMEDOUT) {
break;
}
}
pthread_mutex_unlock(&renderer->d.mutex);
}
}
}
static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer) {
free(renderer->d.outputBuffer);
SDL_Quit();
}
static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_KeyboardEvent* event) {
enum GBAKey key = 0;
switch (event->keysym.sym) {
case SDLK_z:
key = GBA_KEY_A;
break;
case SDLK_x:
key = GBA_KEY_B;
break;
case SDLK_a:
key = GBA_KEY_L;
break;
case SDLK_s:
key = GBA_KEY_R;
break;
case SDLK_RETURN:
key = GBA_KEY_START;
break;
case SDLK_BACKSPACE:
key = GBA_KEY_SELECT;
break;
case SDLK_UP:
key = GBA_KEY_UP;
break;
case SDLK_DOWN:
key = GBA_KEY_DOWN;
break;
case SDLK_LEFT:
key = GBA_KEY_LEFT;
break;
case SDLK_RIGHT:
key = GBA_KEY_RIGHT;
break;
case SDLK_TAB:
context->renderer->turbo = !context->renderer->turbo;
return;
default:
return;
}
if (event->type == SDL_KEYDOWN) {
context->activeKeys |= 1 << key;
} else {
context->activeKeys &= ~(1 << key);
}
}