src/gba/renderers/gl.c (view raw)
1/* Copyright (c) 2013-2019 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/gba/renderers/gl.h>
7
8#include <mgba/core/cache-set.h>
9#include <mgba/internal/arm/macros.h>
10#include <mgba/internal/gba/io.h>
11#include <mgba/internal/gba/renderers/cache-set.h>
12
13static void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer);
14static void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer);
15static void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer);
16static void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
17static void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
18static void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
19static uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
20static void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
21static void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer);
22static void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels);
23static void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);
24
25static void GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer* renderer);
26static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value);
27static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value);
28static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value);
29static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value);
30static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value);
31static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value);
32
33static void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
34static void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
35static void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
36static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
37static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
38
39#define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 && glRenderer->bg[X].priority == priority
40
41static const GLchar* const _gl3Header =
42 "#version 130\n";
43
44static const char* const _vertexShader =
45 "attribute vec2 position;\n"
46 "uniform ivec3 loc;\n"
47 "const ivec3 maxPos = ivec3(240, 160, 32);\n"
48 "varying vec2 texCoord;\n"
49
50 "void main() {\n"
51 " vec2 local = (position * loc.x + vec2(0, loc.y)) / vec2(1., maxPos.y);\n"
52 " gl_Position = vec4(local * 2. - 1., loc.z / float(maxPos.z), 1.);\n"
53 " texCoord = local * maxPos.xy;\n"
54 "}";
55
56static const char* const _renderTile16 =
57 "vec4 renderTile(int tile, int paletteId, ivec2 localCoord) {\n"
58 " int address = charBase + tile * 16 + (localCoord.x >> 2) + (localCoord.y << 1);\n"
59 " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n"
60 " int entry = int(halfrow[3 - (localCoord.x & 3)] * 15.9);\n"
61 " vec4 color = texelFetch(palette, ivec2(entry, paletteId), 0);\n"
62 " if (entry == 0) {\n"
63 " color.a = 0;\n"
64 " } else {\n"
65 " color.a = 1;\n"
66 " }\n"
67 " return color;\n"
68 "}";
69
70static const char* const _renderTile256 =
71 "vec4 renderTile(int tile, int paletteId, ivec2 localCoord) {\n"
72 " int address = charBase + tile * 32 + (localCoord.x >> 1) + (localCoord.y << 2);\n"
73 " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n"
74 " int entry = int(halfrow[3 - 2 * (localCoord.x & 1)] * 15.9);\n"
75 " int pal2 = int(halfrow[2 - 2 * (localCoord.x & 1)] * 15.9);\n"
76 " vec4 color = texelFetch(palette, ivec2(entry, pal2 + (paletteId & 16)), 0);\n"
77 " if (pal2 > 0 || entry > 0) {\n"
78 " color.a = 1.;\n"
79 " } else {\n"
80 " color.a = 0.;\n"
81 " }\n"
82 " return color;\n"
83 "}";
84
85static const char* const _renderMode0 =
86 "varying vec2 texCoord;\n"
87 "uniform sampler2D vram;\n"
88 "uniform sampler2D palette;\n"
89 "uniform int screenBase;\n"
90 "uniform int charBase;\n"
91 "uniform int size;\n"
92 "uniform ivec2 offset;\n"
93
94 "vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n"
95
96 "void main() {\n"
97 " ivec2 coord = ivec2(texCoord) + offset;\n"
98 " if ((size & 1) == 1) {\n"
99 " coord.y += coord.x & 256;\n"
100 " }\n"
101 " coord.x &= 255;\n"
102 " int mapAddress = screenBase + (coord.x >> 3) + (coord.y >> 3) * 32;\n"
103 " vec4 map = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0);\n"
104 " int flags = int(map.g * 15.9);\n"
105 " if ((flags & 4) == 4) {\n"
106 " coord.x ^= 7;\n"
107 " }\n"
108 " if ((flags & 8) == 8) {\n"
109 " coord.y ^= 7;\n"
110 " }\n"
111 " int tile = int(map.a * 15.9) + int(map.b * 15.9) * 16 + (flags & 0x3) * 256;\n"
112 " gl_FragColor = renderTile(tile, int(map.r * 15.9), coord & 7);\n"
113 "}";
114
115static const char* const _fetchTileOverflow =
116 "vec4 fetchTile(ivec2 coord) {\n"
117 " int sizeAdjusted = (0x8000 << size) - 1;\n"
118 " coord &= sizeAdjusted;\n"
119 " return renderTile(coord);\n"
120 "}";
121
122static const char* const _fetchTileNoOverflow =
123 "vec4 fetchTile(ivec2 coord) {\n"
124 " int sizeAdjusted = (0x8000 << size) - 1;\n"
125 " ivec2 outerCoord = coord & ~sizeAdjusted;\n"
126 " if ((outerCoord.x | outerCoord.y) != 0) {\n"
127 " vec4 color = texelFetch(palette, ivec2(0, 0), 0);\n"
128 " color.a = 0;\n"
129 " return color;\n"
130 " }\n"
131 " return renderTile(coord);\n"
132 "}";
133
134static const char* const _renderMode2 =
135 "varying vec2 texCoord;\n"
136 "uniform sampler2D vram;\n"
137 "uniform sampler2D palette;\n"
138 "uniform int screenBase;\n"
139 "uniform int charBase;\n"
140 "uniform int size;\n"
141 "uniform ivec2 offset;\n"
142 "uniform ivec2 oldOffset;\n"
143 "uniform mat2x2 transform;\n"
144 "uniform mat2x2 oldTransform;\n"
145
146 "vec4 fetchTile(ivec2 coord);\n"
147
148 "vec4 renderTile(ivec2 coord) {\n"
149 " int map = (coord.x >> 11) + (((coord.y >> 7) & 0x7F0) << size);\n"
150 " int mapAddress = screenBase + (map >> 1);\n"
151 " vec4 twomaps = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0);\n"
152 " int tile = int(twomaps[3 - 2 * (map & 1)] * 15.9) + int(twomaps[2 - 2 * (map & 1)] * 15.9) * 16;\n"
153 " int address = charBase + tile * 32 + ((coord.x >> 9) & 3) + ((coord.y >> 6) & 0x1C);\n"
154 " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n"
155 " int entry = int(halfrow[3 - ((coord.x >> 7) & 2)] * 15.9);\n"
156 " int pal2 = int(halfrow[2 - ((coord.x >> 7) & 2)] * 15.9);\n"
157 " vec4 color = texelFetch(palette, ivec2(entry, pal2), 0);\n"
158 " if (pal2 > 0 || entry > 0) {\n"
159 " color.a = 1.;\n"
160 " } else {\n"
161 " color.a = 0.;\n"
162 " }\n"
163 " return color;\n"
164 "}"
165
166 "void main() {\n"
167 " vec2 newCoord = transform[0] * texCoord.x + offset;\n"
168 " vec2 oldCoord = oldTransform[0] * texCoord.x + oldOffset;\n"
169 " gl_FragColor = fetchTile(ivec2(newCoord * fract(texCoord.y) + oldCoord * (1. - fract(texCoord.y))));\n"
170 "}";
171
172static const char* const _composite =
173 "varying vec2 texCoord;\n"
174 "uniform sampler2D layer;\n"
175 "uniform int scale;\n"
176
177 "void main() {\n"
178 " vec4 color = texelFetch(layer, ivec2(texCoord * scale), 0);\n"
179 " if (color.a == 0) {\n"
180 " discard;\n"
181 " }\n"
182 " gl_FragColor = color;\n"
183 "}";
184
185static const GLint _vertices[] = {
186 0, 0,
187 0, 1,
188 1, 1,
189 1, 0,
190};
191
192void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) {
193 renderer->d.init = GBAVideoGLRendererInit;
194 renderer->d.reset = GBAVideoGLRendererReset;
195 renderer->d.deinit = GBAVideoGLRendererDeinit;
196 renderer->d.writeVideoRegister = GBAVideoGLRendererWriteVideoRegister;
197 renderer->d.writeVRAM = GBAVideoGLRendererWriteVRAM;
198 renderer->d.writeOAM = GBAVideoGLRendererWriteOAM;
199 renderer->d.writePalette = GBAVideoGLRendererWritePalette;
200 renderer->d.drawScanline = GBAVideoGLRendererDrawScanline;
201 renderer->d.finishFrame = GBAVideoGLRendererFinishFrame;
202 renderer->d.getPixels = GBAVideoGLRendererGetPixels;
203 renderer->d.putPixels = GBAVideoGLRendererPutPixels;
204
205 renderer->d.disableBG[0] = false;
206 renderer->d.disableBG[1] = false;
207 renderer->d.disableBG[2] = false;
208 renderer->d.disableBG[3] = false;
209 renderer->d.disableOBJ = false;
210
211 renderer->scale = 1;
212}
213
214void _compileBackground(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) {
215 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
216 glAttachShader(program, vs);
217 glAttachShader(program, fs);
218 glShaderSource(fs, shaderBufferLines, shaderBuffer, 0);
219 glCompileShader(fs);
220 glGetShaderInfoLog(fs, 1024, 0, log);
221 if (log[0]) {
222 mLOG(GBA_VIDEO, ERROR, "Fragment shader compilation failure: %s", log);
223 }
224 glLinkProgram(program);
225 glGetProgramInfoLog(program, 1024, 0, log);
226 if (log[0]) {
227 mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log);
228 }
229 glDeleteShader(fs);
230}
231
232void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
233 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
234 glGenFramebuffers(2, glRenderer->fbo);
235 glGenTextures(3, glRenderer->layers);
236
237 glGenTextures(1, &glRenderer->paletteTex);
238 glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
239 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
240 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
241
242 glGenTextures(1, &glRenderer->vramTex);
243 glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex);
244 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
245 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
246 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 256, 192, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0);
247
248 glGenTextures(1, &glRenderer->oamTex);
249 glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex);
250 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
251 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
252
253 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]);
254 glBindTexture(GL_TEXTURE_2D, glRenderer->outputTex);
255 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
256 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
257 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
258 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
259 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
260 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->outputTex, 0);
261
262 glBindTexture(GL_TEXTURE_2D, glRenderer->layers[2]);
263 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
264 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
265 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
266 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
267 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
268 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, glRenderer->layers[2], 0);
269
270 glBindFramebuffer(GL_FRAMEBUFFER, 0);
271
272 int i;
273 for (i = 0; i < 4; ++i) {
274 glRenderer->bg[i].index = i;
275 glGenFramebuffers(1, &glRenderer->bg[i].fbo);
276 glGenTextures(1, &glRenderer->bg[i].tex);
277 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo);
278 glBindTexture(GL_TEXTURE_2D, glRenderer->bg[i].tex);
279 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
280 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
281 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
282 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
283 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
284 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->bg[i].tex, 0);
285 glBindFramebuffer(GL_FRAMEBUFFER, 0);
286 }
287
288 glRenderer->compositeProgram = glCreateProgram();
289 glRenderer->objProgram = glCreateProgram();
290 glRenderer->bgProgram[0] = glCreateProgram();
291 glRenderer->bgProgram[1] = glCreateProgram();
292 glRenderer->bgProgram[2] = glCreateProgram();
293 glRenderer->bgProgram[3] = glCreateProgram();
294 glRenderer->bgProgram[4] = glCreateProgram();
295 glRenderer->bgProgram[5] = glCreateProgram();
296
297 char log[1024];
298 const GLchar* shaderBuffer[8];
299 shaderBuffer[0] = _gl3Header;
300
301 GLuint vs = glCreateShader(GL_VERTEX_SHADER);
302 shaderBuffer[1] = _vertexShader;
303 glShaderSource(vs, 2, shaderBuffer, 0);
304 glCompileShader(vs);
305 glGetShaderInfoLog(vs, 1024, 0, log);
306 if (log[0]) {
307 mLOG(GBA_VIDEO, ERROR, "Vertex shader compilation failure: %s", log);
308 }
309
310 shaderBuffer[1] = _renderMode0;
311
312 shaderBuffer[2] = _renderTile16;
313 _compileBackground(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log);
314
315 shaderBuffer[2] = _renderTile256;
316 _compileBackground(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log);
317
318 shaderBuffer[1] = _renderMode2;
319
320 shaderBuffer[2] = _fetchTileOverflow;
321 _compileBackground(glRenderer, glRenderer->bgProgram[2], shaderBuffer, 3, vs, log);
322
323 shaderBuffer[2] = _fetchTileNoOverflow;
324 _compileBackground(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log);
325
326 shaderBuffer[1] = _composite;
327 _compileBackground(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log);
328
329 glDeleteShader(vs);
330
331 GBAVideoGLRendererReset(renderer);
332}
333
334void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) {
335 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
336 glDeleteFramebuffers(2, glRenderer->fbo);
337 glDeleteTextures(3, glRenderer->layers);
338 glDeleteTextures(1, &glRenderer->paletteTex);
339 glDeleteTextures(1, &glRenderer->vramTex);
340 glDeleteTextures(1, &glRenderer->oamTex);
341}
342
343void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
344 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
345
346 glRenderer->paletteDirty = true;
347 glRenderer->vramDirty = 0xFFFFFF;
348}
349
350void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
351 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
352 glRenderer->vramDirty |= 1 << (address >> 12);
353}
354
355void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
356 UNUSED(oam);
357 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
358 glRenderer->oamDirty = true;
359}
360
361void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
362 UNUSED(address);
363 UNUSED(value);
364 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
365 glRenderer->paletteDirty = true;
366}
367
368uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
369 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
370 if (renderer->cache) {
371 GBAVideoCacheWriteVideoRegister(renderer->cache, address, value);
372 }
373
374 switch (address) {
375 case REG_DISPCNT:
376 value &= 0xFFF7;
377 glRenderer->dispcnt = value;
378 GBAVideoGLRendererUpdateDISPCNT(glRenderer);
379 break;
380 case REG_BG0CNT:
381 value &= 0xDFFF;
382 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[0], value);
383 break;
384 case REG_BG1CNT:
385 value &= 0xDFFF;
386 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[1], value);
387 break;
388 case REG_BG2CNT:
389 value &= 0xFFFF;
390 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[2], value);
391 break;
392 case REG_BG3CNT:
393 value &= 0xFFFF;
394 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[3], value);
395 break;
396 case REG_BG0HOFS:
397 value &= 0x01FF;
398 glRenderer->bg[0].x = value;
399 break;
400 case REG_BG0VOFS:
401 value &= 0x01FF;
402 glRenderer->bg[0].y = value;
403 break;
404 case REG_BG1HOFS:
405 value &= 0x01FF;
406 glRenderer->bg[1].x = value;
407 break;
408 case REG_BG1VOFS:
409 value &= 0x01FF;
410 glRenderer->bg[1].y = value;
411 break;
412 case REG_BG2HOFS:
413 value &= 0x01FF;
414 glRenderer->bg[2].x = value;
415 break;
416 case REG_BG2VOFS:
417 value &= 0x01FF;
418 glRenderer->bg[2].y = value;
419 break;
420 case REG_BG3HOFS:
421 value &= 0x01FF;
422 glRenderer->bg[3].x = value;
423 break;
424 case REG_BG3VOFS:
425 value &= 0x01FF;
426 glRenderer->bg[3].y = value;
427 break;
428 case REG_BG2PA:
429 glRenderer->bg[2].dx = value;
430 break;
431 case REG_BG2PB:
432 glRenderer->bg[2].dmx = value;
433 break;
434 case REG_BG2PC:
435 glRenderer->bg[2].dy = value;
436 break;
437 case REG_BG2PD:
438 glRenderer->bg[2].dmy = value;
439 break;
440 case REG_BG2X_LO:
441 GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value);
442 break;
443 case REG_BG2X_HI:
444 GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[2], value);
445 break;
446 case REG_BG2Y_LO:
447 GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[2], value);
448 break;
449 case REG_BG2Y_HI:
450 GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value);
451 break;
452 case REG_BG3PA:
453 glRenderer->bg[3].dx = value;
454 break;
455 case REG_BG3PB:
456 glRenderer->bg[3].dmx = value;
457 break;
458 case REG_BG3PC:
459 glRenderer->bg[3].dy = value;
460 break;
461 case REG_BG3PD:
462 glRenderer->bg[3].dmy = value;
463 break;
464 case REG_BG3X_LO:
465 GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value);
466 break;
467 case REG_BG3X_HI:
468 GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[3], value);
469 break;
470 case REG_BG3Y_LO:
471 GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[3], value);
472 break;
473 case REG_BG3Y_HI:
474 GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[3], value);
475 break;
476 case REG_BLDCNT:
477 GBAVideoGLRendererWriteBLDCNT(glRenderer, value);
478 value &= 0x3FFF;
479 break;
480 case REG_BLDALPHA:
481 glRenderer->blda = value & 0x1F;
482 if (glRenderer->blda > 0x10) {
483 glRenderer->blda = 0x10;
484 }
485 glRenderer->bldb = (value >> 8) & 0x1F;
486 if (glRenderer->bldb > 0x10) {
487 glRenderer->bldb = 0x10;
488 }
489 value &= 0x1F1F;
490 break;
491 case REG_BLDY:
492 value &= 0x1F;
493 if (value > 0x10) {
494 value = 0x10;
495 }
496 if (glRenderer->bldy != value) {
497 glRenderer->bldy = value;
498 }
499 break;
500 case REG_WIN0H:
501 /*glRenderer->winN[0].h.end = value;
502 glRenderer->winN[0].h.start = value >> 8;
503 if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[0].h.start > glRenderer->winN[0].h.end) {
504 glRenderer->winN[0].h.start = 0;
505 }
506 if (glRenderer->winN[0].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) {
507 glRenderer->winN[0].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;
508 if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) {
509 glRenderer->winN[0].h.start = GBA_VIDEO_HORIZONTAL_PIXELS;
510 }
511 }*/
512 break;
513 case REG_WIN1H:
514 /*glRenderer->winN[1].h.end = value;
515 glRenderer->winN[1].h.start = value >> 8;
516 if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[1].h.start > glRenderer->winN[1].h.end) {
517 glRenderer->winN[1].h.start = 0;
518 }
519 if (glRenderer->winN[1].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) {
520 glRenderer->winN[1].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;
521 if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) {
522 glRenderer->winN[1].h.start = GBA_VIDEO_HORIZONTAL_PIXELS;
523 }
524 }*/
525 break;
526 case REG_WIN0V:
527 /*glRenderer->winN[0].v.end = value;
528 glRenderer->winN[0].v.start = value >> 8;
529 if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[0].v.start > glRenderer->winN[0].v.end) {
530 glRenderer->winN[0].v.start = 0;
531 }
532 if (glRenderer->winN[0].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
533 glRenderer->winN[0].v.end = GBA_VIDEO_VERTICAL_PIXELS;
534 if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
535 glRenderer->winN[0].v.start = GBA_VIDEO_VERTICAL_PIXELS;
536 }
537 }*/
538 break;
539 case REG_WIN1V:
540 /*glRenderer->winN[1].v.end = value;
541 glRenderer->winN[1].v.start = value >> 8;
542 if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[1].v.start > glRenderer->winN[1].v.end) {
543 glRenderer->winN[1].v.start = 0;
544 }
545 if (glRenderer->winN[1].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
546 glRenderer->winN[1].v.end = GBA_VIDEO_VERTICAL_PIXELS;
547 if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
548 glRenderer->winN[1].v.start = GBA_VIDEO_VERTICAL_PIXELS;
549 }
550 }*/
551 break;
552 case REG_WININ:
553 value &= 0x3F3F;
554 //glRenderer->winN[0].control.packed = value;
555 //glRenderer->winN[1].control.packed = value >> 8;
556 break;
557 case REG_WINOUT:
558 value &= 0x3F3F;
559 //glRenderer->winout.packed = value;
560 //glRenderer->objwin.packed = value >> 8;
561 break;
562 case REG_MOSAIC:
563 glRenderer->mosaic = value;
564 break;
565 case REG_GREENSWP:
566 mLOG(GBA_VIDEO, STUB, "Stub video register write: 0x%03X", address);
567 break;
568 default:
569 mLOG(GBA_VIDEO, GAME_ERROR, "Invalid video register: 0x%03X", address);
570 }
571 return value;
572}
573
574void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
575 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
576 if (glRenderer->paletteDirty) {
577 glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
578 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette);
579 glRenderer->paletteDirty = false;
580 }
581 if (glRenderer->oamDirty) {
582 glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex);
583 glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 4, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, glRenderer->d.oam);
584 glRenderer->oamDirty = false;
585 }
586 int i;
587 for (i = 0; i < 24; ++i) {
588 if (!(glRenderer->vramDirty & (1 << i))) {
589 continue;
590 }
591 // TODO: PBOs
592 glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex);
593 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 8 * i, 256, 8, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, &glRenderer->d.vram[2048 * i]);
594 }
595 glRenderer->vramDirty = 0;
596
597 uint32_t backdrop = M_RGB5_TO_RGB8(renderer->palette[0]);
598 glClearColor(((backdrop >> 16) & 0xFF) / 256., ((backdrop >> 8) & 0xFF) / 256., (backdrop & 0xFF) / 256., 0.f);
599 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]);
600 glEnable(GL_SCISSOR_TEST);
601 glScissor(0, y * glRenderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, glRenderer->scale);
602 glClear(GL_COLOR_BUFFER_BIT);
603 glDisable(GL_SCISSOR_TEST);
604 if (y == 0) {
605 glClearDepthf(1);
606 glClear(GL_DEPTH_BUFFER_BIT);
607 }
608 glBindFramebuffer(GL_FRAMEBUFFER, 0);
609
610 unsigned priority;
611 for (priority = 0; priority < 4; ++priority) {
612 if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
613 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[0], y);
614 }
615 if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
616 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[1], y);
617 }
618 if (TEST_LAYER_ENABLED(2)) {
619 switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
620 case 0:
621 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[2], y);
622 break;
623 case 1:
624 case 2:
625 GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[2], y);
626 break;
627 case 3:
628 //GBAVideoGLRendererDrawBackgroundMode3(glRenderer, &glRenderer->bg[2], y);
629 break;
630 case 4:
631 //GBAVideoGLRendererDrawBackgroundMode4(glRenderer, &glRenderer->bg[2], y);
632 break;
633 case 5:
634 //GBAVideoGLRendererDrawBackgroundMode5(glRenderer, &glRenderer->bg[2], y);
635 break;
636 }
637 }
638 if (TEST_LAYER_ENABLED(3)) {
639 switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
640 case 0:
641 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[3], y);
642 break;
643 case 2:
644 GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[3], y);
645 break;
646 }
647 }
648 }
649 if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
650 glRenderer->bg[2].lastDx = glRenderer->bg[2].dx;
651 glRenderer->bg[2].lastDy = glRenderer->bg[2].dy;
652 glRenderer->bg[2].lastDmx = glRenderer->bg[2].dmx;
653 glRenderer->bg[2].lastDmy = glRenderer->bg[2].dmy;
654 glRenderer->bg[2].lastSx = glRenderer->bg[2].sx;
655 glRenderer->bg[2].lastSy = glRenderer->bg[2].sy;
656 glRenderer->bg[2].lastSx = glRenderer->bg[2].sx;
657 glRenderer->bg[2].lastSy = glRenderer->bg[2].sy;
658 glRenderer->bg[2].sx += glRenderer->bg[2].dmx;
659 glRenderer->bg[2].sy += glRenderer->bg[2].dmy;
660 glRenderer->bg[3].lastDx = glRenderer->bg[3].dx;
661 glRenderer->bg[3].lastDy = glRenderer->bg[3].dy;
662 glRenderer->bg[3].lastDmx = glRenderer->bg[3].dmx;
663 glRenderer->bg[3].lastDmy = glRenderer->bg[3].dmy;
664 glRenderer->bg[3].lastSx = glRenderer->bg[3].sx;
665 glRenderer->bg[3].lastSy = glRenderer->bg[3].sy;
666 glRenderer->bg[3].sx += glRenderer->bg[3].dmx;
667 glRenderer->bg[3].sy += glRenderer->bg[3].dmy;
668 }
669}
670
671void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) {
672 UNUSED(renderer);
673 glFlush();
674}
675
676void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
677
678}
679
680void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
681
682}
683
684static void _enableBg(struct GBAVideoGLRenderer* renderer, int bg, bool active) {
685 int wasActive = renderer->bg[bg].enabled;
686 if (!active) {
687 renderer->bg[bg].enabled = 0;
688 } else if (!wasActive && active) {
689 /*if (renderer->nextY == 0 || GBARegisterDISPCNTGetMode(renderer->dispcnt) > 2) {
690 // TODO: Investigate in more depth how switching background works in different modes
691 renderer->bg[bg].enabled = 4;
692 } else {
693 renderer->bg[bg].enabled = 1;
694 }*/
695 renderer->bg[bg].enabled = 4;
696 }
697}
698
699static void GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer* renderer) {
700 _enableBg(renderer, 0, GBARegisterDISPCNTGetBg0Enable(renderer->dispcnt));
701 _enableBg(renderer, 1, GBARegisterDISPCNTGetBg1Enable(renderer->dispcnt));
702 _enableBg(renderer, 2, GBARegisterDISPCNTGetBg2Enable(renderer->dispcnt));
703 _enableBg(renderer, 3, GBARegisterDISPCNTGetBg3Enable(renderer->dispcnt));
704}
705
706static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value) {
707 bg->priority = GBARegisterBGCNTGetPriority(value);
708 bg->charBase = GBARegisterBGCNTGetCharBase(value) << 13;
709 bg->mosaic = GBARegisterBGCNTGetMosaic(value);
710 bg->multipalette = GBARegisterBGCNTGet256Color(value);
711 bg->screenBase = GBARegisterBGCNTGetScreenBase(value) << 10;
712 bg->overflow = GBARegisterBGCNTGetOverflow(value);
713 bg->size = GBARegisterBGCNTGetSize(value);
714}
715
716static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
717 bg->refx = (bg->refx & 0xFFFF0000) | value;
718 bg->sx = bg->refx;
719}
720
721static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
722 bg->refx = (bg->refx & 0x0000FFFF) | (value << 16);
723 bg->refx <<= 4;
724 bg->refx >>= 4;
725 bg->sx = bg->refx;
726}
727
728static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
729 bg->refy = (bg->refy & 0xFFFF0000) | value;
730 bg->sy = bg->refy;
731}
732
733static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
734 bg->refy = (bg->refy & 0x0000FFFF) | (value << 16);
735 bg->refy <<= 4;
736 bg->refy >>= 4;
737 bg->sy = bg->refy;
738}
739
740static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value) {
741 renderer->bg[0].target1 = GBARegisterBLDCNTGetTarget1Bg0(value);
742 renderer->bg[1].target1 = GBARegisterBLDCNTGetTarget1Bg1(value);
743 renderer->bg[2].target1 = GBARegisterBLDCNTGetTarget1Bg2(value);
744 renderer->bg[3].target1 = GBARegisterBLDCNTGetTarget1Bg3(value);
745 renderer->bg[0].target2 = GBARegisterBLDCNTGetTarget2Bg0(value);
746 renderer->bg[1].target2 = GBARegisterBLDCNTGetTarget2Bg1(value);
747 renderer->bg[2].target2 = GBARegisterBLDCNTGetTarget2Bg2(value);
748 renderer->bg[3].target2 = GBARegisterBLDCNTGetTarget2Bg3(value);
749
750 renderer->blendEffect = GBARegisterBLDCNTGetEffect(value);
751 renderer->target1Obj = GBARegisterBLDCNTGetTarget1Obj(value);
752 renderer->target1Bd = GBARegisterBLDCNTGetTarget1Bd(value);
753 renderer->target2Obj = GBARegisterBLDCNTGetTarget2Obj(value);
754 renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value);
755}
756
757static void _compositeLayer(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
758 if ((y & 0x1F) != 0x1F) {
759 return;
760 }
761 glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]);
762 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
763 glScissor(0, (y * renderer->scale) % (0x20 * renderer->scale), GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale);
764 glDepthFunc(GL_LESS);
765 glEnable(GL_DEPTH_TEST);
766 glUseProgram(renderer->compositeProgram);
767 glActiveTexture(GL_TEXTURE0);
768 glBindTexture(GL_TEXTURE_2D, background->tex);
769 glUniform3i(0, 0x20, y & ~0x1F, (background->priority << 3) + (background->index << 1) + 1);
770 glUniform1i(1, 0);
771 glUniform1i(2, renderer->scale);
772 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
773 glEnableVertexAttribArray(0);
774 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
775 glDisable(GL_DEPTH_TEST);
776}
777
778void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
779 int inY = y + background->y;
780 int yBase = inY & 0xFF;
781 if (background->size == 2) {
782 yBase += inY & 0x100;
783 } else if (background->size == 3) {
784 yBase += (inY & 0x100) << 1;
785 }
786 glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
787 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
788 glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale);
789 glUseProgram(renderer->bgProgram[background->multipalette ? 1 : 0]);
790 glActiveTexture(GL_TEXTURE0);
791 glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
792 glActiveTexture(GL_TEXTURE0 + 1);
793 glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
794 glUniform3i(0, 1, y, 0);
795 glUniform1i(1, 0);
796 glUniform1i(2, 1);
797 glUniform1i(3, background->screenBase);
798 glUniform1i(4, background->charBase);
799 glUniform1i(5, background->size);
800 glUniform2i(6, background->x, yBase - y);
801 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
802 glEnableVertexAttribArray(0);
803 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
804
805 _compositeLayer(renderer, background, y);
806
807 glBindFramebuffer(GL_FRAMEBUFFER, 0);
808}
809
810void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
811 glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
812 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
813 glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale);
814 glUseProgram(renderer->bgProgram[background->overflow ? 2 : 3]);
815 glActiveTexture(GL_TEXTURE0);
816 glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
817 glActiveTexture(GL_TEXTURE0 + 1);
818 glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
819 glUniform3i(0, 1, y, 0);
820 glUniform1i(1, 0);
821 glUniform1i(2, 1);
822 glUniform1i(3, background->screenBase);
823 glUniform1i(4, background->charBase);
824 glUniform1i(5, background->size);
825 glUniform2i(6, background->sx, background->sy);
826 glUniform2i(7, background->lastSx, background->lastSy);
827 glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { background->dx, background->dy, background->dmx, background->dmy });
828 glUniformMatrix2fv(9, 1, GL_FALSE, (GLfloat[]) { background->lastDx, background->lastDy, background->lastDmx, background->lastDmy });
829 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
830 glEnableVertexAttribArray(0);
831 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
832
833 _compositeLayer(renderer, background, y);
834
835 glBindFramebuffer(GL_FRAMEBUFFER, 0);
836}