src/gba/renderers/video-glsl.c (view raw)
1#include "video-glsl.h"
2
3#include <string.h>
4
5#define UNIFORM_LOCATION(UNIFORM) (glGetUniformLocation(glslRenderer->program, UNIFORM))
6
7static const GLfloat _vertices[4] = {
8 -1, 0,
9 1, 0
10};
11
12static const GLchar* _fragmentShader[] = {
13 "uniform float y;",
14 "uniform sampler2D palette;",
15
16 "void main() {",
17 " gl_FragColor = texture2D(palette, vec2(0, y / 256.0));",
18 "}"
19};
20
21static const GLchar* _vertexShader[] = {
22 "attribute vec2 vert;",
23 "uniform float y;",
24
25 "void main() {",
26 " gl_Position = vec4(vert.x, 1.0 - y / 80.0, 0, 1.0);",
27 "}"
28};
29
30static void GBAVideoGLSLRendererInit(struct GBAVideoRenderer* renderer);
31static void GBAVideoGLSLRendererDeinit(struct GBAVideoRenderer* renderer);
32static void GBAVideoGLSLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
33static uint16_t GBAVideoGLSLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
34static void GBAVideoGLSLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
35static void GBAVideoGLSLRendererFinishFrame(struct GBAVideoRenderer* renderer);
36
37void GBAVideoGLSLRendererCreate(struct GBAVideoGLSLRenderer* glslRenderer) {
38 glslRenderer->d.init = GBAVideoGLSLRendererInit;
39 glslRenderer->d.deinit = GBAVideoGLSLRendererDeinit;
40 glslRenderer->d.writeVideoRegister = GBAVideoGLSLRendererWriteVideoRegister;
41 glslRenderer->d.writePalette = GBAVideoGLSLRendererWritePalette;
42 glslRenderer->d.drawScanline = GBAVideoGLSLRendererDrawScanline;
43 glslRenderer->d.finishFrame = GBAVideoGLSLRendererFinishFrame;
44
45 glslRenderer->d.turbo = 0;
46 glslRenderer->d.framesPending = 0;
47 glslRenderer->d.frameskip = 0;
48
49 glslRenderer->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
50 glslRenderer->vertexShader = glCreateShader(GL_VERTEX_SHADER);
51 glslRenderer->program = glCreateProgram();
52
53 glShaderSource(glslRenderer->fragmentShader, 5, _fragmentShader, 0);
54 glShaderSource(glslRenderer->vertexShader, 5, _vertexShader, 0);
55
56 glAttachShader(glslRenderer->program, glslRenderer->vertexShader);
57 glAttachShader(glslRenderer->program, glslRenderer->fragmentShader);
58 char log[1024];
59 glCompileShader(glslRenderer->fragmentShader);
60 glCompileShader(glslRenderer->vertexShader);
61 glGetShaderInfoLog(glslRenderer->fragmentShader, 1024, 0, log);
62 glGetShaderInfoLog(glslRenderer->vertexShader, 1024, 0, log);
63 glLinkProgram(glslRenderer->program);
64
65 glGenTextures(1, &glslRenderer->vramTexture);
66 glBindTexture(GL_TEXTURE_2D, glslRenderer->vramTexture);
67 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
68 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
69 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
70 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
71
72 memset(glslRenderer->vram, 0, sizeof (glslRenderer->vram));
73
74 {
75 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
76 glslRenderer->mutex = mutex;
77 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
78 glslRenderer->upCond = cond;
79 glslRenderer->downCond = cond;
80 }
81}
82
83void GBAVideoGLSLRendererProcessEvents(struct GBAVideoGLSLRenderer* glslRenderer) {
84 glUseProgram(glslRenderer->program);
85 glUniform1i(UNIFORM_LOCATION("palette"), 0);
86
87 glEnable(GL_TEXTURE_2D);
88 glActiveTexture(GL_TEXTURE0);
89 glBindTexture(GL_TEXTURE_2D, glslRenderer->vramTexture);
90 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, glslRenderer->vram);
91
92 GLuint location = glGetAttribLocation(glslRenderer->program, "vert");
93 glEnableVertexAttribArray(location);
94 glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
95 int y;
96 for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) {
97 glUniform1f(UNIFORM_LOCATION("y"), y);
98 glDrawArrays(GL_LINES, 0, 2);
99 }
100 glDisableVertexAttribArray(location);
101 glFlush();
102}
103
104static void GBAVideoGLSLRendererInit(struct GBAVideoRenderer* renderer) {
105 struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
106
107 glslRenderer->state = GLSL_NONE;
108 glslRenderer->y = 0;
109
110 pthread_mutex_init(&glslRenderer->mutex, 0);
111 pthread_cond_init(&glslRenderer->upCond, 0);
112 pthread_cond_init(&glslRenderer->downCond, 0);
113}
114
115static void GBAVideoGLSLRendererDeinit(struct GBAVideoRenderer* renderer) {
116 struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
117
118 /*glDeleteShader(glslRenderer->fragmentShader);
119 glDeleteShader(glslRenderer->vertexShader);
120 glDeleteProgram(glslRenderer->program);
121
122 glDeleteTextures(1, &glslRenderer->paletteTexture);*/
123
124 pthread_mutex_lock(&glslRenderer->mutex);
125 pthread_cond_broadcast(&glslRenderer->upCond);
126 pthread_mutex_unlock(&glslRenderer->mutex);
127
128 pthread_mutex_destroy(&glslRenderer->mutex);
129 pthread_cond_destroy(&glslRenderer->upCond);
130 pthread_cond_destroy(&glslRenderer->downCond);
131}
132
133static void GBAVideoGLSLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
134 struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
135 GLshort color = 0;
136 color |= (value & 0x001F) << 11;
137 color |= (value & 0x03E0) << 1;
138 color |= (value & 0x7C00) >> 9;
139 glslRenderer->vram[(address >> 1) + glslRenderer->y * 512] = color;
140}
141
142static uint16_t GBAVideoGLSLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
143 struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
144 (void)(glslRenderer);
145 (void)(address);
146
147 return value;
148}
149
150static void GBAVideoGLSLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
151 struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
152
153 glslRenderer->y = y + 1;
154 if (y + 1 < VIDEO_VERTICAL_PIXELS) {
155 memcpy(&glslRenderer->vram[(y + 1) * 512], &glslRenderer->vram[y * 512], 1024);
156 } else {
157 glslRenderer->y = 0;
158 memcpy(&glslRenderer->vram[0], &glslRenderer->vram[y * 512], 1024);
159 }
160}
161
162static void GBAVideoGLSLRendererFinishFrame(struct GBAVideoRenderer* renderer) {
163 struct GBAVideoGLSLRenderer* glslRenderer = (struct GBAVideoGLSLRenderer*) renderer;
164
165 pthread_mutex_lock(&glslRenderer->mutex);
166 glslRenderer->state = GLSL_NONE;
167 if (renderer->frameskip > 0) {
168 --renderer->frameskip;
169 } else {
170 renderer->framesPending++;
171 pthread_cond_broadcast(&glslRenderer->upCond);
172 if (!renderer->turbo) {
173 pthread_cond_wait(&glslRenderer->downCond, &glslRenderer->mutex);
174 }
175 }
176 pthread_mutex_unlock(&glslRenderer->mutex);
177}