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#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
9
10#include <mgba/core/cache-set.h>
11#include <mgba/internal/arm/macros.h>
12#include <mgba/internal/gba/io.h>
13#include <mgba/internal/gba/renderers/cache-set.h>
14#include <mgba-util/memory.h>
15
16#define FLAG_CONST "const vec4 flagCoeff = vec4(64., 32., 16., 1.);\n"
17
18static void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer);
19static void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer);
20static void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer);
21static void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
22static void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
23static void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
24static uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
25static void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
26static void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer);
27static void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels);
28static void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);
29
30static void GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer* renderer);
31static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value);
32static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value);
33static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value);
34static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value);
35static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value);
36static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value);
37
38static void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY);
39static void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
40static void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
41static void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
42static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
43static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
44static void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y);
45
46static void _finalizeLayers(struct GBAVideoGLRenderer* renderer);
47
48#define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4
49
50struct GBAVideoGLUniform {
51 const char* name;
52 int type;
53};
54
55static const GLchar* const _gl3Header =
56 "#version 130\n";
57
58static const char* const _vertexShader =
59 "in vec2 position;\n"
60 "uniform ivec2 loc;\n"
61 "uniform ivec2 maxPos;\n"
62 "out vec2 texCoord;\n"
63
64 "void main() {\n"
65 " vec2 local = vec2(position.x, float(position.y * loc.x + loc.y) / abs(maxPos.y));\n"
66 " gl_Position = vec4((local * 2. - 1.) * sign(maxPos), 0., 1.);\n"
67 " texCoord = local * abs(maxPos);\n"
68 "}";
69
70static const char* const _renderTile16 =
71 "vec4 renderTile(int tile, int paletteId, ivec2 localCoord) {\n"
72 " int address = charBase + tile * 16 + (localCoord.x >> 2) + (localCoord.y << 1);\n"
73 " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n"
74 " int entry = int(halfrow[3 - (localCoord.x & 3)] * 15.9);\n"
75 " vec4 color = texelFetch(palette, ivec2(entry, paletteId), 0);\n"
76 " if (entry == 0) {\n"
77 " discard;\n"
78 " }\n"
79 " color.a = 1;\n"
80 " return color;\n"
81 "}";
82
83static const char* const _renderTile256 =
84 "vec4 renderTile(int tile, int paletteId, ivec2 localCoord) {\n"
85 " int address = charBase + tile * 32 + (localCoord.x >> 1) + (localCoord.y << 2);\n"
86 " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n"
87 " int entry = int(halfrow[3 - 2 * (localCoord.x & 1)] * 15.9);\n"
88 " int pal2 = int(halfrow[2 - 2 * (localCoord.x & 1)] * 15.9);\n"
89 " vec4 color = texelFetch(palette, ivec2(entry, pal2 + (paletteId & 16)), 0);\n"
90 " if ((pal2 | entry) == 0) {\n"
91 " discard;\n"
92 " }\n"
93 " color.a = 1.;\n"
94 " return color;\n"
95 "}";
96
97static const struct GBAVideoGLUniform _uniformsMode0[] = {
98 { "loc", GBA_GL_VS_LOC, },
99 { "maxPos", GBA_GL_VS_MAXPOS, },
100 { "vram", GBA_GL_BG_VRAM, },
101 { "palette", GBA_GL_BG_PALETTE, },
102 { "screenBase", GBA_GL_BG_SCREENBASE, },
103 { "charBase", GBA_GL_BG_CHARBASE, },
104 { "size", GBA_GL_BG_SIZE, },
105 { "offset", GBA_GL_BG_OFFSET, },
106 { "inflags", GBA_GL_BG_INFLAGS, },
107 { 0 }
108};
109
110static const char* const _renderMode0 =
111 "in vec2 texCoord;\n"
112 "uniform sampler2D vram;\n"
113 "uniform sampler2D palette;\n"
114 "uniform int screenBase;\n"
115 "uniform int charBase;\n"
116 "uniform int size;\n"
117 "uniform ivec2 offset;\n"
118 "uniform ivec4 inflags;\n"
119 "out vec4 color;\n"
120 "out vec4 flags;\n"
121 FLAG_CONST
122
123 "vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n"
124
125 "void main() {\n"
126 " ivec2 coord = ivec2(texCoord) + offset;\n"
127 " if ((size & 1) == 1) {\n"
128 " coord.y += coord.x & 256;\n"
129 " }\n"
130 " coord.x &= 255;\n"
131 " int mapAddress = screenBase + (coord.x >> 3) + (coord.y >> 3) * 32;\n"
132 " vec4 map = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0);\n"
133 " int tileFlags = int(map.g * 15.9);\n"
134 " if ((tileFlags & 4) == 4) {\n"
135 " coord.x ^= 7;\n"
136 " }\n"
137 " if ((tileFlags & 8) == 8) {\n"
138 " coord.y ^= 7;\n"
139 " }\n"
140 " int tile = int(map.a * 15.9) + int(map.b * 15.9) * 16 + (tileFlags & 0x3) * 256;\n"
141 " color = renderTile(tile, int(map.r * 15.9), coord & 7);\n"
142 " flags = inflags / flagCoeff;\n"
143 "}";
144
145static const char* const _fetchTileOverflow =
146 "vec4 fetchTile(ivec2 coord) {\n"
147 " int sizeAdjusted = (0x8000 << size) - 1;\n"
148 " coord &= sizeAdjusted;\n"
149 " return renderTile(coord);\n"
150 "}";
151
152static const char* const _fetchTileNoOverflow =
153 "vec4 fetchTile(ivec2 coord) {\n"
154 " int sizeAdjusted = (0x8000 << size) - 1;\n"
155 " ivec2 outerCoord = coord & ~sizeAdjusted;\n"
156 " if ((outerCoord.x | outerCoord.y) != 0) {\n"
157 " discard;\n"
158 " }\n"
159 " return renderTile(coord);\n"
160 "}";
161
162static const struct GBAVideoGLUniform _uniformsMode2[] = {
163 { "loc", GBA_GL_VS_LOC, },
164 { "maxPos", GBA_GL_VS_MAXPOS, },
165 { "vram", GBA_GL_BG_VRAM, },
166 { "palette", GBA_GL_BG_PALETTE, },
167 { "screenBase", GBA_GL_BG_SCREENBASE, },
168 { "charBase", GBA_GL_BG_CHARBASE, },
169 { "size", GBA_GL_BG_SIZE, },
170 { "inflags", GBA_GL_BG_INFLAGS, },
171 { "offset", GBA_GL_BG_OFFSET, },
172 { "transform", GBA_GL_BG_TRANSFORM, },
173 { "range", GBA_GL_BG_RANGE, },
174 { 0 }
175};
176
177static const char* const _interpolate =
178 "vec2 interpolate(ivec2 arr[4], float x) {\n"
179 " float x1m = 1. - x;\n"
180 " return x1m * x1m * x1m * arr[0] +"
181 " 3 * x1m * x1m * x * arr[1] +"
182 " 3 * x1m * x * x * arr[2] +"
183 " x * x * x * arr[3];\n"
184 "}\n";
185
186static const char* const _renderMode2 =
187 "in vec2 texCoord;\n"
188 "uniform sampler2D vram;\n"
189 "uniform sampler2D palette;\n"
190 "uniform int screenBase;\n"
191 "uniform int charBase;\n"
192 "uniform int size;\n"
193 "uniform ivec4 inflags;\n"
194 "uniform ivec2[4] offset;\n"
195 "uniform ivec2[4] transform;\n"
196 "uniform vec2 range;\n"
197 "out vec4 color;\n"
198 "out vec4 flags;\n"
199 FLAG_CONST
200 "precision highp float;\n"
201 "precision highp int;\n"
202
203 "vec4 fetchTile(ivec2 coord);\n"
204 "vec2 interpolate(ivec2 arr[4], float x);\n"
205
206 "vec4 renderTile(ivec2 coord) {\n"
207 " int map = (coord.x >> 11) + (((coord.y >> 7) & 0x7F0) << size);\n"
208 " int mapAddress = screenBase + (map >> 1);\n"
209 " vec4 twomaps = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0);\n"
210 " int tile = int(twomaps[3 - 2 * (map & 1)] * 15.9) + int(twomaps[2 - 2 * (map & 1)] * 15.9) * 16;\n"
211 " int address = charBase + tile * 32 + ((coord.x >> 9) & 3) + ((coord.y >> 6) & 0x1C);\n"
212 " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n"
213 " int entry = int(halfrow[3 - ((coord.x >> 7) & 2)] * 15.9);\n"
214 " int pal2 = int(halfrow[2 - ((coord.x >> 7) & 2)] * 15.9);\n"
215 " vec4 color = texelFetch(palette, ivec2(entry, pal2), 0);\n"
216 " if ((pal2 | entry) == 0) {\n"
217 " discard;\n"
218 " }\n"
219 " color.a = 1.;\n"
220 " return color;\n"
221 "}\n"
222
223 "void main() {\n"
224 " float y = texCoord.y - range.x;\n"
225 " float lin = 0.5 - y / range.y * 0.25;\n"
226 " vec2 mixedTransform = interpolate(transform, lin);\n"
227 " vec2 mixedOffset = interpolate(offset, lin);\n"
228 " color = fetchTile(ivec2(mixedTransform * texCoord.x + mixedOffset));\n"
229 " flags = inflags / flagCoeff;\n"
230 "}";
231
232static const struct GBAVideoGLUniform _uniformsMode35[] = {
233 { "loc", GBA_GL_VS_LOC, },
234 { "maxPos", GBA_GL_VS_MAXPOS, },
235 { "vram", GBA_GL_BG_VRAM, },
236 { "charBase", GBA_GL_BG_CHARBASE, },
237 { "size", GBA_GL_BG_SIZE, },
238 { "inflags", GBA_GL_BG_INFLAGS, },
239 { "offset", GBA_GL_BG_OFFSET, },
240 { "transform", GBA_GL_BG_TRANSFORM, },
241 { "range", GBA_GL_BG_RANGE, },
242 { 0 }
243};
244
245static const char* const _renderMode35 =
246 "in vec2 texCoord;\n"
247 "uniform sampler2D vram;\n"
248 "uniform int charBase;\n"
249 "uniform ivec2 size;\n"
250 "uniform ivec4 inflags;\n"
251 "uniform ivec2[4] offset;\n"
252 "uniform ivec2[4] transform;\n"
253 "uniform vec2 range;\n"
254 "out vec4 color;\n"
255 "out vec4 flags;\n"
256 FLAG_CONST
257 "precision highp float;\n"
258 "precision highp int;\n"
259
260 "vec2 interpolate(ivec2 arr[4], float x);\n"
261
262 "void main() {\n"
263 " float y = texCoord.y - range.x;\n"
264 " float lin = 0.5 - y / range.y * 0.25;\n"
265 " vec2 mixedTransform = interpolate(transform, lin);\n"
266 " vec2 mixedOffset = interpolate(offset, lin);\n"
267 " ivec2 coord = ivec2(mixedTransform * texCoord.x + mixedOffset);\n"
268 " if (coord.x < 0 || coord.x >= (size.x << 8)) {\n"
269 " discard;\n"
270 " }\n"
271 " if (coord.y < 0 || coord.y >= (size.y << 8)) {\n"
272 " discard;\n"
273 " }\n"
274 " int address = charBase + (coord.x >> 8) + (coord.y >> 8) * size.x;\n"
275 " ivec4 entry = ivec4(texelFetch(vram, ivec2(address & 255, address >> 8), 0) * 15.9);\n"
276 " int sixteen = (entry.x << 12) | (entry.y << 8) | (entry.z << 4) | entry.w;\n"
277 " color = vec4((sixteen & 0x1F) / 31., ((sixteen >> 5) & 0x1F) / 31., ((sixteen >> 10) & 0x1F) / 31., 1.);\n"
278 " flags = inflags / flagCoeff;\n"
279 "}";
280
281static const struct GBAVideoGLUniform _uniformsMode4[] = {
282 { "loc", GBA_GL_VS_LOC, },
283 { "maxPos", GBA_GL_VS_MAXPOS, },
284 { "vram", GBA_GL_BG_VRAM, },
285 { "palette", GBA_GL_BG_PALETTE, },
286 { "charBase", GBA_GL_BG_CHARBASE, },
287 { "size", GBA_GL_BG_SIZE, },
288 { "inflags", GBA_GL_BG_INFLAGS, },
289 { "offset", GBA_GL_BG_OFFSET, },
290 { "transform", GBA_GL_BG_TRANSFORM, },
291 { "range", GBA_GL_BG_RANGE, },
292 { 0 }
293};
294
295static const char* const _renderMode4 =
296 "in vec2 texCoord;\n"
297 "uniform sampler2D vram;\n"
298 "uniform sampler2D palette;\n"
299 "uniform int charBase;\n"
300 "uniform ivec2 size;\n"
301 "uniform ivec4 inflags;\n"
302 "uniform ivec2[4] offset;\n"
303 "uniform ivec2[4] transform;\n"
304 "uniform vec2 range;\n"
305 "out vec4 color;\n"
306 "out vec4 flags;\n"
307 FLAG_CONST
308 "precision highp float;\n"
309 "precision highp int;\n"
310
311 "vec2 interpolate(ivec2 arr[4], float x);\n"
312
313 "void main() {\n"
314 " float y = texCoord.y - range.x;\n"
315 " float lin = 0.5 - y / range.y * 0.25;\n"
316 " vec2 mixedTransform = interpolate(transform, lin);\n"
317 " vec2 mixedOffset = interpolate(offset, lin);\n"
318 " ivec2 coord = ivec2(mixedTransform * texCoord.x + mixedOffset);\n"
319 " if (coord.x < 0 || coord.x >= (size.x << 8)) {\n"
320 " discard;\n"
321 " }\n"
322 " if (coord.y < 0 || coord.y >= (size.y << 8)) {\n"
323 " discard;\n"
324 " }\n"
325 " int address = charBase + (coord.x >> 8) + (coord.y >> 8) * size.x;\n"
326 " vec4 twoEntries = texelFetch(vram, ivec2((address >> 1) & 255, address >> 9), 0);\n"
327 " ivec2 entry = ivec2(twoEntries[3 - 2 * (address & 1)] * 15.9, twoEntries[2 - 2 * (address & 1)] * 15.9);\n"
328 " color = texelFetch(palette, entry, 0);\n"
329 " color.a = 1;\n"
330 " flags = inflags / flagCoeff;\n"
331 "}";
332
333static const struct GBAVideoGLUniform _uniformsObj[] = {
334 { "loc", GBA_GL_VS_LOC, },
335 { "maxPos", GBA_GL_VS_MAXPOS, },
336 { "vram", GBA_GL_OBJ_VRAM, },
337 { "palette", GBA_GL_OBJ_PALETTE, },
338 { "charBase", GBA_GL_OBJ_CHARBASE, },
339 { "stride", GBA_GL_OBJ_STRIDE, },
340 { "localPalette", GBA_GL_OBJ_LOCALPALETTE, },
341 { "inflags", GBA_GL_OBJ_INFLAGS, },
342 { "transform", GBA_GL_OBJ_TRANSFORM, },
343 { "dims", GBA_GL_OBJ_DIMS, },
344 { "objwin", GBA_GL_OBJ_OBJWIN, },
345 { 0 }
346};
347
348static const char* const _renderObj =
349 "in vec2 texCoord;\n"
350 "uniform sampler2D vram;\n"
351 "uniform sampler2D palette;\n"
352 "uniform int charBase;\n"
353 "uniform int stride;\n"
354 "uniform int localPalette;\n"
355 "uniform ivec4 inflags;\n"
356 "uniform mat2x2 transform;\n"
357 "uniform ivec4 dims;\n"
358 "uniform vec4 objwin;\n"
359 "out vec4 color;\n"
360 "out vec4 flags;\n"
361 "out vec3 window;\n"
362 FLAG_CONST
363
364 "vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n"
365
366 "void main() {\n"
367 " ivec2 coord = ivec2(transform * (texCoord - dims.zw / 2) + dims.xy / 2);\n"
368 " if ((coord & ~(dims.xy - 1)) != ivec2(0, 0)) {\n"
369 " discard;\n"
370 " }\n"
371 " vec4 pix = renderTile((coord.x >> 3) + (coord.y >> 3) * stride, 16 + localPalette, coord & 7);\n"
372 " if (objwin.x > 0) {\n"
373 " pix.a = 0;\n"
374 " }\n"
375 " color = pix;\n"
376 " flags = inflags / flagCoeff;\n"
377 " window = objwin.yzw;\n"
378 "}";
379
380static const struct GBAVideoGLUniform _uniformsFinalize[] = {
381 { "loc", GBA_GL_VS_LOC, },
382 { "maxPos", GBA_GL_VS_MAXPOS, },
383 { "scale", GBA_GL_FINALIZE_SCALE, },
384 { "layers", GBA_GL_FINALIZE_LAYERS, },
385 { "flags", GBA_GL_FINALIZE_FLAGS, },
386 { "window", GBA_GL_FINALIZE_WINDOW, },
387 { "backdrop", GBA_GL_FINALIZE_BACKDROP, },
388 { "backdropFlags", GBA_GL_FINALIZE_BACKDROPFLAGS, },
389 { 0 }
390};
391
392static const char* const _finalize =
393 "in vec2 texCoord;\n"
394 "uniform int scale;\n"
395 "uniform sampler2D layers[5];\n"
396 "uniform sampler2D flags[5];\n"
397 "uniform sampler2D window;\n"
398 "uniform vec4 backdrop;\n"
399 "uniform vec4 backdropFlags;\n"
400 FLAG_CONST
401 "out vec4 color;\n"
402
403 "void composite(vec4 pixel, ivec4 flags, inout vec4 topPixel, inout ivec4 topFlags, inout vec4 bottomPixel, inout ivec4 bottomFlags) {\n"
404 " if (pixel.a == 0) {\n"
405 " return;\n"
406 " }\n"
407 " if (flags.x >= topFlags.x) {\n"
408 " if (flags.x >= bottomFlags.x) {\n"
409 " return;\n"
410 " }\n"
411 " bottomFlags = flags;\n"
412 " bottomPixel = pixel;\n"
413 " } else {\n"
414 " bottomFlags = topFlags;\n"
415 " topFlags = flags;\n"
416 " bottomPixel = topPixel;\n"
417 " topPixel = pixel;\n"
418 " }\n"
419 "}\n"
420
421 "void main() {\n"
422 " vec4 windowFlags = texelFetch(window, ivec2(texCoord * scale), 0);\n"
423 " int layerWindow = int(windowFlags.x * 128);\n"
424 " vec4 topPixel = backdrop;\n"
425 " vec4 bottomPixel = backdrop;\n"
426 " ivec4 topFlags = ivec4(backdropFlags * flagCoeff);\n"
427 " ivec4 bottomFlags = ivec4(backdropFlags * flagCoeff);\n"
428 " if ((layerWindow & 1) == 0) {\n"
429 " vec4 pix = texelFetch(layers[0], ivec2(texCoord * scale), 0);\n"
430 " ivec4 inflags = ivec4(texelFetch(flags[0], ivec2(texCoord * scale), 0).xyz * flagCoeff.xyz, 0);\n"
431 " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n"
432 " }\n"
433 " if ((layerWindow & 2) == 0) {\n"
434 " vec4 pix = texelFetch(layers[1], ivec2(texCoord * scale), 0);\n"
435 " ivec4 inflags = ivec4(texelFetch(flags[1], ivec2(texCoord * scale), 0).xyz * flagCoeff.xyz, 0);\n"
436 " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n"
437 " }\n"
438 " if ((layerWindow & 4) == 0) {\n"
439 " vec4 pix = texelFetch(layers[2], ivec2(texCoord * scale), 0);\n"
440 " ivec4 inflags = ivec4(texelFetch(flags[2], ivec2(texCoord * scale), 0).xyz * flagCoeff.xyz, 0);\n"
441 " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n"
442 " }\n"
443 " if ((layerWindow & 8) == 0) {\n"
444 " vec4 pix = texelFetch(layers[3], ivec2(texCoord * scale), 0);\n"
445 " ivec4 inflags = ivec4(texelFetch(flags[3], ivec2(texCoord * scale), 0).xyz * flagCoeff.xyz, 0);\n"
446 " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n"
447 " }\n"
448 " if ((layerWindow & 16) == 0) {\n"
449 " vec4 pix = texelFetch(layers[4], ivec2(texCoord * scale), 0);\n"
450 " ivec4 inflags = ivec4(texelFetch(flags[4], ivec2(texCoord * scale), 0) * flagCoeff);\n"
451 " composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n"
452 " }\n"
453 " if ((layerWindow & 32) != 0) {\n"
454 " topFlags.y &= ~1;\n"
455 " }\n"
456 " if (((topFlags.y & 13) == 5 || topFlags.w > 0) && (bottomFlags.y & 2) == 2) {\n"
457 " topPixel *= topFlags.z / 16.;\n"
458 " topPixel += bottomPixel * windowFlags.y;\n"
459 " } else if ((topFlags.y & 13) == 9) {\n"
460 " topPixel += (1. - topPixel) * windowFlags.z;\n"
461 " } else if ((topFlags.y & 13) == 13) {\n"
462 " topPixel -= topPixel * windowFlags.z;\n"
463 " }\n"
464 " color = topPixel;\n"
465 "}";
466
467static const GLint _vertices[] = {
468 0, 0,
469 0, 1,
470 1, 1,
471 1, 0,
472};
473
474void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) {
475 renderer->d.init = GBAVideoGLRendererInit;
476 renderer->d.reset = GBAVideoGLRendererReset;
477 renderer->d.deinit = GBAVideoGLRendererDeinit;
478 renderer->d.writeVideoRegister = GBAVideoGLRendererWriteVideoRegister;
479 renderer->d.writeVRAM = GBAVideoGLRendererWriteVRAM;
480 renderer->d.writeOAM = GBAVideoGLRendererWriteOAM;
481 renderer->d.writePalette = GBAVideoGLRendererWritePalette;
482 renderer->d.drawScanline = GBAVideoGLRendererDrawScanline;
483 renderer->d.finishFrame = GBAVideoGLRendererFinishFrame;
484 renderer->d.getPixels = GBAVideoGLRendererGetPixels;
485 renderer->d.putPixels = GBAVideoGLRendererPutPixels;
486
487 renderer->d.disableBG[0] = false;
488 renderer->d.disableBG[1] = false;
489 renderer->d.disableBG[2] = false;
490 renderer->d.disableBG[3] = false;
491 renderer->d.disableOBJ = false;
492
493 renderer->scale = 1;
494}
495
496static void _compileShader(struct GBAVideoGLRenderer* glRenderer, struct GBAVideoGLShader* shader, const char** shaderBuffer, int shaderBufferLines, GLuint vs, const struct GBAVideoGLUniform* uniforms, char* log) {
497 GLuint program = glCreateProgram();
498 shader->program = program;
499
500 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
501 glAttachShader(program, vs);
502 glAttachShader(program, fs);
503 glShaderSource(fs, shaderBufferLines, shaderBuffer, 0);
504 glCompileShader(fs);
505 glGetShaderInfoLog(fs, 1024, 0, log);
506 if (log[0]) {
507 mLOG(GBA_VIDEO, ERROR, "Fragment shader compilation failure: %s", log);
508 }
509 glLinkProgram(program);
510 glGetProgramInfoLog(program, 1024, 0, log);
511 if (log[0]) {
512 mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log);
513 }
514 glDeleteShader(fs);
515#ifndef BUILD_GLES3
516 glBindFragDataLocation(program, 0, "color");
517 glBindFragDataLocation(program, 1, "flags");
518#endif
519
520 glGenVertexArrays(1, &shader->vao);
521 glBindVertexArray(shader->vao);
522 glBindBuffer(GL_ARRAY_BUFFER, glRenderer->vbo);
523 GLuint positionLocation = glGetAttribLocation(program, "position");
524 glVertexAttribPointer(positionLocation, 2, GL_INT, GL_FALSE, 0, NULL);
525
526 size_t i;
527 for (i = 0; uniforms[i].name; ++i) {
528 shader->uniforms[uniforms[i].type] = glGetUniformLocation(program, uniforms[i].name);
529 }
530}
531
532static void _deleteShader(struct GBAVideoGLShader* shader) {
533 glDeleteProgram(shader->program);
534 glDeleteVertexArrays(1, &shader->vao);
535}
536
537static void _initFramebufferTexture(GLuint tex, GLenum format, GLenum attachment, int scale) {
538 glBindTexture(GL_TEXTURE_2D, tex);
539 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
540 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
541 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
542 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
543 glTexImage2D(GL_TEXTURE_2D, 0, format, GBA_VIDEO_HORIZONTAL_PIXELS * scale, GBA_VIDEO_VERTICAL_PIXELS * scale, 0, format, GL_UNSIGNED_BYTE, 0);
544 glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex, 0);
545}
546
547void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
548 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
549 glRenderer->temporaryBuffer = NULL;
550
551 glGenFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo);
552 glGenTextures(GBA_GL_TEX_MAX, glRenderer->layers);
553
554 glGenTextures(1, &glRenderer->paletteTex);
555 glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
556 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
557 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
558
559 glGenTextures(1, &glRenderer->vramTex);
560 glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex);
561 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
562 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
563 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 256, 192, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0);
564
565 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
566 _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale);
567 _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], GL_RGBA, GL_COLOR_ATTACHMENT1, glRenderer->scale);
568 _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_WINDOW], GL_RGBA, GL_COLOR_ATTACHMENT2, glRenderer->scale);
569
570 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_WINDOW]);
571 _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_WINDOW], GL_RGB, GL_COLOR_ATTACHMENT0, glRenderer->scale);
572
573 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OUTPUT]);
574 _initFramebufferTexture(glRenderer->outputTex, GL_RGB, GL_COLOR_ATTACHMENT0, glRenderer->scale);
575
576 glBindFramebuffer(GL_FRAMEBUFFER, 0);
577
578 glGenBuffers(1, &glRenderer->vbo);
579 glBindBuffer(GL_ARRAY_BUFFER, glRenderer->vbo);
580 glBufferData(GL_ARRAY_BUFFER, sizeof(_vertices), _vertices, GL_STATIC_DRAW);
581
582 int i;
583 for (i = 0; i < 4; ++i) {
584 struct GBAVideoGLBackground* bg = &glRenderer->bg[i];
585 bg->index = i;
586 bg->enabled = 0;
587 bg->priority = 0;
588 bg->charBase = 0;
589 bg->mosaic = 0;
590 bg->multipalette = 0;
591 bg->screenBase = 0;
592 bg->overflow = 0;
593 bg->size = 0;
594 bg->target1 = 0;
595 bg->target2 = 0;
596 bg->x = 0;
597 bg->y = 0;
598 bg->refx = 0;
599 bg->refy = 0;
600 bg->affine[0].dx = 256;
601 bg->affine[0].dmx = 0;
602 bg->affine[0].dy = 0;
603 bg->affine[0].dmy = 256;
604 bg->affine[0].sx = 0;
605 bg->affine[0].sy = 0;
606 glGenFramebuffers(1, &bg->fbo);
607 glGenTextures(1, &bg->tex);
608 glGenTextures(1, &bg->flags);
609 glBindFramebuffer(GL_FRAMEBUFFER, bg->fbo);
610 _initFramebufferTexture(bg->tex, GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale);
611 _initFramebufferTexture(bg->flags, GL_RGB, GL_COLOR_ATTACHMENT1, glRenderer->scale);
612 glBindFramebuffer(GL_FRAMEBUFFER, 0);
613 }
614
615 char log[1024];
616 const GLchar* shaderBuffer[8];
617 shaderBuffer[0] = _gl3Header;
618
619 GLuint vs = glCreateShader(GL_VERTEX_SHADER);
620 shaderBuffer[1] = _vertexShader;
621 glShaderSource(vs, 2, shaderBuffer, 0);
622 glCompileShader(vs);
623 glGetShaderInfoLog(vs, 1024, 0, log);
624 if (log[0]) {
625 mLOG(GBA_VIDEO, ERROR, "Vertex shader compilation failure: %s", log);
626 }
627
628 shaderBuffer[1] = _renderMode0;
629
630 shaderBuffer[2] = _renderTile16;
631 _compileShader(glRenderer, &glRenderer->bgShader[0], shaderBuffer, 3, vs, _uniformsMode0, log);
632
633 shaderBuffer[2] = _renderTile256;
634 _compileShader(glRenderer, &glRenderer->bgShader[1], shaderBuffer, 3, vs, _uniformsMode0, log);
635
636 shaderBuffer[1] = _renderMode2;
637 shaderBuffer[2] = _interpolate;
638
639 shaderBuffer[3] = _fetchTileOverflow;
640 _compileShader(glRenderer, &glRenderer->bgShader[2], shaderBuffer, 4, vs, _uniformsMode2, log);
641
642 shaderBuffer[3] = _fetchTileNoOverflow;
643 _compileShader(glRenderer, &glRenderer->bgShader[3], shaderBuffer, 4, vs, _uniformsMode2, log);
644
645 shaderBuffer[1] = _renderMode4;
646 shaderBuffer[2] = _interpolate;
647 _compileShader(glRenderer, &glRenderer->bgShader[4], shaderBuffer, 3, vs, _uniformsMode4, log);
648
649 shaderBuffer[1] = _renderMode35;
650 shaderBuffer[2] = _interpolate;
651 _compileShader(glRenderer, &glRenderer->bgShader[5], shaderBuffer, 3, vs, _uniformsMode35, log);
652
653 shaderBuffer[1] = _renderObj;
654
655 shaderBuffer[2] = _renderTile16;
656 _compileShader(glRenderer, &glRenderer->objShader[0], shaderBuffer, 3, vs, _uniformsObj, log);
657#ifndef BUILD_GLES3
658 glBindFragDataLocation(glRenderer->objShader[0].program, 2, "window");
659#endif
660
661 shaderBuffer[2] = _renderTile256;
662 _compileShader(glRenderer, &glRenderer->objShader[1], shaderBuffer, 3, vs, _uniformsObj, log);
663#ifndef BUILD_GLES3
664 glBindFragDataLocation(glRenderer->objShader[1].program, 2, "window");
665#endif
666
667 shaderBuffer[1] = _finalize;
668 _compileShader(glRenderer, &glRenderer->finalizeShader, shaderBuffer, 2, vs, _uniformsFinalize, log);
669
670 glBindVertexArray(0);
671 glDeleteShader(vs);
672
673 GBAVideoGLRendererReset(renderer);
674}
675
676void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) {
677 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
678 if (glRenderer->temporaryBuffer) {
679 mappedMemoryFree(glRenderer->temporaryBuffer, GBA_VIDEO_HORIZONTAL_PIXELS * GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale * glRenderer->scale);
680 }
681 glDeleteFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo);
682 glDeleteTextures(GBA_GL_TEX_MAX, glRenderer->layers);
683 glDeleteTextures(1, &glRenderer->paletteTex);
684 glDeleteTextures(1, &glRenderer->vramTex);
685
686 _deleteShader(&glRenderer->bgShader[0]);
687 _deleteShader(&glRenderer->bgShader[1]);
688 _deleteShader(&glRenderer->bgShader[2]);
689 _deleteShader(&glRenderer->bgShader[3]);
690 _deleteShader(&glRenderer->objShader[0]);
691 _deleteShader(&glRenderer->objShader[1]);
692 _deleteShader(&glRenderer->finalizeShader);
693
694 int i;
695 for (i = 0; i < 4; ++i) {
696 struct GBAVideoGLBackground* bg = &glRenderer->bg[i];
697 glDeleteFramebuffers(1, &bg->fbo);
698 glDeleteTextures(1, &bg->tex);
699 glDeleteTextures(1, &bg->flags);
700 }
701}
702
703void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
704 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
705
706 glRenderer->paletteDirty = true;
707 glRenderer->vramDirty = 0xFFFFFF;
708 glRenderer->firstAffine = -1;
709}
710
711void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
712 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
713 glRenderer->vramDirty |= 1 << (address >> 12);
714}
715
716void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
717 UNUSED(oam);
718 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
719 glRenderer->oamDirty = true;
720}
721
722void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
723 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
724#ifdef BUILD_GLES3
725 glRenderer->shadowPalette[address >> 1] = (value & 0x3F) | ((value & 0x7FE0) << 1);
726#else
727 UNUSED(address);
728 UNUSED(value);
729#endif
730 glRenderer->paletteDirty = true;
731}
732
733uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
734 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
735 if (renderer->cache) {
736 GBAVideoCacheWriteVideoRegister(renderer->cache, address, value);
737 }
738
739 switch (address) {
740 case REG_DISPCNT:
741 value &= 0xFFF7;
742 glRenderer->dispcnt = value;
743 GBAVideoGLRendererUpdateDISPCNT(glRenderer);
744 break;
745 case REG_BG0CNT:
746 value &= 0xDFFF;
747 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[0], value);
748 break;
749 case REG_BG1CNT:
750 value &= 0xDFFF;
751 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[1], value);
752 break;
753 case REG_BG2CNT:
754 value &= 0xFFFF;
755 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[2], value);
756 break;
757 case REG_BG3CNT:
758 value &= 0xFFFF;
759 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[3], value);
760 break;
761 case REG_BG0HOFS:
762 value &= 0x01FF;
763 glRenderer->bg[0].x = value;
764 break;
765 case REG_BG0VOFS:
766 value &= 0x01FF;
767 glRenderer->bg[0].y = value;
768 break;
769 case REG_BG1HOFS:
770 value &= 0x01FF;
771 glRenderer->bg[1].x = value;
772 break;
773 case REG_BG1VOFS:
774 value &= 0x01FF;
775 glRenderer->bg[1].y = value;
776 break;
777 case REG_BG2HOFS:
778 value &= 0x01FF;
779 glRenderer->bg[2].x = value;
780 break;
781 case REG_BG2VOFS:
782 value &= 0x01FF;
783 glRenderer->bg[2].y = value;
784 break;
785 case REG_BG3HOFS:
786 value &= 0x01FF;
787 glRenderer->bg[3].x = value;
788 break;
789 case REG_BG3VOFS:
790 value &= 0x01FF;
791 glRenderer->bg[3].y = value;
792 break;
793 case REG_BG2PA:
794 glRenderer->bg[2].affine[0].dx = value;
795 break;
796 case REG_BG2PB:
797 glRenderer->bg[2].affine[0].dmx = value;
798 break;
799 case REG_BG2PC:
800 glRenderer->bg[2].affine[0].dy = value;
801 break;
802 case REG_BG2PD:
803 glRenderer->bg[2].affine[0].dmy = value;
804 break;
805 case REG_BG2X_LO:
806 GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value);
807 break;
808 case REG_BG2X_HI:
809 GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[2], value);
810 break;
811 case REG_BG2Y_LO:
812 GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[2], value);
813 break;
814 case REG_BG2Y_HI:
815 GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value);
816 break;
817 case REG_BG3PA:
818 glRenderer->bg[3].affine[0].dx = value;
819 break;
820 case REG_BG3PB:
821 glRenderer->bg[3].affine[0].dmx = value;
822 break;
823 case REG_BG3PC:
824 glRenderer->bg[3].affine[0].dy = value;
825 break;
826 case REG_BG3PD:
827 glRenderer->bg[3].affine[0].dmy = value;
828 break;
829 case REG_BG3X_LO:
830 GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value);
831 break;
832 case REG_BG3X_HI:
833 GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[3], value);
834 break;
835 case REG_BG3Y_LO:
836 GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[3], value);
837 break;
838 case REG_BG3Y_HI:
839 GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[3], value);
840 break;
841 case REG_BLDCNT:
842 GBAVideoGLRendererWriteBLDCNT(glRenderer, value);
843 value &= 0x3FFF;
844 break;
845 case REG_BLDALPHA:
846 glRenderer->blda = value & 0x1F;
847 if (glRenderer->blda > 0x10) {
848 glRenderer->blda = 0x10;
849 }
850 glRenderer->bldb = (value >> 8) & 0x1F;
851 if (glRenderer->bldb > 0x10) {
852 glRenderer->bldb = 0x10;
853 }
854 value &= 0x1F1F;
855 break;
856 case REG_BLDY:
857 value &= 0x1F;
858 if (value > 0x10) {
859 value = 0x10;
860 }
861 glRenderer->bldy = value;
862 break;
863 case REG_WIN0H:
864 glRenderer->winN[0].h[0].end = value;
865 glRenderer->winN[0].h[0].start = value >> 8;
866 if (glRenderer->winN[0].h[0].start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[0].h[0].start > glRenderer->winN[0].h[0].end) {
867 glRenderer->winN[0].h[0].start = 0;
868 }
869 if (glRenderer->winN[0].h[0].end > GBA_VIDEO_HORIZONTAL_PIXELS) {
870 glRenderer->winN[0].h[0].end = GBA_VIDEO_HORIZONTAL_PIXELS;
871 if (glRenderer->winN[0].h[0].start > GBA_VIDEO_HORIZONTAL_PIXELS) {
872 glRenderer->winN[0].h[0].start = GBA_VIDEO_HORIZONTAL_PIXELS;
873 }
874 }
875 break;
876 case REG_WIN1H:
877 glRenderer->winN[1].h[0].end = value;
878 glRenderer->winN[1].h[0].start = value >> 8;
879 if (glRenderer->winN[1].h[0].start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[1].h[0].start > glRenderer->winN[1].h[0].end) {
880 glRenderer->winN[1].h[0].start = 0;
881 }
882 if (glRenderer->winN[1].h[0].end > GBA_VIDEO_HORIZONTAL_PIXELS) {
883 glRenderer->winN[1].h[0].end = GBA_VIDEO_HORIZONTAL_PIXELS;
884 if (glRenderer->winN[1].h[0].start > GBA_VIDEO_HORIZONTAL_PIXELS) {
885 glRenderer->winN[1].h[0].start = GBA_VIDEO_HORIZONTAL_PIXELS;
886 }
887 }
888 break;
889 case REG_WIN0V:
890 glRenderer->winN[0].v.end = value;
891 glRenderer->winN[0].v.start = value >> 8;
892 if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[0].v.start > glRenderer->winN[0].v.end) {
893 glRenderer->winN[0].v.start = 0;
894 }
895 if (glRenderer->winN[0].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
896 glRenderer->winN[0].v.end = GBA_VIDEO_VERTICAL_PIXELS;
897 if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
898 glRenderer->winN[0].v.start = GBA_VIDEO_VERTICAL_PIXELS;
899 }
900 }
901 break;
902 case REG_WIN1V:
903 glRenderer->winN[1].v.end = value;
904 glRenderer->winN[1].v.start = value >> 8;
905 if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[1].v.start > glRenderer->winN[1].v.end) {
906 glRenderer->winN[1].v.start = 0;
907 }
908 if (glRenderer->winN[1].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
909 glRenderer->winN[1].v.end = GBA_VIDEO_VERTICAL_PIXELS;
910 if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
911 glRenderer->winN[1].v.start = GBA_VIDEO_VERTICAL_PIXELS;
912 }
913 }
914 break;
915 case REG_WININ:
916 value &= 0x3F3F;
917 glRenderer->winN[0].control = value;
918 glRenderer->winN[1].control = value >> 8;
919 break;
920 case REG_WINOUT:
921 value &= 0x3F3F;
922 glRenderer->winout = value;
923 glRenderer->objwin = value >> 8;
924 break;
925 case REG_MOSAIC:
926 glRenderer->mosaic = value;
927 break;
928 default:
929 break;
930 }
931 return value;
932}
933
934void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
935 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
936 if (glRenderer->paletteDirty) {
937 glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
938#ifdef BUILD_GLES3
939 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_6_5, glRenderer->shadowPalette);
940#else
941 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette);
942#endif
943 glRenderer->paletteDirty = false;
944 }
945 int i;
946 for (i = 0; i < 24; ++i) {
947 if (!(glRenderer->vramDirty & (1 << i))) {
948 continue;
949 }
950 // TODO: PBOs
951 glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex);
952 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 8 * i, 256, 8, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, &glRenderer->d.vram[2048 * i]);
953 }
954 glRenderer->vramDirty = 0;
955
956 if (y == 0) {
957 memcpy(&glRenderer->winN[0].h[1], &glRenderer->winN[0].h[0], sizeof(struct GBAVideoWindowRegion));
958 memcpy(&glRenderer->winN[1].h[1], &glRenderer->winN[1].h[0], sizeof(struct GBAVideoWindowRegion));
959
960 glDisable(GL_SCISSOR_TEST);
961 glClearColor(0, 0, 0, 0);
962 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
963 glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
964 glClear(GL_COLOR_BUFFER_BIT);
965
966 for (i = 0; i < 4; ++i) {
967 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo);
968 glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
969 glClear(GL_COLOR_BUFFER_BIT);
970 }
971 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
972 }
973 glEnable(GL_SCISSOR_TEST);
974
975 if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
976 if (glRenderer->firstAffine < 0) {
977 memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
978 memcpy(&glRenderer->bg[3].affine[3], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
979 memcpy(&glRenderer->bg[2].affine[2], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
980 memcpy(&glRenderer->bg[3].affine[2], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
981 memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
982 memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
983 glRenderer->firstAffine = y;
984 }
985 } else {
986 glRenderer->firstAffine = -1;
987 }
988
989 GBAVideoGLRendererDrawWindow(glRenderer, y);
990 if (GBARegisterDISPCNTIsObjEnable(glRenderer->dispcnt) && !glRenderer->d.disableOBJ) {
991 if (glRenderer->oamDirty) {
992 glRenderer->oamMax = GBAVideoRendererCleanOAM(glRenderer->d.oam->obj, glRenderer->sprites, 0);
993 glRenderer->oamDirty = false;
994 }
995 int i;
996 for (i = glRenderer->oamMax; i--;) {
997 struct GBAVideoRendererSprite* sprite = &glRenderer->sprites[i];
998 if ((y < sprite->y && (sprite->endY - 256 < 0 || y >= sprite->endY - 256)) || y >= sprite->endY) {
999 continue;
1000 }
1001
1002 GBAVideoGLRendererDrawSprite(glRenderer, &sprite->obj, y, sprite->y);
1003 }
1004 }
1005
1006 if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
1007 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[0], y);
1008 }
1009 if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
1010 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[1], y);
1011 }
1012 if (TEST_LAYER_ENABLED(2)) {
1013 switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
1014 case 0:
1015 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[2], y);
1016 break;
1017 case 1:
1018 case 2:
1019 GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[2], y);
1020 break;
1021 case 3:
1022 GBAVideoGLRendererDrawBackgroundMode3(glRenderer, &glRenderer->bg[2], y);
1023 break;
1024 case 4:
1025 GBAVideoGLRendererDrawBackgroundMode4(glRenderer, &glRenderer->bg[2], y);
1026 break;
1027 case 5:
1028 GBAVideoGLRendererDrawBackgroundMode5(glRenderer, &glRenderer->bg[2], y);
1029 break;
1030 }
1031 }
1032 if (TEST_LAYER_ENABLED(3)) {
1033 switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
1034 case 0:
1035 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[3], y);
1036 break;
1037 case 2:
1038 GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[3], y);
1039 break;
1040 }
1041 }
1042
1043 if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
1044 memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[2], sizeof(struct GBAVideoGLAffine));
1045 memcpy(&glRenderer->bg[3].affine[3], &glRenderer->bg[3].affine[2], sizeof(struct GBAVideoGLAffine));
1046 memcpy(&glRenderer->bg[2].affine[2], &glRenderer->bg[2].affine[1], sizeof(struct GBAVideoGLAffine));
1047 memcpy(&glRenderer->bg[3].affine[2], &glRenderer->bg[3].affine[1], sizeof(struct GBAVideoGLAffine));
1048 memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
1049 memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
1050
1051 glRenderer->bg[2].affine[0].sx += glRenderer->bg[2].affine[0].dmx;
1052 glRenderer->bg[2].affine[0].sy += glRenderer->bg[2].affine[0].dmy;
1053 glRenderer->bg[3].affine[0].sx += glRenderer->bg[3].affine[0].dmx;
1054 glRenderer->bg[3].affine[0].sy += glRenderer->bg[3].affine[0].dmy;
1055 }
1056 memcpy(&glRenderer->winN[0].h[1], &glRenderer->winN[0].h[0], sizeof(struct GBAVideoWindowRegion));
1057 memcpy(&glRenderer->winN[1].h[1], &glRenderer->winN[1].h[0], sizeof(struct GBAVideoWindowRegion));
1058}
1059
1060void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) {
1061 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
1062 _finalizeLayers(glRenderer);
1063 glRenderer->firstAffine = -1;
1064 glRenderer->bg[2].affine[0].sx = glRenderer->bg[2].refx;
1065 glRenderer->bg[2].affine[0].sy = glRenderer->bg[2].refy;
1066 glRenderer->bg[3].affine[0].sx = glRenderer->bg[3].refx;
1067 glRenderer->bg[3].affine[0].sy = glRenderer->bg[3].refy;
1068 glFlush();
1069}
1070
1071void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
1072 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
1073 *stride = GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale;
1074 if (!glRenderer->temporaryBuffer) {
1075 glRenderer->temporaryBuffer = anonymousMemoryMap(GBA_VIDEO_HORIZONTAL_PIXELS * GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale * glRenderer->scale * BYTES_PER_PIXEL);
1076 }
1077 glFinish();
1078 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OUTPUT]);
1079 glPixelStorei(GL_PACK_ROW_LENGTH, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale);
1080 glPixelStorei(GL_PACK_ALIGNMENT, 1);
1081 glReadPixels(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, GL_RGBA, GL_UNSIGNED_BYTE, (void*) glRenderer->temporaryBuffer);
1082 *pixels = glRenderer->temporaryBuffer;
1083}
1084
1085void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
1086
1087}
1088
1089static void _enableBg(struct GBAVideoGLRenderer* renderer, int bg, bool active) {
1090 int wasActive = renderer->bg[bg].enabled;
1091 if (!active) {
1092 renderer->bg[bg].enabled = 0;
1093 } else if (!wasActive && active) {
1094 /*if (renderer->nextY == 0 || GBARegisterDISPCNTGetMode(renderer->dispcnt) > 2) {
1095 // TODO: Investigate in more depth how switching background works in different modes
1096 renderer->bg[bg].enabled = 4;
1097 } else {
1098 renderer->bg[bg].enabled = 1;
1099 }*/
1100 renderer->bg[bg].enabled = 4;
1101 }
1102}
1103
1104static void GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer* renderer) {
1105 _enableBg(renderer, 0, GBARegisterDISPCNTGetBg0Enable(renderer->dispcnt));
1106 _enableBg(renderer, 1, GBARegisterDISPCNTGetBg1Enable(renderer->dispcnt));
1107 _enableBg(renderer, 2, GBARegisterDISPCNTGetBg2Enable(renderer->dispcnt));
1108 _enableBg(renderer, 3, GBARegisterDISPCNTGetBg3Enable(renderer->dispcnt));
1109}
1110
1111static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value) {
1112 bg->priority = GBARegisterBGCNTGetPriority(value);
1113 bg->charBase = GBARegisterBGCNTGetCharBase(value) << 13;
1114 bg->mosaic = GBARegisterBGCNTGetMosaic(value);
1115 bg->multipalette = GBARegisterBGCNTGet256Color(value);
1116 bg->screenBase = GBARegisterBGCNTGetScreenBase(value) << 10;
1117 bg->overflow = GBARegisterBGCNTGetOverflow(value);
1118 bg->size = GBARegisterBGCNTGetSize(value);
1119}
1120
1121static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
1122 bg->refx = (bg->refx & 0xFFFF0000) | value;
1123 bg->affine[0].sx = bg->refx;
1124}
1125
1126static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
1127 bg->refx = (bg->refx & 0x0000FFFF) | (value << 16);
1128 bg->refx <<= 4;
1129 bg->refx >>= 4;
1130 bg->affine[0].sx = bg->refx;
1131}
1132
1133static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
1134 bg->refy = (bg->refy & 0xFFFF0000) | value;
1135 bg->affine[0].sy = bg->refy;
1136}
1137
1138static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
1139 bg->refy = (bg->refy & 0x0000FFFF) | (value << 16);
1140 bg->refy <<= 4;
1141 bg->refy >>= 4;
1142 bg->affine[0].sy = bg->refy;
1143}
1144
1145static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value) {
1146 renderer->bg[0].target1 = GBARegisterBLDCNTGetTarget1Bg0(value);
1147 renderer->bg[1].target1 = GBARegisterBLDCNTGetTarget1Bg1(value);
1148 renderer->bg[2].target1 = GBARegisterBLDCNTGetTarget1Bg2(value);
1149 renderer->bg[3].target1 = GBARegisterBLDCNTGetTarget1Bg3(value);
1150 renderer->bg[0].target2 = GBARegisterBLDCNTGetTarget2Bg0(value);
1151 renderer->bg[1].target2 = GBARegisterBLDCNTGetTarget2Bg1(value);
1152 renderer->bg[2].target2 = GBARegisterBLDCNTGetTarget2Bg2(value);
1153 renderer->bg[3].target2 = GBARegisterBLDCNTGetTarget2Bg3(value);
1154
1155 renderer->blendEffect = GBARegisterBLDCNTGetEffect(value);
1156 renderer->target1Obj = GBARegisterBLDCNTGetTarget1Obj(value);
1157 renderer->target1Bd = GBARegisterBLDCNTGetTarget1Bd(value);
1158 renderer->target2Obj = GBARegisterBLDCNTGetTarget2Obj(value);
1159 renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value);
1160}
1161
1162void _finalizeLayers(struct GBAVideoGLRenderer* renderer) {
1163 const GLuint* uniforms = renderer->finalizeShader.uniforms;
1164 glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OUTPUT]);
1165 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1166 glScissor(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1167 glUseProgram(renderer->finalizeShader.program);
1168 glBindVertexArray(renderer->finalizeShader.vao);
1169 glActiveTexture(GL_TEXTURE0);
1170 glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_WINDOW]);
1171 glActiveTexture(GL_TEXTURE0 + 1);
1172 glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_OBJ_COLOR]);
1173 glActiveTexture(GL_TEXTURE0 + 2);
1174 glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_OBJ_FLAGS]);
1175 glActiveTexture(GL_TEXTURE0 + 3);
1176 glBindTexture(GL_TEXTURE_2D, renderer->bg[0].tex);
1177 glActiveTexture(GL_TEXTURE0 + 4);
1178 glBindTexture(GL_TEXTURE_2D, renderer->bg[0].flags);
1179 glActiveTexture(GL_TEXTURE0 + 5);
1180 glBindTexture(GL_TEXTURE_2D, renderer->bg[1].tex);
1181 glActiveTexture(GL_TEXTURE0 + 6);
1182 glBindTexture(GL_TEXTURE_2D, renderer->bg[1].flags);
1183 glActiveTexture(GL_TEXTURE0 + 7);
1184 glBindTexture(GL_TEXTURE_2D, renderer->bg[2].tex);
1185 glActiveTexture(GL_TEXTURE0 + 8);
1186 glBindTexture(GL_TEXTURE_2D, renderer->bg[2].flags);
1187 glActiveTexture(GL_TEXTURE0 + 9);
1188 glBindTexture(GL_TEXTURE_2D, renderer->bg[3].tex);
1189 glActiveTexture(GL_TEXTURE0 + 10);
1190 glBindTexture(GL_TEXTURE_2D, renderer->bg[3].flags);
1191
1192 uint32_t backdrop = M_RGB5_TO_RGB8(renderer->d.palette[0]);
1193 glUniform2i(uniforms[GBA_GL_VS_LOC], GBA_VIDEO_VERTICAL_PIXELS, 0);
1194 glUniform2i(uniforms[GBA_GL_VS_MAXPOS], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1195 glUniform1i(uniforms[GBA_GL_FINALIZE_SCALE], renderer->scale);
1196 glUniform1iv(uniforms[GBA_GL_FINALIZE_LAYERS], 5, (GLint[]) { 3, 5, 7, 9, 1 });
1197 glUniform1iv(uniforms[GBA_GL_FINALIZE_FLAGS], 5, (GLint[]) { 4, 6, 8, 10, 2 });
1198 glUniform1i(uniforms[GBA_GL_FINALIZE_WINDOW], 0);
1199 glUniform4f(uniforms[GBA_GL_FINALIZE_BACKDROP], ((backdrop >> 16) & 0xFF) / 256., ((backdrop >> 8) & 0xFF) / 256., (backdrop & 0xFF) / 256., 0.f);
1200 glUniform4f(uniforms[GBA_GL_FINALIZE_BACKDROPFLAGS], 1, (renderer->target1Bd | (renderer->target2Bd * 2) | (renderer->blendEffect * 4)) / 32.f, renderer->blda / 16.f, 0);
1201 glEnableVertexAttribArray(0);
1202 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1203 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1204}
1205
1206void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY) {
1207 int width = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][0];
1208 int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][1];
1209 int32_t x = (uint32_t) GBAObjAttributesBGetX(sprite->b) << 23;
1210 x >>= 23;
1211
1212 int align = GBAObjAttributesAIs256Color(sprite->a) && !GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt);
1213 unsigned charBase = (BASE_TILE >> 1) + (GBAObjAttributesCGetTile(sprite->c) & ~align) * 0x10;
1214 int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x20 >> GBAObjAttributesAGet256Color(sprite->a));
1215
1216 if (spriteY + height >= 256) {
1217 spriteY -= 256;
1218 }
1219
1220 if (!GBAObjAttributesAIsTransformed(sprite->a) && GBAObjAttributesBIsVFlip(sprite->b)) {
1221 spriteY = (y - height) + (y - spriteY) + 1;
1222 }
1223
1224 int totalWidth = width;
1225 int totalHeight = height;
1226 if (GBAObjAttributesAIsTransformed(sprite->a) && GBAObjAttributesAIsDoubleSize(sprite->a)) {
1227 totalWidth <<= 1;
1228 totalHeight <<= 1;
1229 }
1230
1231 const struct GBAVideoGLShader* shader = &renderer->objShader[GBAObjAttributesAGet256Color(sprite->a)];
1232 const GLuint* uniforms = shader->uniforms;
1233 glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]);
1234 glViewport(x * renderer->scale, spriteY * renderer->scale, totalWidth * renderer->scale, totalHeight * renderer->scale);
1235 glScissor(x * renderer->scale, y * renderer->scale, totalWidth * renderer->scale, renderer->scale);
1236 glUseProgram(shader->program);
1237 glBindVertexArray(shader->vao);
1238 glActiveTexture(GL_TEXTURE0);
1239 glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
1240 glActiveTexture(GL_TEXTURE0 + 1);
1241 glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
1242 glUniform2i(uniforms[GBA_GL_VS_LOC], 1, y - spriteY);
1243 glUniform2i(uniforms[GBA_GL_VS_MAXPOS], (GBAObjAttributesBIsHFlip(sprite->b) && !GBAObjAttributesAIsTransformed(sprite->a)) ? -totalWidth : totalWidth, totalHeight);
1244 glUniform1i(uniforms[GBA_GL_OBJ_VRAM], 0);
1245 glUniform1i(uniforms[GBA_GL_OBJ_PALETTE], 1);
1246 glUniform1i(uniforms[GBA_GL_OBJ_CHARBASE], charBase);
1247 glUniform1i(uniforms[GBA_GL_OBJ_STRIDE], stride);
1248 glUniform1i(uniforms[GBA_GL_OBJ_LOCALPALETTE], GBAObjAttributesCGetPalette(sprite->c));
1249 glUniform4i(uniforms[GBA_GL_OBJ_INFLAGS], GBAObjAttributesCGetPriority(sprite->c) << 3,
1250 (renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) | (renderer->target2Obj * 2) | (renderer->blendEffect * 4),
1251 renderer->blda, GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT);
1252 if (GBAObjAttributesAIsTransformed(sprite->a)) {
1253 struct GBAOAMMatrix mat;
1254 LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a);
1255 LOAD_16(mat.b, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].b);
1256 LOAD_16(mat.c, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].c);
1257 LOAD_16(mat.d, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].d);
1258
1259 glUniformMatrix2fv(uniforms[GBA_GL_OBJ_TRANSFORM], 1, GL_FALSE, (GLfloat[]) { mat.a / 256.f, mat.c / 256.f, mat.b / 256.f, mat.d / 256.f });
1260 } else {
1261 glUniformMatrix2fv(uniforms[GBA_GL_OBJ_TRANSFORM], 1, GL_FALSE, (GLfloat[]) { 1.f, 0, 0, 1.f });
1262 }
1263 glUniform4i(uniforms[GBA_GL_OBJ_DIMS], width, height, totalWidth, totalHeight);
1264 if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_OBJWIN) {
1265 int window = ~renderer->objwin & 0x3F;
1266 glUniform4f(uniforms[GBA_GL_OBJ_OBJWIN], 1, window / 128.f, renderer->bldb / 16.f, renderer->bldy / 16.f);
1267 glDrawBuffers(3, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 });
1268 } else {
1269 glUniform4f(uniforms[GBA_GL_OBJ_OBJWIN], 0, 0, 0, 0);
1270 glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
1271 }
1272 glEnableVertexAttribArray(0);
1273 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1274 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1275}
1276
1277void _prepareBackground(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, const GLuint* uniforms) {
1278 glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
1279 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1280 glActiveTexture(GL_TEXTURE0);
1281 glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
1282 glActiveTexture(GL_TEXTURE0 + 1);
1283 glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
1284 glUniform2i(uniforms[GBA_GL_VS_MAXPOS], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1285 glUniform1i(uniforms[GBA_GL_BG_VRAM], 0);
1286 glUniform1i(uniforms[GBA_GL_BG_PALETTE], 1);
1287 glUniform4i(uniforms[GBA_GL_BG_INFLAGS], (background->priority << 3) + (background->index << 1) + 1,
1288 background->target1 | (background->target2 * 2) | (renderer->blendEffect * 4),
1289 renderer->blda, 0);
1290 glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
1291}
1292
1293void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1294 int inY = y + background->y;
1295 int yBase = inY & 0xFF;
1296 if (background->size == 2) {
1297 yBase += inY & 0x100;
1298 } else if (background->size == 3) {
1299 yBase += (inY & 0x100) << 1;
1300 }
1301
1302 const struct GBAVideoGLShader* shader = &renderer->bgShader[background->multipalette ? 1 : 0];
1303 const GLuint* uniforms = shader->uniforms;
1304 glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale);
1305 glUseProgram(shader->program);
1306 glBindVertexArray(shader->vao);
1307 _prepareBackground(renderer, background, uniforms);
1308 glUniform2i(uniforms[GBA_GL_VS_LOC], 1, y);
1309 glUniform1i(uniforms[GBA_GL_BG_SCREENBASE], background->screenBase);
1310 glUniform1i(uniforms[GBA_GL_BG_CHARBASE], background->charBase);
1311 glUniform1i(uniforms[GBA_GL_BG_SIZE], background->size);
1312 glUniform2i(uniforms[GBA_GL_BG_OFFSET], background->x, yBase - y);
1313 glEnableVertexAttribArray(0);
1314 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1315 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1316}
1317
1318void _prepareTransform(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, const GLuint* uniforms, int y) {
1319 int reverse = 0;
1320 int forward = 1;
1321 if (renderer->scale > 1) {
1322 switch (y - renderer->firstAffine) {
1323 case 0:
1324 case 1:
1325 case 2:
1326 case 3:
1327 return;
1328 case 4:
1329 forward = 2;
1330 reverse = 4;
1331 break;
1332 case 5:
1333 forward = 2;
1334 reverse = 3;
1335 break;
1336 case 6:
1337 forward = 2;
1338 reverse = 2;
1339 break;
1340 case 7:
1341 forward = 2;
1342 reverse = 1;
1343 break;
1344 }
1345 }
1346
1347 glScissor(0, (y - reverse) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale * forward);
1348 glUniform2i(uniforms[GBA_GL_VS_LOC], forward, y - reverse);
1349 glUniform2f(uniforms[GBA_GL_BG_RANGE], y - 1, 1);
1350 if (renderer->scale > 1) {
1351 glUniform2iv(uniforms[GBA_GL_BG_OFFSET], 4, (GLint[]) {
1352 background->affine[0].sx, background->affine[0].sy,
1353 background->affine[1].sx, background->affine[1].sy,
1354 background->affine[2].sx, background->affine[2].sy,
1355 background->affine[3].sx, background->affine[3].sy,
1356 });
1357 glUniform2iv(uniforms[GBA_GL_BG_TRANSFORM], 4, (GLint[]) {
1358 background->affine[0].dx, background->affine[0].dy,
1359 background->affine[1].dx, background->affine[1].dy,
1360 background->affine[2].dx, background->affine[2].dy,
1361 background->affine[3].dx, background->affine[3].dy,
1362 });
1363 } else {
1364 glUniform2iv(uniforms[GBA_GL_BG_OFFSET], 4, (GLint[]) {
1365 background->affine[0].sx, background->affine[0].sy,
1366 background->affine[0].sx, background->affine[0].sy,
1367 background->affine[0].sx, background->affine[0].sy,
1368 background->affine[0].sx, background->affine[0].sy,
1369 });
1370 glUniform2iv(uniforms[GBA_GL_BG_TRANSFORM], 4, (GLint[]) {
1371 background->affine[0].dx, background->affine[0].dy,
1372 background->affine[0].dx, background->affine[0].dy,
1373 background->affine[0].dx, background->affine[0].dy,
1374 background->affine[0].dx, background->affine[0].dy,
1375 });
1376 }
1377 _prepareBackground(renderer, background, uniforms);
1378}
1379
1380void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1381 const struct GBAVideoGLShader* shader = &renderer->bgShader[background->overflow ? 2 : 3];
1382 const GLuint* uniforms = shader->uniforms;
1383 glUseProgram(shader->program);
1384 glBindVertexArray(shader->vao);
1385 _prepareTransform(renderer, background, uniforms, y);
1386 glUniform1i(uniforms[GBA_GL_BG_SCREENBASE], background->screenBase);
1387 glUniform1i(uniforms[GBA_GL_BG_CHARBASE], background->charBase);
1388 glUniform1i(uniforms[GBA_GL_BG_SIZE], background->size);
1389 glEnableVertexAttribArray(0);
1390 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1391 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1392}
1393
1394void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1395 const struct GBAVideoGLShader* shader = &renderer->bgShader[5];
1396 const GLuint* uniforms = shader->uniforms;
1397 glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
1398 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1399 glUseProgram(shader->program);
1400 glBindVertexArray(shader->vao);
1401 _prepareTransform(renderer, background, uniforms, y);
1402 glUniform1i(uniforms[GBA_GL_BG_CHARBASE], 0);
1403 glUniform2i(uniforms[GBA_GL_BG_SIZE], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1404 glEnableVertexAttribArray(0);
1405 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1406 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1407}
1408
1409void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1410 const struct GBAVideoGLShader* shader = &renderer->bgShader[4];
1411 const GLuint* uniforms = shader->uniforms;
1412 glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
1413 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1414 glUseProgram(shader->program);
1415 glBindVertexArray(shader->vao);
1416 _prepareTransform(renderer, background, uniforms, y);
1417 glUniform1i(uniforms[GBA_GL_BG_CHARBASE], GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt) ? 0xA000 : 0);
1418 glUniform2i(uniforms[GBA_GL_BG_SIZE], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1419 glEnableVertexAttribArray(0);
1420 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1421 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1422}
1423
1424void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1425 const struct GBAVideoGLShader* shader = &renderer->bgShader[5];
1426 const GLuint* uniforms = shader->uniforms;
1427 glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
1428 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1429 glUseProgram(shader->program);
1430 glBindVertexArray(shader->vao);
1431 _prepareTransform(renderer, background, uniforms, y);
1432 glUniform1i(uniforms[GBA_GL_BG_CHARBASE], GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt) ? 0x5000 : 0);
1433 glUniform2i(uniforms[GBA_GL_BG_SIZE], 160, 128);
1434 glEnableVertexAttribArray(0);
1435 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1436 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1437}
1438
1439static void _scissorWindow(int start, int end, int y, int lines, int scale) {
1440 if (start > end) {
1441 _scissorWindow(start, GBA_VIDEO_HORIZONTAL_PIXELS * scale, y, lines, scale);
1442 _scissorWindow(0, end, y, lines, scale);
1443 return;
1444 }
1445 glScissor(start, y, end - start, lines);
1446 glClear(GL_COLOR_BUFFER_BIT);
1447}
1448
1449static void _scissorWindowN(struct GBAVideoWindowRegion* region, int y, int scale) {
1450 int sdelta = region[0].start - region[1].start;
1451 int edelta = region[0].end - region[1].end;
1452 int maxDelta = 0;
1453 if (sdelta > maxDelta) {
1454 maxDelta = sdelta;
1455 } else if (-sdelta > maxDelta) {
1456 maxDelta = -sdelta;
1457 }
1458 if (edelta > maxDelta) {
1459 maxDelta = edelta;
1460 } else if (-edelta > maxDelta) {
1461 maxDelta = -edelta;
1462 }
1463 if (!(sdelta | edelta) || maxDelta >= GBA_VIDEO_VERTICAL_PIXELS / 2) {
1464 _scissorWindow(region[0].start * scale, region[0].end * scale, y, scale, scale);
1465 } else {
1466 int i;
1467 for (i = 0; i < scale; ++i) {
1468 int start = region[1].start * scale + sdelta * i;
1469 int end = region[1].end * scale + edelta * i;
1470 _scissorWindow(start, end, y + i, 1, scale);
1471 }
1472 }
1473}
1474
1475static void _clearWindow(GBAWindowControl window, int bldb, int bldy) {
1476 window = ~window & 0x3F;
1477 glClearColor(window / 128.f, bldb / 16.f, bldy / 16.f, 0);
1478}
1479
1480void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y) {
1481 glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_WINDOW]);
1482 int dispcnt = ((renderer->dispcnt >> 8) & 0x1F) | 0x20;
1483 if (!(renderer->dispcnt & 0xE000)) {
1484 _clearWindow(dispcnt, renderer->bldb, renderer->bldy);
1485 _scissorWindow(0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, y * renderer->scale, renderer->scale, renderer->scale);
1486 } else {
1487 _clearWindow(renderer->winout & dispcnt, renderer->bldb, renderer->bldy);
1488 _scissorWindow(0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, y * renderer->scale, renderer->scale, renderer->scale);
1489 if (GBARegisterDISPCNTIsWin1Enable(renderer->dispcnt) && y >= renderer->winN[1].v.start && y < renderer->winN[1].v.end) {
1490 _clearWindow(renderer->winN[1].control & dispcnt, renderer->bldb, renderer->bldy);
1491 _scissorWindowN(renderer->winN[1].h, y * renderer->scale, renderer->scale);
1492 }
1493 if (GBARegisterDISPCNTIsWin0Enable(renderer->dispcnt) && y >= renderer->winN[0].v.start && y < renderer->winN[0].v.end) {
1494 _clearWindow(renderer->winN[0].control & dispcnt, renderer->bldb, renderer->bldy);
1495 _scissorWindowN(renderer->winN[0].h, y * renderer->scale, renderer->scale);
1496 }
1497 }
1498}
1499
1500#endif