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 ivec2 loc;\n"
47 "const ivec2 maxPos = ivec2(240, 160);\n"
48 "varying vec2 texCoord;\n"
49
50 "void main() {\n"
51 " vec2 local = (position + vec2(0, loc.y)) / vec2(1., maxPos.y);\n"
52 " gl_Position = vec4(local * 2. - 1., 0., 1.);\n"
53 " texCoord = local * maxPos;\n"
54 "}";
55
56static const char* const _renderTile16 =
57 "vec4 renderTile(int tile, int tileBase, int paletteId, ivec2 localCoord) {\n"
58 " int address = tileBase + 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 tileBase, int paletteId, ivec2 localCoord) {\n"
72 " int address = tileBase + 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 tileBase, 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, charBase, int(map.r * 15.9), coord & 7);\n"
113 "}";
114
115static const char* const _composite =
116 "varying vec2 texCoord;\n"
117 "uniform sampler2D layer;\n"
118
119 "void main() {\n"
120 " vec4 color = texelFetch(layer, ivec2(texCoord), 0);\n"
121 " if (color.a == 0) {\n"
122 " discard;\n"
123 " }\n"
124 " gl_FragColor = color;\n"
125 "}";
126
127static const GLint _vertices[] = {
128 0, 0,
129 0, 1,
130 1, 1,
131 1, 0,
132};
133
134void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) {
135 renderer->d.init = GBAVideoGLRendererInit;
136 renderer->d.reset = GBAVideoGLRendererReset;
137 renderer->d.deinit = GBAVideoGLRendererDeinit;
138 renderer->d.writeVideoRegister = GBAVideoGLRendererWriteVideoRegister;
139 renderer->d.writeVRAM = GBAVideoGLRendererWriteVRAM;
140 renderer->d.writeOAM = GBAVideoGLRendererWriteOAM;
141 renderer->d.writePalette = GBAVideoGLRendererWritePalette;
142 renderer->d.drawScanline = GBAVideoGLRendererDrawScanline;
143 renderer->d.finishFrame = GBAVideoGLRendererFinishFrame;
144 renderer->d.getPixels = GBAVideoGLRendererGetPixels;
145 renderer->d.putPixels = GBAVideoGLRendererPutPixels;
146
147 renderer->d.disableBG[0] = false;
148 renderer->d.disableBG[1] = false;
149 renderer->d.disableBG[2] = false;
150 renderer->d.disableBG[3] = false;
151 renderer->d.disableOBJ = false;
152}
153
154void _compileBackground(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) {
155 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
156 glAttachShader(program, vs);
157 glAttachShader(program, fs);
158 glShaderSource(fs, shaderBufferLines, shaderBuffer, 0);
159 glCompileShader(fs);
160 glGetShaderInfoLog(fs, 1024, 0, log);
161 if (log[0]) {
162 mLOG(GBA_VIDEO, ERROR, "Fragment shader compilation failure: %s", log);
163 }
164 glLinkProgram(program);
165 glGetProgramInfoLog(program, 1024, 0, log);
166 if (log[0]) {
167 mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log);
168 }
169 glDeleteShader(fs);
170}
171
172void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
173 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
174 glGenFramebuffers(2, glRenderer->fbo);
175 glGenTextures(4, glRenderer->layers);
176
177 glGenTextures(1, &glRenderer->paletteTex);
178 glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
179 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
180 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
181
182 glGenTextures(1, &glRenderer->vramTex);
183 glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex);
184 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
185 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
186 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 256, 192, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0);
187
188 glGenTextures(1, &glRenderer->oamTex);
189 glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex);
190 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
191 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
192
193 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]);
194 glBindTexture(GL_TEXTURE_2D, glRenderer->layers[2]);
195 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
196 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
197 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
198 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
199 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
200 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[2], 0);
201
202 glBindTexture(GL_TEXTURE_2D, glRenderer->layers[3]);
203 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
204 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
205 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
206 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
207 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
208 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, glRenderer->layers[3], 0);
209
210 glBindFramebuffer(GL_FRAMEBUFFER, 0);
211
212 int i;
213 for (i = 0; i < 4; ++i) {
214 glRenderer->bg[i].index = i;
215 glGenFramebuffers(1, &glRenderer->bg[i].fbo);
216 glGenTextures(1, &glRenderer->bg[i].tex);
217 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo);
218 glBindTexture(GL_TEXTURE_2D, glRenderer->bg[i].tex);
219 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
220 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
221 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
222 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
223 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
224 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->bg[i].tex, 0);
225 glBindFramebuffer(GL_FRAMEBUFFER, 0);
226 }
227
228 glRenderer->compositeProgram = glCreateProgram();
229 glRenderer->objProgram = glCreateProgram();
230 glRenderer->bgProgram[0] = glCreateProgram();
231 glRenderer->bgProgram[1] = glCreateProgram();
232 glRenderer->bgProgram[2] = glCreateProgram();
233 glRenderer->bgProgram[3] = glCreateProgram();
234 glRenderer->bgProgram[4] = glCreateProgram();
235 glRenderer->bgProgram[5] = glCreateProgram();
236
237 char log[1024];
238 const GLchar* shaderBuffer[8];
239 shaderBuffer[0] = _gl3Header;
240
241 GLuint vs = glCreateShader(GL_VERTEX_SHADER);
242 shaderBuffer[1] = _vertexShader;
243 glShaderSource(vs, 2, shaderBuffer, 0);
244 glCompileShader(vs);
245 glGetShaderInfoLog(vs, 1024, 0, log);
246 if (log[0]) {
247 mLOG(GBA_VIDEO, ERROR, "Vertex shader compilation failure: %s", log);
248 }
249
250 shaderBuffer[1] = _renderMode0;
251
252 shaderBuffer[2] = _renderTile16;
253 _compileBackground(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log);
254
255 shaderBuffer[2] = _renderTile256;
256 _compileBackground(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log);
257
258 shaderBuffer[1] = _composite;
259 _compileBackground(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log);
260
261 glDeleteShader(vs);
262
263 GBAVideoGLRendererReset(renderer);
264}
265
266void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) {
267 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
268 glDeleteFramebuffers(2, glRenderer->fbo);
269 glDeleteTextures(4, glRenderer->layers);
270 glDeleteTextures(1, &glRenderer->paletteTex);
271 glDeleteTextures(1, &glRenderer->vramTex);
272 glDeleteTextures(1, &glRenderer->oamTex);
273}
274
275void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
276 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
277
278 glRenderer->paletteDirty = true;
279 glRenderer->vramDirty = 0xFFFFFF;
280}
281
282void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
283 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
284 glRenderer->vramDirty |= 1 << (address >> 12);
285}
286
287void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
288 UNUSED(oam);
289 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
290 glRenderer->oamDirty = true;
291}
292
293void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
294 UNUSED(address);
295 UNUSED(value);
296 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
297 glRenderer->paletteDirty = true;
298}
299
300uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
301 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
302 if (renderer->cache) {
303 GBAVideoCacheWriteVideoRegister(renderer->cache, address, value);
304 }
305
306 switch (address) {
307 case REG_DISPCNT:
308 value &= 0xFFF7;
309 glRenderer->dispcnt = value;
310 GBAVideoGLRendererUpdateDISPCNT(glRenderer);
311 break;
312 case REG_BG0CNT:
313 value &= 0xDFFF;
314 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[0], value);
315 break;
316 case REG_BG1CNT:
317 value &= 0xDFFF;
318 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[1], value);
319 break;
320 case REG_BG2CNT:
321 value &= 0xFFFF;
322 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[2], value);
323 break;
324 case REG_BG3CNT:
325 value &= 0xFFFF;
326 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[3], value);
327 break;
328 case REG_BG0HOFS:
329 value &= 0x01FF;
330 glRenderer->bg[0].x = value;
331 break;
332 case REG_BG0VOFS:
333 value &= 0x01FF;
334 glRenderer->bg[0].y = value;
335 break;
336 case REG_BG1HOFS:
337 value &= 0x01FF;
338 glRenderer->bg[1].x = value;
339 break;
340 case REG_BG1VOFS:
341 value &= 0x01FF;
342 glRenderer->bg[1].y = value;
343 break;
344 case REG_BG2HOFS:
345 value &= 0x01FF;
346 glRenderer->bg[2].x = value;
347 break;
348 case REG_BG2VOFS:
349 value &= 0x01FF;
350 glRenderer->bg[2].y = value;
351 break;
352 case REG_BG3HOFS:
353 value &= 0x01FF;
354 glRenderer->bg[3].x = value;
355 break;
356 case REG_BG3VOFS:
357 value &= 0x01FF;
358 glRenderer->bg[3].y = value;
359 break;
360 case REG_BG2PA:
361 glRenderer->bg[2].dx = value;
362 break;
363 case REG_BG2PB:
364 glRenderer->bg[2].dmx = value;
365 break;
366 case REG_BG2PC:
367 glRenderer->bg[2].dy = value;
368 break;
369 case REG_BG2PD:
370 glRenderer->bg[2].dmy = value;
371 break;
372 case REG_BG2X_LO:
373 GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value);
374 break;
375 case REG_BG2X_HI:
376 GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[2], value);
377 break;
378 case REG_BG2Y_LO:
379 GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[2], value);
380 break;
381 case REG_BG2Y_HI:
382 GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value);
383 break;
384 case REG_BG3PA:
385 glRenderer->bg[3].dx = value;
386 break;
387 case REG_BG3PB:
388 glRenderer->bg[3].dmx = value;
389 break;
390 case REG_BG3PC:
391 glRenderer->bg[3].dy = value;
392 break;
393 case REG_BG3PD:
394 glRenderer->bg[3].dmy = value;
395 break;
396 case REG_BG3X_LO:
397 GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value);
398 break;
399 case REG_BG3X_HI:
400 GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[3], value);
401 break;
402 case REG_BG3Y_LO:
403 GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[3], value);
404 break;
405 case REG_BG3Y_HI:
406 GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[3], value);
407 break;
408 case REG_BLDCNT:
409 GBAVideoGLRendererWriteBLDCNT(glRenderer, value);
410 value &= 0x3FFF;
411 break;
412 case REG_BLDALPHA:
413 glRenderer->blda = value & 0x1F;
414 if (glRenderer->blda > 0x10) {
415 glRenderer->blda = 0x10;
416 }
417 glRenderer->bldb = (value >> 8) & 0x1F;
418 if (glRenderer->bldb > 0x10) {
419 glRenderer->bldb = 0x10;
420 }
421 value &= 0x1F1F;
422 break;
423 case REG_BLDY:
424 value &= 0x1F;
425 if (value > 0x10) {
426 value = 0x10;
427 }
428 if (glRenderer->bldy != value) {
429 glRenderer->bldy = value;
430 }
431 break;
432 case REG_WIN0H:
433 /*glRenderer->winN[0].h.end = value;
434 glRenderer->winN[0].h.start = value >> 8;
435 if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[0].h.start > glRenderer->winN[0].h.end) {
436 glRenderer->winN[0].h.start = 0;
437 }
438 if (glRenderer->winN[0].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) {
439 glRenderer->winN[0].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;
440 if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) {
441 glRenderer->winN[0].h.start = GBA_VIDEO_HORIZONTAL_PIXELS;
442 }
443 }*/
444 break;
445 case REG_WIN1H:
446 /*glRenderer->winN[1].h.end = value;
447 glRenderer->winN[1].h.start = value >> 8;
448 if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[1].h.start > glRenderer->winN[1].h.end) {
449 glRenderer->winN[1].h.start = 0;
450 }
451 if (glRenderer->winN[1].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) {
452 glRenderer->winN[1].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;
453 if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) {
454 glRenderer->winN[1].h.start = GBA_VIDEO_HORIZONTAL_PIXELS;
455 }
456 }*/
457 break;
458 case REG_WIN0V:
459 /*glRenderer->winN[0].v.end = value;
460 glRenderer->winN[0].v.start = value >> 8;
461 if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[0].v.start > glRenderer->winN[0].v.end) {
462 glRenderer->winN[0].v.start = 0;
463 }
464 if (glRenderer->winN[0].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
465 glRenderer->winN[0].v.end = GBA_VIDEO_VERTICAL_PIXELS;
466 if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
467 glRenderer->winN[0].v.start = GBA_VIDEO_VERTICAL_PIXELS;
468 }
469 }*/
470 break;
471 case REG_WIN1V:
472 /*glRenderer->winN[1].v.end = value;
473 glRenderer->winN[1].v.start = value >> 8;
474 if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[1].v.start > glRenderer->winN[1].v.end) {
475 glRenderer->winN[1].v.start = 0;
476 }
477 if (glRenderer->winN[1].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
478 glRenderer->winN[1].v.end = GBA_VIDEO_VERTICAL_PIXELS;
479 if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
480 glRenderer->winN[1].v.start = GBA_VIDEO_VERTICAL_PIXELS;
481 }
482 }*/
483 break;
484 case REG_WININ:
485 value &= 0x3F3F;
486 //glRenderer->winN[0].control.packed = value;
487 //glRenderer->winN[1].control.packed = value >> 8;
488 break;
489 case REG_WINOUT:
490 value &= 0x3F3F;
491 //glRenderer->winout.packed = value;
492 //glRenderer->objwin.packed = value >> 8;
493 break;
494 case REG_MOSAIC:
495 glRenderer->mosaic = value;
496 break;
497 case REG_GREENSWP:
498 mLOG(GBA_VIDEO, STUB, "Stub video register write: 0x%03X", address);
499 break;
500 default:
501 mLOG(GBA_VIDEO, GAME_ERROR, "Invalid video register: 0x%03X", address);
502 }
503 return value;
504}
505
506void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
507 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
508 if (glRenderer->paletteDirty) {
509 glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
510 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette);
511 glRenderer->paletteDirty = false;
512 }
513 if (glRenderer->oamDirty) {
514 glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex);
515 glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 4, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, glRenderer->d.oam);
516 glRenderer->oamDirty = false;
517 }
518 int i;
519 for (i = 0; i < 24; ++i) {
520 if (!(glRenderer->vramDirty & (1 << i))) {
521 continue;
522 }
523 // TODO: PBOs
524 glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex);
525 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 8 * i, 256, 8, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, &glRenderer->d.vram[2048 * i]);
526 }
527 glRenderer->vramDirty = 0;
528
529 uint32_t backdrop = M_RGB5_TO_RGB8(renderer->palette[0]);
530 glClearColor(((backdrop >> 16) & 0xFF) / 256., ((backdrop >> 8) & 0xFF) / 256., (backdrop & 0xFF) / 256., 0.f);
531 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]);
532 glEnable(GL_SCISSOR_TEST);
533 glScissor(0, y, GBA_VIDEO_HORIZONTAL_PIXELS, 1);
534 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
535 glBindFramebuffer(GL_FRAMEBUFFER, 0);
536
537 unsigned priority;
538 for (priority = 0; priority < 4; ++priority) {
539 if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
540 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[0], y);
541 }
542 if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
543 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[1], y);
544 }
545 if (TEST_LAYER_ENABLED(2)) {
546 switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
547 case 0:
548 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[2], y);
549 break;
550 case 1:
551 case 2:
552 //GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[2], y);
553 break;
554 case 3:
555 //GBAVideoGLRendererDrawBackgroundMode3(glRenderer, &glRenderer->bg[2], y);
556 break;
557 case 4:
558 //GBAVideoGLRendererDrawBackgroundMode4(glRenderer, &glRenderer->bg[2], y);
559 break;
560 case 5:
561 //GBAVideoGLRendererDrawBackgroundMode5(glRenderer, &glRenderer->bg[2], y);
562 break;
563 }
564 }
565 if (TEST_LAYER_ENABLED(3)) {
566 switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
567 case 0:
568 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[3], y);
569 break;
570 case 2:
571 //GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[3], y);
572 break;
573 }
574 }
575 }
576 if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
577 glRenderer->bg[2].sx += glRenderer->bg[2].dmx;
578 glRenderer->bg[2].sy += glRenderer->bg[2].dmy;
579 glRenderer->bg[3].sx += glRenderer->bg[3].dmx;
580 glRenderer->bg[3].sy += glRenderer->bg[3].dmy;
581 }
582}
583
584void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) {
585 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
586 glFinish();
587 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]);
588 glPixelStorei(GL_PACK_ROW_LENGTH, glRenderer->outputBufferStride);
589 glReadPixels(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_BYTE, glRenderer->outputBuffer);
590 glBindFramebuffer(GL_FRAMEBUFFER, 0);
591}
592
593void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
594
595}
596
597void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
598
599}
600
601static void _enableBg(struct GBAVideoGLRenderer* renderer, int bg, bool active) {
602 int wasActive = renderer->bg[bg].enabled;
603 if (!active) {
604 renderer->bg[bg].enabled = 0;
605 } else if (!wasActive && active) {
606 /*if (renderer->nextY == 0 || GBARegisterDISPCNTGetMode(renderer->dispcnt) > 2) {
607 // TODO: Investigate in more depth how switching background works in different modes
608 renderer->bg[bg].enabled = 4;
609 } else {
610 renderer->bg[bg].enabled = 1;
611 }*/
612 renderer->bg[bg].enabled = 4;
613 }
614}
615
616static void GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer* renderer) {
617 _enableBg(renderer, 0, GBARegisterDISPCNTGetBg0Enable(renderer->dispcnt));
618 _enableBg(renderer, 1, GBARegisterDISPCNTGetBg1Enable(renderer->dispcnt));
619 _enableBg(renderer, 2, GBARegisterDISPCNTGetBg2Enable(renderer->dispcnt));
620 _enableBg(renderer, 3, GBARegisterDISPCNTGetBg3Enable(renderer->dispcnt));
621}
622
623static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value) {
624 bg->priority = GBARegisterBGCNTGetPriority(value);
625 bg->charBase = GBARegisterBGCNTGetCharBase(value) << 13;
626 bg->mosaic = GBARegisterBGCNTGetMosaic(value);
627 bg->multipalette = GBARegisterBGCNTGet256Color(value);
628 bg->screenBase = GBARegisterBGCNTGetScreenBase(value) << 10;
629 bg->overflow = GBARegisterBGCNTGetOverflow(value);
630 bg->size = GBARegisterBGCNTGetSize(value);
631}
632
633static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
634 bg->refx = (bg->refx & 0xFFFF0000) | value;
635 bg->sx = bg->refx;
636}
637
638static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
639 bg->refx = (bg->refx & 0x0000FFFF) | (value << 16);
640 bg->refx <<= 4;
641 bg->refx >>= 4;
642 bg->sx = bg->refx;
643}
644
645static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
646 bg->refy = (bg->refy & 0xFFFF0000) | value;
647 bg->sy = bg->refy;
648}
649
650static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
651 bg->refy = (bg->refy & 0x0000FFFF) | (value << 16);
652 bg->refy <<= 4;
653 bg->refy >>= 4;
654 bg->sy = bg->refy;
655}
656
657static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value) {
658 renderer->bg[0].target1 = GBARegisterBLDCNTGetTarget1Bg0(value);
659 renderer->bg[1].target1 = GBARegisterBLDCNTGetTarget1Bg1(value);
660 renderer->bg[2].target1 = GBARegisterBLDCNTGetTarget1Bg2(value);
661 renderer->bg[3].target1 = GBARegisterBLDCNTGetTarget1Bg3(value);
662 renderer->bg[0].target2 = GBARegisterBLDCNTGetTarget2Bg0(value);
663 renderer->bg[1].target2 = GBARegisterBLDCNTGetTarget2Bg1(value);
664 renderer->bg[2].target2 = GBARegisterBLDCNTGetTarget2Bg2(value);
665 renderer->bg[3].target2 = GBARegisterBLDCNTGetTarget2Bg3(value);
666
667 renderer->blendEffect = GBARegisterBLDCNTGetEffect(value);
668 renderer->target1Obj = GBARegisterBLDCNTGetTarget1Obj(value);
669 renderer->target1Bd = GBARegisterBLDCNTGetTarget1Bd(value);
670 renderer->target2Obj = GBARegisterBLDCNTGetTarget2Obj(value);
671 renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value);
672}
673
674void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
675 int inY = y + background->y;
676 int yBase = inY & 0xFF;
677 if (background->size == 2) {
678 yBase += inY & 0x100;
679 } else if (background->size == 3) {
680 yBase += (inY & 0x100) << 1;
681 }
682 glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
683 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
684 glScissor(0, y, GBA_VIDEO_HORIZONTAL_PIXELS, 1);
685 glUseProgram(renderer->bgProgram[background->multipalette ? 1 : 0]);
686 glActiveTexture(GL_TEXTURE0);
687 glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
688 glActiveTexture(GL_TEXTURE0 + 1);
689 glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
690 glUniform2i(0, 0, y);
691 glUniform1i(1, 0);
692 glUniform1i(2, 1);
693 glUniform1i(3, background->screenBase);
694 glUniform1i(4, background->charBase);
695 glUniform1i(5, background->size);
696 glUniform2i(6, background->x, yBase - y);
697 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
698 glEnableVertexAttribArray(0);
699 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
700
701 glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]);
702 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
703 glScissor(0, y, GBA_VIDEO_HORIZONTAL_PIXELS, 1);
704 glDepthFunc(GL_LESS);
705 glEnable(GL_DEPTH_TEST);
706 glUseProgram(renderer->compositeProgram);
707 glActiveTexture(GL_TEXTURE0);
708 glBindTexture(GL_TEXTURE_2D, background->tex);
709 glUniform2i(0, (background->priority << 3) + (background->index << 1) + 1, y);
710 glUniform1i(1, 0);
711 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
712 glEnableVertexAttribArray(0);
713 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
714 glDisable(GL_DEPTH_TEST);
715
716 glBindFramebuffer(GL_FRAMEBUFFER, 0);
717}