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 static void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer);
17 static void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer);
18 static void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer);
19 static void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
20 static void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
21 static void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
22 static uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
23 static void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
24 static void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer);
25 static void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels);
26 static void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);
27 
28 static void GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer* renderer);
29 static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value);
30 static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value);
31 static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value);
32 static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value);
33 static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value);
34 static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value);
35 
36 static void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY);
37 static void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
38 static void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
39 static void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
40 static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
41 static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
42 static void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y);
43 
44 static void _cleanRegister(struct GBAVideoGLRenderer* renderer, int address, uint16_t value);
45 static void _drawScanlines(struct GBAVideoGLRenderer* renderer, int lastY);
46 static void _finalizeLayers(struct GBAVideoGLRenderer* renderer);
47 
48 #define TEST_LAYER_ENABLED(X) !glRenderer->d.disableBG[X] && glRenderer->bg[X].enabled == 4
49 
50 struct GBAVideoGLUniform {
51 	const char* name;
52 	int type;
53 };
54 
55 #define PALETTE_ENTRY "#define PALETTE_ENTRY(x) (vec3((ivec3(0x1F, 0x3E0, 0x7C00) & (x)) >> ivec3(0, 5, 10)) / 31.)\n"
56 #define MOSAIC \
57 	"#define MOSAIC(LHS, RHS) (((int(LHS) * mosaicTable[RHS]) >> 12) * RHS)\n" \
58 	"const int mosaicTable[17] = int[17](0, 4096, 2048, 1366, 1024, 820, 683, 586, 512, 456, 410, 373, 342, 316, 293, 274, 256);\n"
59 
60 static const GLchar* const _gles3Header =
61 	"#version 300 es\n"
62 	"#define OUT(n) layout(location = n)\n"
63 	PALETTE_ENTRY
64 	"precision highp float;\n"
65 	"precision highp int;\n"
66 	"precision highp sampler2D;\n"
67 	"precision highp isampler2D;\n";
68 
69 static const GLchar* const _gl3Header =
70 	"#version 150 core\n"
71 	"#define OUT(n)\n"
72 	PALETTE_ENTRY
73 	"precision highp float;\n";
74 
75 static const char* const _vertexShader =
76 	"in vec2 position;\n"
77 	"uniform ivec2 loc;\n"
78 	"uniform ivec2 maxPos;\n"
79 	"out vec2 texCoord;\n"
80 
81 	"void main() {\n"
82 	"	vec2 local = vec2(position.x, float(position.y * float(loc.x) + float(loc.y)) / float(maxPos.y));\n"
83 	"	gl_Position = vec4((local * 2. - 1.) * vec2(sign(maxPos)), 0., 1.);\n"
84 	"	texCoord = local * vec2(abs(maxPos));\n"
85 	"}";
86 
87 static const char* const _renderTile16 =
88 	"int renderTile(int tile, int paletteId, ivec2 localCoord) {\n"
89 	"	int address = charBase + tile * 16 + (localCoord.x >> 2) + (localCoord.y << 1);\n"
90 	"	int halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0).r;\n"
91 	"	int entry = (halfrow >> (4 * (localCoord.x & 3))) & 15;\n"
92 	"	if (entry == 0) {\n"
93 	"		discard;\n"
94 	"	}\n"
95 	"	return paletteId * 16 + entry;\n"
96 	"}";
97 
98 static const char* const _renderTile256 =
99 	"int renderTile(int tile, int paletteId, ivec2 localCoord) {\n"
100 	"	int address = charBase + tile * 32 + (localCoord.x >> 1) + (localCoord.y << 2);\n"
101 	"	int halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0).r;\n"
102 	"	int entry = (halfrow >> (8 * (localCoord.x & 1))) & 255;\n"
103 	"	if (entry == 0) {\n"
104 	"		discard;\n"
105 	"	}\n"
106 	"	return entry;\n"
107 	"}";
108 
109 static const struct GBAVideoGLUniform _uniformsMode0[] = {
110 	{ "loc", GBA_GL_VS_LOC, },
111 	{ "maxPos", GBA_GL_VS_MAXPOS, },
112 	{ "vram", GBA_GL_BG_VRAM, },
113 	{ "palette", GBA_GL_BG_PALETTE, },
114 	{ "screenBase", GBA_GL_BG_SCREENBASE, },
115 	{ "charBase", GBA_GL_BG_CHARBASE, },
116 	{ "size", GBA_GL_BG_SIZE, },
117 	{ "offset", GBA_GL_BG_OFFSET, },
118 	{ "mosaic", GBA_GL_BG_MOSAIC, },
119 	{ 0 }
120 };
121 
122 static const char* const _renderMode0 =
123 	MOSAIC
124 	"in vec2 texCoord;\n"
125 	"uniform isampler2D vram;\n"
126 	"uniform sampler2D palette;\n"
127 	"uniform int screenBase;\n"
128 	"uniform int charBase;\n"
129 	"uniform int size;\n"
130 	"uniform int offset[160];\n"
131 	"uniform ivec2 mosaic;\n"
132 	"OUT(0) out vec4 color;\n"
133 
134 	"int renderTile(int tile, int paletteId, ivec2 localCoord);\n"
135 
136 	"void main() {\n"
137 	"	ivec2 coord = ivec2(texCoord);\n"
138 	"	if (mosaic.x > 1) {\n"
139 	"		coord.x = MOSAIC(coord.x, mosaic.x);\n"
140 	"	}\n"
141 	"	if (mosaic.y > 1) {\n"
142 	"		coord.y = MOSAIC(coord.y, mosaic.y);\n"
143 	"	}\n"
144 	"	coord += (ivec2(0x1FF, 0x1FF000) & offset[int(texCoord.y)]) >> ivec2(0, 12);\n"
145 	"	ivec2 wrap = ivec2(255, 255);\n"
146 	"	int doty = 0;\n"
147 	"	if ((size & 1) == 1) {\n"
148 	"		wrap.x = 511;\n"
149 	"		++doty;\n"
150 	"	}\n"
151 	"	if ((size & 2) == 2) {\n"
152 	"		wrap.y = 511;\n"
153 	"		++doty;\n"
154 	"	}\n"
155 	"	coord &= wrap;\n"
156 	"	wrap = coord & 256;\n"
157 	"	coord &= 255;\n"
158 	"	coord.y += wrap.x + wrap.y * doty;\n"
159 	"	int mapAddress = screenBase + (coord.x >> 3) + (coord.y >> 3) * 32;\n"
160 	"	int map = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0).r;\n"
161 	"	if ((map & 1024) == 1024) {\n"
162 	"		coord.x ^= 7;\n"
163 	"	}\n"
164 	"	if ((map & 2048) == 2048) {\n"
165 	"		coord.y ^= 7;\n"
166 	"	}\n"
167 	"	int tile = map & 1023;\n"
168 	"	int paletteEntry = renderTile(tile, map >> 12, coord & 7);\n"
169 	"	color = texelFetch(palette, ivec2(paletteEntry, int(texCoord.y)), 0);\n"
170 	"}";
171 
172 static const char* const _fetchTileOverflow =
173 	"int fetchTile(ivec2 coord) {\n"
174 	"	int sizeAdjusted = (0x8000 << size) - 1;\n"
175 	"	coord &= sizeAdjusted;\n"
176 	"	return renderTile(coord);\n"
177 	"}";
178 
179 static const char* const _fetchTileNoOverflow =
180 	"int fetchTile(ivec2 coord) {\n"
181 	"	int sizeAdjusted = (0x8000 << size) - 1;\n"
182 	"	ivec2 outerCoord = coord & ~sizeAdjusted;\n"
183 	"	if ((outerCoord.x | outerCoord.y) != 0) {\n"
184 	"		discard;\n"
185 	"	}\n"
186 	"	return renderTile(coord);\n"
187 	"}";
188 
189 static const struct GBAVideoGLUniform _uniformsMode2[] = {
190 	{ "loc", GBA_GL_VS_LOC, },
191 	{ "maxPos", GBA_GL_VS_MAXPOS, },
192 	{ "vram", GBA_GL_BG_VRAM, },
193 	{ "palette", GBA_GL_BG_PALETTE, },
194 	{ "screenBase", GBA_GL_BG_SCREENBASE, },
195 	{ "charBase", GBA_GL_BG_CHARBASE, },
196 	{ "size", GBA_GL_BG_SIZE, },
197 	{ "offset", GBA_GL_BG_OFFSET, },
198 	{ "transform", GBA_GL_BG_TRANSFORM, },
199 	{ "range", GBA_GL_BG_RANGE, },
200 	{ "mosaic", GBA_GL_BG_MOSAIC, },
201 	{ 0 }
202 };
203 
204 static const char* const _interpolate =
205 	"vec2 interpolate(ivec2 arr[4], float x) {\n"
206 	"	float x1m = 1. - x;\n"
207 	"	return x1m * x1m * x1m * vec2(arr[0]) +"
208 		" 3. * x1m * x1m * x   * vec2(arr[1]) +"
209 		" 3. * x1m * x   * x   * vec2(arr[2]) +"
210 		"      x   * x   * x   * vec2(arr[3]);\n"
211 	"}\n"
212 
213 	"void loadAffine(int y, out ivec2 mat[4], out ivec2 aff[4]) {\n"
214 	"	int start = max(range.x, y - 3);\n"
215 	"	mat[0] = transform[start + 0].xy;\n"
216 	"	aff[0] = transform[start + 0].zw;\n"
217 	"	mat[1] = transform[start + 1].xy;\n"
218 	"	aff[1] = transform[start + 1].zw;\n"
219 	"	mat[2] = transform[start + 2].xy;\n"
220 	"	aff[2] = transform[start + 2].zw;\n"
221 	"	mat[3] = transform[start + 3].xy;\n"
222 	"	aff[3] = transform[start + 3].zw;\n"
223 	"}\n";
224 
225 static const char* const _renderMode2 =
226 	MOSAIC
227 	"in vec2 texCoord;\n"
228 	"uniform isampler2D vram;\n"
229 	"uniform sampler2D palette;\n"
230 	"uniform int screenBase;\n"
231 	"uniform int charBase;\n"
232 	"uniform int size;\n"
233 	"uniform ivec4 transform[160];\n"
234 	"uniform ivec2 range;\n"
235 	"uniform ivec2 mosaic;\n"
236 	"OUT(0) out vec4 color;\n"
237 
238 	"int fetchTile(ivec2 coord);\n"
239 	"vec2 interpolate(ivec2 arr[4], float x);\n"
240 	"void loadAffine(int y, out ivec2 mat[4], out ivec2 aff[4]);\n"
241 
242 	"int renderTile(ivec2 coord) {\n"
243 	"	int map = (coord.x >> 11) + (((coord.y >> 7) & 0x7F0) << size);\n"
244 	"	int mapAddress = screenBase + (map >> 1);\n"
245 	"	int twomaps = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0).r;\n"
246 	"	int tile = (twomaps >> (8 * (map & 1))) & 255;\n"
247 	"	int address = charBase + tile * 32 + ((coord.x >> 9) & 3) + ((coord.y >> 6) & 0x1C);\n"
248 	"	int halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0).r;\n"
249 	"	int entry = (halfrow >> (8 * ((coord.x >> 8) & 1))) & 255;\n"
250 	"	if (entry == 0) {\n"
251 	"		discard;\n"
252 	"	}\n"
253 	"	return entry;\n"
254 	"}\n"
255 
256 	"void main() {\n"
257 	"	ivec2 mat[4];\n"
258 	"	ivec2 offset[4];\n"
259 	"	vec2 incoord = texCoord;\n"
260 	"	if (mosaic.x > 1) {\n"
261 	"		incoord.x = float(MOSAIC(incoord.x, mosaic.x));\n"
262 	"	}\n"
263 	"	if (mosaic.y > 1) {\n"
264 	"		incoord.y = float(MOSAIC(incoord.y, mosaic.y));\n"
265 	"	}\n"
266 	"	loadAffine(int(incoord.y), mat, offset);\n"
267 	"	float y = fract(incoord.y);\n"
268 	"	float start = 0.75;\n"
269 	"	if (int(incoord.y) - range.x < 4) {\n"
270 	"		y = incoord.y - float(range.x);\n"
271 	"		start = 0.;\n"
272 	"	}\n"
273 	"	float lin = start + y * 0.25;\n"
274 	"	vec2 mixedTransform = interpolate(mat, lin);\n"
275 	"	vec2 mixedOffset = interpolate(offset, lin);\n"
276 	"	int paletteEntry = fetchTile(ivec2(mixedTransform * incoord.x + mixedOffset));\n"
277 	"	color = texelFetch(palette, ivec2(paletteEntry, int(texCoord.y)), 0);\n"
278 	"}";
279 
280 static const struct GBAVideoGLUniform _uniformsMode35[] = {
281 	{ "loc", GBA_GL_VS_LOC, },
282 	{ "maxPos", GBA_GL_VS_MAXPOS, },
283 	{ "vram", GBA_GL_BG_VRAM, },
284 	{ "charBase", GBA_GL_BG_CHARBASE, },
285 	{ "size", GBA_GL_BG_SIZE, },
286 	{ "offset", GBA_GL_BG_OFFSET, },
287 	{ "transform", GBA_GL_BG_TRANSFORM, },
288 	{ "range", GBA_GL_BG_RANGE, },
289 	{ "mosaic", GBA_GL_BG_MOSAIC, },
290 	{ 0 }
291 };
292 
293 static const char* const _renderMode35 =
294 	MOSAIC
295 	"in vec2 texCoord;\n"
296 	"uniform isampler2D vram;\n"
297 	"uniform int charBase;\n"
298 	"uniform ivec2 size;\n"
299 	"uniform ivec4 transform[160];\n"
300 	"uniform ivec2 range;\n"
301 	"uniform ivec2 mosaic;\n"
302 	"OUT(0) out vec4 color;\n"
303 
304 	"vec2 interpolate(ivec2 arr[4], float x);\n"
305 	"void loadAffine(int y, out ivec2 mat[4], out ivec2 aff[4]);\n"
306 
307 	"void main() {\n"
308 	"	ivec2 mat[4];\n"
309 	"	ivec2 offset[4];\n"
310 	"	vec2 incoord = texCoord;\n"
311 	"	if (mosaic.x > 1) {\n"
312 	"		incoord.x = float(MOSAIC(incoord.x, mosaic.x));\n"
313 	"	}\n"
314 	"	if (mosaic.y > 1) {\n"
315 	"		incoord.y = float(MOSAIC(incoord.y, mosaic.y));\n"
316 	"	}\n"
317 	"	loadAffine(int(incoord.y), mat, offset);\n"
318 	"	float y = fract(incoord.y);\n"
319 	"	float start = 0.75;\n"
320 	"	if (int(incoord.y) - range.x < 4) {\n"
321 	"		y = incoord.y - float(range.x);\n"
322 	"		start = 0.;\n"
323 	"	}\n"
324 	"	float lin = start + y * 0.25;\n"
325 	"	vec2 mixedTransform = interpolate(mat, lin);\n"
326 	"	vec2 mixedOffset = interpolate(offset, lin);\n"
327 	"	ivec2 coord = ivec2(mixedTransform * incoord.x + mixedOffset);\n"
328 	"	if (coord.x < 0 || coord.x >= (size.x << 8)) {\n"
329 	"		discard;\n"
330 	"	}\n"
331 	"	if (coord.y < 0 || coord.y >= (size.y << 8)) {\n"
332 	"		discard;\n"
333 	"	}\n"
334 	"	int address = charBase + (coord.x >> 8) + (coord.y >> 8) * size.x;\n"
335 	"	int entry = texelFetch(vram, ivec2(address & 255, address >> 8), 0).r;\n"
336 	"	color = vec4(float(entry & 0x1F) / 31., float((entry >> 5) & 0x1F) / 31., float((entry >> 10) & 0x1F) / 31., 1.);\n"
337 	"}";
338 
339 static const struct GBAVideoGLUniform _uniformsMode4[] = {
340 	{ "loc", GBA_GL_VS_LOC, },
341 	{ "maxPos", GBA_GL_VS_MAXPOS, },
342 	{ "vram", GBA_GL_BG_VRAM, },
343 	{ "palette", GBA_GL_BG_PALETTE, },
344 	{ "charBase", GBA_GL_BG_CHARBASE, },
345 	{ "size", GBA_GL_BG_SIZE, },
346 	{ "offset", GBA_GL_BG_OFFSET, },
347 	{ "transform", GBA_GL_BG_TRANSFORM, },
348 	{ "range", GBA_GL_BG_RANGE, },
349 	{ "mosaic", GBA_GL_BG_MOSAIC, },
350 	{ 0 }
351 };
352 
353 static const char* const _renderMode4 =
354 	MOSAIC
355 	"in vec2 texCoord;\n"
356 	"uniform isampler2D vram;\n"
357 	"uniform sampler2D palette;\n"
358 	"uniform int charBase;\n"
359 	"uniform ivec2 size;\n"
360 	"uniform ivec4 transform[160];\n"
361 	"uniform ivec2 range;\n"
362 	"uniform ivec2 mosaic;\n"
363 	"OUT(0) out vec4 color;\n"
364 
365 	"vec2 interpolate(ivec2 arr[4], float x);\n"
366 	"void loadAffine(int y, out ivec2 mat[4], out ivec2 aff[4]);\n"
367 
368 	"void main() {\n"
369 	"	ivec2 mat[4];\n"
370 	"	ivec2 offset[4];\n"
371 	"	vec2 incoord = texCoord;\n"
372 	"	if (mosaic.x > 1) {\n"
373 	"		incoord.x = float(MOSAIC(incoord.x, mosaic.x));\n"
374 	"	}\n"
375 	"	if (mosaic.y > 1) {\n"
376 	"		incoord.y = float(MOSAIC(incoord.y, mosaic.y));\n"
377 	"	}\n"
378 	"	loadAffine(int(incoord.y), mat, offset);\n"
379 	"	float y = fract(incoord.y);\n"
380 	"	float start = 0.75;\n"
381 	"	if (int(incoord.y) - range.x < 4) {\n"
382 	"		y = incoord.y - float(range.x);\n"
383 	"		start = 0.;\n"
384 	"	}\n"
385 	"	float lin = start + y * 0.25;\n"
386 	"	vec2 mixedTransform = interpolate(mat, lin);\n"
387 	"	vec2 mixedOffset = interpolate(offset, lin);\n"
388 	"	ivec2 coord = ivec2(mixedTransform * incoord.x + mixedOffset);\n"
389 	"	if (coord.x < 0 || coord.x >= (size.x << 8)) {\n"
390 	"		discard;\n"
391 	"	}\n"
392 	"	if (coord.y < 0 || coord.y >= (size.y << 8)) {\n"
393 	"		discard;\n"
394 	"	}\n"
395 	"	int address = charBase + (coord.x >> 8) + (coord.y >> 8) * size.x;\n"
396 	"	int twoEntries = texelFetch(vram, ivec2((address >> 1) & 255, address >> 9), 0).r;\n"
397 	"	int entry = (twoEntries >> (8 * (address & 1))) & 255;\n"
398 	"	if (entry == 0) {\n"
399 	"		discard;\n"
400 	"	}\n"
401 	"	color = texelFetch(palette, ivec2(entry, int(texCoord.y)), 0);\n"
402 	"}";
403 
404 static const struct GBAVideoGLUniform _uniformsObj[] = {
405 	{ "loc", GBA_GL_VS_LOC, },
406 	{ "maxPos", GBA_GL_VS_MAXPOS, },
407 	{ "vram", GBA_GL_OBJ_VRAM, },
408 	{ "palette", GBA_GL_OBJ_PALETTE, },
409 	{ "charBase", GBA_GL_OBJ_CHARBASE, },
410 	{ "stride", GBA_GL_OBJ_STRIDE, },
411 	{ "localPalette", GBA_GL_OBJ_LOCALPALETTE, },
412 	{ "inflags", GBA_GL_OBJ_INFLAGS, },
413 	{ "transform", GBA_GL_OBJ_TRANSFORM, },
414 	{ "dims", GBA_GL_OBJ_DIMS, },
415 	{ "objwin", GBA_GL_OBJ_OBJWIN, },
416 	{ "mosaic", GBA_GL_OBJ_MOSAIC, },
417 	{ "cyclesRemaining", GBA_GL_OBJ_CYCLES, },
418 	{ 0 }
419 };
420 
421 static const char* const _renderObj =
422 	MOSAIC
423 	"in vec2 texCoord;\n"
424 	"uniform isampler2D vram;\n"
425 	"uniform sampler2D palette;\n"
426 	"uniform int charBase;\n"
427 	"uniform int stride;\n"
428 	"uniform int localPalette;\n"
429 	"uniform ivec4 inflags;\n"
430 	"uniform mat2x2 transform;\n"
431 	"uniform ivec4 dims;\n"
432 	"uniform ivec3 objwin;\n"
433 	"uniform ivec4 mosaic;\n"
434 	"uniform int cyclesRemaining[160];\n"
435 	"OUT(0) out vec4 color;\n"
436 	"OUT(1) out ivec4 flags;\n"
437 	"OUT(2) out ivec4 window;\n"
438 
439 	"int renderTile(int tile, int paletteId, ivec2 localCoord);\n"
440 
441 	"void main() {\n"
442 	"	vec2 incoord = texCoord;\n"
443 	"	if (mosaic.x > 1) {\n"
444 	"		int x = int(incoord.x);\n"
445 	"		x = MOSAIC(mosaic.z + x, mosaic.x) - mosaic.z;\n"
446 	"		incoord.x = float(clamp(x, 0, dims.z - 1));\n"
447 	"	} else if (mosaic.x < -1) {\n"
448 	"		int x = dims.z - int(incoord.x) - 1;\n"
449 	"		x = dims.z - MOSAIC(mosaic.z + x, -mosaic.x) + mosaic.z - 1;\n"
450 	"		incoord.x = float(clamp(x, 0, dims.z - 1));\n"
451 	"	}\n"
452 	"	if (cyclesRemaining[int(incoord.y) + mosaic.w] <= 0) {\n"
453 	"		discard;\n"
454 	"	}\n"
455 	"	if (mosaic.y > 1) {\n"
456 	"		int y = int(incoord.y);\n"
457 	"		y = MOSAIC(mosaic.w + y, mosaic.y) - mosaic.w;"
458 	"		incoord.y = float(clamp(y, 0, dims.w - 1));\n"
459 	"	}\n"
460 	"	ivec2 coord = ivec2(transform * (incoord - vec2(dims.zw) / 2.) + vec2(dims.xy) / 2.);\n"
461 	"	if ((coord & ~(dims.xy - 1)) != ivec2(0, 0)) {\n"
462 	"		discard;\n"
463 	"	}\n"
464 	"	int paletteEntry = renderTile((coord.x >> 3) + (coord.y >> 3) * stride, localPalette, coord & 7);\n"
465 	"	color = texelFetch(palette, ivec2(paletteEntry + 256, coord.y), 0);\n"
466 	"	flags = inflags;\n"
467 	"	gl_FragDepth = float(flags.x) / 16.;\n"
468 	"	window = ivec4(objwin, 0);\n"
469 	"}";
470 
471 static const struct GBAVideoGLUniform _uniformsObjPriority[] = {
472 	{ "loc", GBA_GL_VS_LOC, },
473 	{ "maxPos", GBA_GL_VS_MAXPOS, },
474 	{ "inflags", GBA_GL_OBJ_INFLAGS, },
475 	{ 0 }
476 };
477 
478 static const char* const _renderObjPriority =
479 	"in vec2 texCoord;\n"
480 	"uniform ivec4 inflags;\n"
481 	"OUT(0) out vec4 color;\n"
482 	"OUT(1) out ivec4 flags;\n"
483 
484 	"void main() {\n"
485 	"	flags = inflags;\n"
486 	"	gl_FragDepth = float(flags.x) / 16.;\n"
487 	"	color = vec4(0., 0., 0., 0.);"
488 	"}";
489 
490 static const struct GBAVideoGLUniform _uniformsWindow[] = {
491 	{ "loc", GBA_GL_VS_LOC, },
492 	{ "maxPos", GBA_GL_VS_MAXPOS, },
493 	{ "dispcnt", GBA_GL_WIN_DISPCNT, },
494 	{ "blend", GBA_GL_WIN_BLEND, },
495 	{ "flags", GBA_GL_WIN_FLAGS, },
496 	{ "win0", GBA_GL_WIN_WIN0, },
497 	{ "win1", GBA_GL_WIN_WIN1, },
498 	{ 0 }
499 };
500 
501 static const char* const _renderWindow =
502 	"in vec2 texCoord;\n"
503 	"uniform int dispcnt;\n"
504 	"uniform ivec2 blend;\n"
505 	"uniform ivec3 flags;\n"
506 	"uniform ivec4 win0[160];\n"
507 	"uniform ivec4 win1[160];\n"
508 	"OUT(0) out ivec4 window;\n"
509 
510 	"bool crop(vec4 windowParams) {\n"
511 	"	bvec4 compare = lessThan(texCoord.xxyy, windowParams);\n"
512 	"	compare = equal(compare, bvec4(true, false, true, false));\n"
513 	"	if (any(compare)) {\n"
514 	"		vec2 h = windowParams.xy;\n"
515 	"		vec2 v = windowParams.zw;\n"
516 	"		if (v.x > v.y) {\n"
517 	"			if (compare.z && compare.w) {\n"
518 	"				return false;\n"
519 	"			}\n"
520 	"		} else if (compare.z || compare.w) {\n"
521 	"			return false;\n"
522 	"		}\n"
523 	"		if (h.x > h.y) {\n"
524 	"			if (compare.x && compare.y) {\n"
525 	"				return false;\n"
526 	"			}\n"
527 	"		} else if (compare.x || compare.y) {\n"
528 	"			return false;\n"
529 	"		}\n"
530 	"	}\n"
531 	"	return true;\n"
532 	"}\n"
533 
534 	"vec4 interpolate(vec4 top, vec4 bottom) {\n"
535 	"	if (distance(top, bottom) > 40.) {\n"
536 	"		return top;\n"
537 	"	}\n"
538 	"	return vec4(mix(bottom.xy, top.xy, fract(texCoord.y)), top.zw);\n"
539 	"}\n"
540 
541 	"void main() {\n"
542 	"	ivec4 windowFlags = ivec4(flags.z, blend, 0);\n"
543 	"	int top = int(texCoord.y);\n"
544 	"	int bottom = max(top - 1, 0);\n"
545 	"	if ((dispcnt & 0x20) != 0 && crop(interpolate(vec4(win0[top]), vec4(win0[bottom])))) { \n"
546 	"		windowFlags.x = flags.x;\n"
547 	"	} else if ((dispcnt & 0x40) != 0 && crop(interpolate(vec4(win1[top]), vec4(win1[bottom])))) {\n"
548 	"		windowFlags.x = flags.y;\n"
549 	"	}\n"
550 	"	window = windowFlags;\n"
551 	"}\n";
552 
553 static const struct GBAVideoGLUniform _uniformsFinalize[] = {
554 	{ "loc", GBA_GL_VS_LOC, },
555 	{ "maxPos", GBA_GL_VS_MAXPOS, },
556 	{ "scale", GBA_GL_FINALIZE_SCALE, },
557 	{ "layers", GBA_GL_FINALIZE_LAYERS, },
558 	{ "objFlags", GBA_GL_FINALIZE_FLAGS, },
559 	{ "window", GBA_GL_FINALIZE_WINDOW, },
560 	{ "palette", GBA_GL_FINALIZE_PALETTE, },
561 	{ "backdropFlags", GBA_GL_FINALIZE_BACKDROP, },
562 	{ 0 }
563 };
564 
565 static const char* const _finalize =
566 	"in vec2 texCoord;\n"
567 	"uniform int scale;\n"
568 	"uniform sampler2D layers[5];\n"
569 	"uniform isampler2D objFlags;\n"
570 	"uniform isampler2D window;\n"
571 	"uniform sampler2D palette;\n"
572 	"uniform isampler2D backdropFlags;\n"
573 	"out vec4 color;\n"
574 
575 	"void composite(vec4 pixel, ivec4 flags, inout vec4 topPixel, inout ivec4 topFlags, inout vec4 bottomPixel, inout ivec4 bottomFlags) {\n"
576 	"	if (flags.x >= topFlags.x) {\n"
577 	"		if (flags.x >= bottomFlags.x) {\n"
578 	"			return;\n"
579 	"		}\n"
580 	"		bottomFlags = flags;\n"
581 	"		bottomPixel = pixel;\n"
582 	"	} else {\n"
583 	"		bottomFlags = topFlags;\n"
584 	"		topFlags = flags;\n"
585 	"		bottomPixel = topPixel;\n"
586 	"		topPixel = pixel;\n"
587 	"	}\n"
588 	"}\n"
589 
590 	"void main() {\n"
591 	"	vec4 topPixel = texelFetch(palette, ivec2(0, texCoord.y), 0);\n"
592 	"	vec4 bottomPixel = topPixel;\n"
593 	"	ivec4 topFlags = ivec4(texelFetch(backdropFlags, ivec2(0, texCoord.y), 0));\n"
594 	"	ivec4 bottomFlags = topFlags;\n"
595 	"	ivec2 coord = ivec2(texCoord * float(scale));\n"
596 	"	ivec4 windowFlags = texelFetch(window, coord, 0);\n"
597 	"	int layerWindow = windowFlags.x;\n"
598 	"	if ((layerWindow & 16) != 0) {\n"
599 	"		vec4 pix = texelFetch(layers[4], coord, 0);\n"
600 	"		if (pix.a != 0.) {\n"
601 	"			ivec4 inflags = ivec4(texelFetch(objFlags, coord, 0));\n"
602 	"			composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n"
603 	"		}\n"
604 	"	}\n"
605 	"	if ((layerWindow & 1) != 0) {\n"
606 	"		vec4 pix = texelFetch(layers[0], coord, 0);\n"
607 	"		if (pix.a != 0.) {\n"
608 	"			ivec4 inflags = ivec4(texelFetch(backdropFlags, ivec2(1, texCoord.y), 0));\n"
609 	"			composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n"
610 	"		}\n"
611 	"	}\n"
612 	"	if ((layerWindow & 2) != 0) {\n"
613 	"		vec4 pix = texelFetch(layers[1], coord, 0);\n"
614 	"		if (pix.a != 0.) {\n"
615 	"			ivec4 inflags = ivec4(texelFetch(backdropFlags, ivec2(2, texCoord.y), 0));\n"
616 	"			composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n"
617 	"		}\n"
618 	"	}\n"
619 	"	if ((layerWindow & 4) != 0) {\n"
620 	"		vec4 pix = texelFetch(layers[2], coord, 0);\n"
621 	"		if (pix.a != 0.) {\n"
622 	"			ivec4 inflags = ivec4(texelFetch(backdropFlags, ivec2(3, texCoord.y), 0));\n"
623 	"			composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n"
624 	"		}\n"
625 	"	}\n"
626 	"	if ((layerWindow & 8) != 0) {\n"
627 	"		vec4 pix = texelFetch(layers[3], coord, 0);\n"
628 	"		if (pix.a != 0.) {\n"
629 	"			ivec4 inflags = ivec4(texelFetch(backdropFlags, ivec2(4, texCoord.y), 0));\n"
630 	"			composite(pix, inflags, topPixel, topFlags, bottomPixel, bottomFlags);\n"
631 	"		}\n"
632 	"	}\n"
633 	"	if ((layerWindow & 32) == 0) {\n"
634 	"		topFlags.y &= ~1;\n"
635 	"	}\n"
636 	"	if (((topFlags.y & 13) == 5 || topFlags.w > 0) && (bottomFlags.y & 2) == 2) {\n"
637 	"		topPixel.rgb *= float(topFlags.z) / 16.;\n"
638 	"		topPixel.rgb += bottomPixel.rgb * float(windowFlags.y) / 16.;\n"
639 	"	} else if ((topFlags.y & 13) == 9) {\n"
640 	"		topPixel.rgb += (1. - topPixel.rgb) * float(windowFlags.z) / 16.;\n"
641 	"	} else if ((topFlags.y & 13) == 13) {\n"
642 	"		topPixel.rgb -= topPixel.rgb * float(windowFlags.z) / 16.;\n"
643 	"	}\n"
644 	"	color = topPixel;\n"
645 	"}";
646 
647 static const GLint _vertices[] = {
648 	0, 0,
649 	0, 1,
650 	1, 1,
651 	1, 0,
652 };
653 
GBAVideoGLRendererCreate(struct GBAVideoGLRenderer * renderer)654 void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) {
655 	renderer->d.init = GBAVideoGLRendererInit;
656 	renderer->d.reset = GBAVideoGLRendererReset;
657 	renderer->d.deinit = GBAVideoGLRendererDeinit;
658 	renderer->d.writeVideoRegister = GBAVideoGLRendererWriteVideoRegister;
659 	renderer->d.writeVRAM = GBAVideoGLRendererWriteVRAM;
660 	renderer->d.writeOAM = GBAVideoGLRendererWriteOAM;
661 	renderer->d.writePalette = GBAVideoGLRendererWritePalette;
662 	renderer->d.drawScanline = GBAVideoGLRendererDrawScanline;
663 	renderer->d.finishFrame = GBAVideoGLRendererFinishFrame;
664 	renderer->d.getPixels = GBAVideoGLRendererGetPixels;
665 	renderer->d.putPixels = GBAVideoGLRendererPutPixels;
666 
667 	renderer->d.disableBG[0] = false;
668 	renderer->d.disableBG[1] = false;
669 	renderer->d.disableBG[2] = false;
670 	renderer->d.disableBG[3] = false;
671 	renderer->d.disableOBJ = false;
672 
673 	renderer->d.highlightBG[0] = false;
674 	renderer->d.highlightBG[1] = false;
675 	renderer->d.highlightBG[2] = false;
676 	renderer->d.highlightBG[3] = false;
677 	int i;
678 	for (i = 0; i < 128; ++i) {
679 		renderer->d.highlightOBJ[i] = false;
680 	}
681 	renderer->d.highlightColor = M_COLOR_WHITE;
682 	renderer->d.highlightAmount = 0;
683 
684 	renderer->scale = 1;
685 }
686 
_compileShader(struct GBAVideoGLRenderer * glRenderer,struct GBAVideoGLShader * shader,const char ** shaderBuffer,int shaderBufferLines,GLuint vs,const struct GBAVideoGLUniform * uniforms,const char * const * outFrags,char * log)687 static void _compileShader(struct GBAVideoGLRenderer* glRenderer, struct GBAVideoGLShader* shader, const char** shaderBuffer, int shaderBufferLines, GLuint vs, const struct GBAVideoGLUniform* uniforms, const char* const* outFrags, char* log) {
688 	GLuint program = glCreateProgram();
689 	shader->program = program;
690 
691 	GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
692 	glAttachShader(program, vs);
693 	glAttachShader(program, fs);
694 	glShaderSource(fs, shaderBufferLines, shaderBuffer, 0);
695 	glCompileShader(fs);
696 	glGetShaderInfoLog(fs, 2048, 0, log);
697 	if (log[0]) {
698 		mLOG(GBA_VIDEO, ERROR, "Fragment shader compilation failure: %s", log);
699 	}
700 	size_t i;
701 #ifndef BUILD_GLES3
702 	for (i = 0; outFrags[i]; ++i) {
703 		glBindFragDataLocation(program, i, outFrags[i]);
704 	}
705 #else
706 	UNUSED(outFrags);
707 #endif
708 	glLinkProgram(program);
709 	glGetProgramInfoLog(program, 2048, 0, log);
710 	if (log[0]) {
711 		mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log);
712 	}
713 	glDeleteShader(fs);
714 
715 	glGenVertexArrays(1, &shader->vao);
716 	glBindVertexArray(shader->vao);
717 	glBindBuffer(GL_ARRAY_BUFFER, glRenderer->vbo);
718 	GLuint positionLocation = glGetAttribLocation(program, "position");
719 	glEnableVertexAttribArray(positionLocation);
720 	glVertexAttribPointer(positionLocation, 2, GL_INT, GL_FALSE, 0, NULL);
721 
722 	for (i = 0; uniforms[i].name; ++i) {
723 		shader->uniforms[uniforms[i].type] = glGetUniformLocation(program, uniforms[i].name);
724 	}
725 }
726 
_deleteShader(struct GBAVideoGLShader * shader)727 static void _deleteShader(struct GBAVideoGLShader* shader) {
728 	glDeleteProgram(shader->program);
729 	glDeleteVertexArrays(1, &shader->vao);
730 }
731 
_initFramebufferTextureEx(GLuint tex,GLenum internalFormat,GLenum format,GLenum type,GLenum attachment,int scale)732 static void _initFramebufferTextureEx(GLuint tex, GLenum internalFormat, GLenum format, GLenum type, GLenum attachment, int scale) {
733 	glBindTexture(GL_TEXTURE_2D, tex);
734 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
735 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
736 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
737 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
738 	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, scale > 0 ? GBA_VIDEO_HORIZONTAL_PIXELS * scale : 8, GBA_VIDEO_VERTICAL_PIXELS * (scale > 0 ? scale : 1), 0, format, type, 0);
739 	glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex, 0);
740 }
741 
_initFramebufferTexture(GLuint tex,GLenum format,GLenum attachment,int scale)742 static void _initFramebufferTexture(GLuint tex, GLenum format, GLenum attachment, int scale) {
743 	_initFramebufferTextureEx(tex, format, format, GL_UNSIGNED_BYTE, attachment, scale);
744 }
745 
_initFramebuffers(struct GBAVideoGLRenderer * glRenderer)746 static void _initFramebuffers(struct GBAVideoGLRenderer* glRenderer) {
747 	glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
748 	_initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale);
749 	_initFramebufferTextureEx(glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE, GL_COLOR_ATTACHMENT1, glRenderer->scale);
750 	_initFramebufferTextureEx(glRenderer->layers[GBA_GL_TEX_WINDOW], GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE, GL_COLOR_ATTACHMENT2, glRenderer->scale);
751 	_initFramebufferTextureEx(glRenderer->layers[GBA_GL_TEX_OBJ_DEPTH], GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_DEPTH_STENCIL_ATTACHMENT, glRenderer->scale);
752 
753 	glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_BACKDROP]);
754 	_initFramebufferTextureEx(glRenderer->layers[GBA_GL_TEX_BACKDROP], GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE, GL_COLOR_ATTACHMENT0, 0);
755 
756 	glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_WINDOW]);
757 	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_WINDOW], 0);
758 
759 	glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OUTPUT]);
760 	_initFramebufferTexture(glRenderer->outputTex, GL_RGB, GL_COLOR_ATTACHMENT0, glRenderer->scale);
761 
762 	int i;
763 	for (i = 0; i < 4; ++i) {
764 		struct GBAVideoGLBackground* bg = &glRenderer->bg[i];
765 		glBindFramebuffer(GL_FRAMEBUFFER, bg->fbo);
766 		_initFramebufferTexture(bg->tex, GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale);
767 	}
768 	glBindFramebuffer(GL_FRAMEBUFFER, 0);
769 }
770 
GBAVideoGLRendererInit(struct GBAVideoRenderer * renderer)771 void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
772 	struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
773 	glRenderer->temporaryBuffer = NULL;
774 
775 	glGenFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo);
776 	glGenTextures(GBA_GL_TEX_MAX, glRenderer->layers);
777 
778 	glGenTextures(1, &glRenderer->vramTex);
779 	glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex);
780 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
781 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
782 	glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 256, 192, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, 0);
783 
784 	glGenTextures(1, &glRenderer->paletteTex);
785 	glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
786 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
787 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
788 	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
789 
790 	glGenBuffers(1, &glRenderer->vbo);
791 	glBindBuffer(GL_ARRAY_BUFFER, glRenderer->vbo);
792 	glBufferData(GL_ARRAY_BUFFER, sizeof(_vertices), _vertices, GL_STATIC_DRAW);
793 
794 	int i;
795 	for (i = 0; i < 4; ++i) {
796 		struct GBAVideoGLBackground* bg = &glRenderer->bg[i];
797 		bg->index = i;
798 		bg->enabled = 0;
799 		bg->priority = 0;
800 		bg->charBase = 0;
801 		bg->mosaic = 0;
802 		bg->multipalette = 0;
803 		bg->screenBase = 0;
804 		bg->overflow = 0;
805 		bg->size = 0;
806 		bg->target1 = 0;
807 		bg->target2 = 0;
808 		bg->x = 0;
809 		bg->y = 0;
810 		bg->refx = 0;
811 		bg->refy = 0;
812 		bg->affine.dx = 256;
813 		bg->affine.dmx = 0;
814 		bg->affine.dy = 0;
815 		bg->affine.dmy = 256;
816 		bg->affine.sx = 0;
817 		bg->affine.sy = 0;
818 		glGenFramebuffers(1, &bg->fbo);
819 		glGenTextures(1, &bg->tex);
820 	}
821 
822 	_initFramebuffers(glRenderer);
823 
824 	char log[2048];
825 	const GLchar* shaderBuffer[4];
826 	const GLubyte* version = glGetString(GL_VERSION);
827 	if (strncmp((const char*) version, "OpenGL ES ", strlen("OpenGL ES "))) {
828 		shaderBuffer[0] = _gl3Header;
829 	} else {
830 		shaderBuffer[0] = _gles3Header;
831 	}
832 
833 	GLuint vs = glCreateShader(GL_VERTEX_SHADER);
834 	shaderBuffer[1] = _vertexShader;
835 	glShaderSource(vs, 2, shaderBuffer, 0);
836 	glCompileShader(vs);
837 	glGetShaderInfoLog(vs, 2048, 0, log);
838 	if (log[0]) {
839 		mLOG(GBA_VIDEO, ERROR, "Vertex shader compilation failure: %s", log);
840 	}
841 
842 	const char* const noWindow[] = {"color", "flags", NULL};
843 	const char* const window[] = {"color", "flags", "window", NULL};
844 	const char* const onlyWindow[] = {"window", NULL};
845 	const char* const onlyColor[] = {"color", NULL};
846 
847 	shaderBuffer[1] = _renderMode0;
848 
849 	shaderBuffer[2] = _renderTile16;
850 	_compileShader(glRenderer, &glRenderer->bgShader[0], shaderBuffer, 3, vs, _uniformsMode0, noWindow, log);
851 
852 	shaderBuffer[2] = _renderTile256;
853 	_compileShader(glRenderer, &glRenderer->bgShader[1], shaderBuffer, 3, vs, _uniformsMode0, noWindow, log);
854 
855 	shaderBuffer[1] = _renderMode2;
856 	shaderBuffer[2] = _interpolate;
857 
858 	shaderBuffer[3] = _fetchTileOverflow;
859 	_compileShader(glRenderer, &glRenderer->bgShader[2], shaderBuffer, 4, vs, _uniformsMode2, noWindow, log);
860 
861 	shaderBuffer[3] = _fetchTileNoOverflow;
862 	_compileShader(glRenderer, &glRenderer->bgShader[3], shaderBuffer, 4, vs, _uniformsMode2, noWindow, log);
863 
864 	shaderBuffer[1] = _renderMode4;
865 	shaderBuffer[2] = _interpolate;
866 	_compileShader(glRenderer, &glRenderer->bgShader[4], shaderBuffer, 3, vs, _uniformsMode4, noWindow, log);
867 
868 	shaderBuffer[1] = _renderMode35;
869 	shaderBuffer[2] = _interpolate;
870 	_compileShader(glRenderer, &glRenderer->bgShader[5], shaderBuffer, 3, vs, _uniformsMode35, noWindow, log);
871 
872 	shaderBuffer[1] = _renderObj;
873 
874 	shaderBuffer[2] = _renderTile16;
875 	_compileShader(glRenderer, &glRenderer->objShader[0], shaderBuffer, 3, vs, _uniformsObj, window, log);
876 
877 	shaderBuffer[2] = _renderTile256;
878 	_compileShader(glRenderer, &glRenderer->objShader[1], shaderBuffer, 3, vs, _uniformsObj, window, log);
879 
880 	shaderBuffer[1] = _renderObjPriority;
881 	_compileShader(glRenderer, &glRenderer->objShader[2], shaderBuffer, 2, vs, _uniformsObjPriority, noWindow, log);
882 
883 	shaderBuffer[1] = _renderWindow;
884 	_compileShader(glRenderer, &glRenderer->windowShader, shaderBuffer, 2, vs, _uniformsWindow, onlyWindow, log);
885 
886 	shaderBuffer[1] = _finalize;
887 	_compileShader(glRenderer, &glRenderer->finalizeShader, shaderBuffer, 2, vs, _uniformsFinalize, onlyColor, log);
888 
889 	glBindVertexArray(0);
890 	glDeleteShader(vs);
891 
892 	GBAVideoGLRendererReset(renderer);
893 }
894 
GBAVideoGLRendererDeinit(struct GBAVideoRenderer * renderer)895 void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) {
896 	struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
897 	if (glRenderer->temporaryBuffer) {
898 		mappedMemoryFree(glRenderer->temporaryBuffer, GBA_VIDEO_HORIZONTAL_PIXELS * GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale * glRenderer->scale);
899 	}
900 	glDeleteFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo);
901 	glDeleteTextures(GBA_GL_TEX_MAX, glRenderer->layers);
902 	glDeleteTextures(1, &glRenderer->vramTex);
903 	glDeleteTextures(1, &glRenderer->paletteTex);
904 	glDeleteBuffers(1, &glRenderer->vbo);
905 
906 	_deleteShader(&glRenderer->bgShader[0]);
907 	_deleteShader(&glRenderer->bgShader[1]);
908 	_deleteShader(&glRenderer->bgShader[2]);
909 	_deleteShader(&glRenderer->bgShader[3]);
910 	_deleteShader(&glRenderer->objShader[0]);
911 	_deleteShader(&glRenderer->objShader[1]);
912 	_deleteShader(&glRenderer->objShader[2]);
913 	_deleteShader(&glRenderer->finalizeShader);
914 
915 	int i;
916 	for (i = 0; i < 4; ++i) {
917 		struct GBAVideoGLBackground* bg = &glRenderer->bg[i];
918 		glDeleteFramebuffers(1, &bg->fbo);
919 		glDeleteTextures(1, &bg->tex);
920 	}
921 }
922 
GBAVideoGLRendererReset(struct GBAVideoRenderer * renderer)923 void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
924 	struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
925 
926 	glRenderer->oamDirty = true;
927 	glRenderer->paletteDirty = true;
928 	glRenderer->vramDirty = 0xFFFFFF;
929 	glRenderer->firstAffine = -1;
930 	glRenderer->firstY = -1;
931 	glRenderer->dispcnt = 0x0080;
932 	glRenderer->mosaic = 0;
933 	glRenderer->nextPalette = 0;
934 	glRenderer->paletteDirtyScanlines = GBA_VIDEO_VERTICAL_PIXELS;
935 	memset(glRenderer->shadowRegs, 0, sizeof(glRenderer->shadowRegs));
936 	glRenderer->regsDirty = 0xFFFFFFFFFFFEULL;
937 
938 	int i;
939 	for (i = 0; i < 512; ++i) {
940 		int r = M_R5(glRenderer->d.palette[i]);
941 		int g = M_G5(glRenderer->d.palette[i]) << 1;
942 		g |= g >> 5;
943 		int b = M_B5(glRenderer->d.palette[i]);
944 		glRenderer->shadowPalette[0][i] = (r << 11) | (g << 5) | b;
945 	}
946 }
947 
GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer * renderer,uint32_t address)948 void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
949 	struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
950 	glRenderer->vramDirty |= 1 << (address >> 12);
951 }
952 
GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer * renderer,uint32_t oam)953 void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
954 	UNUSED(oam);
955 	struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
956 	glRenderer->oamDirty = true;
957 }
958 
GBAVideoGLRendererWritePalette(struct GBAVideoRenderer * renderer,uint32_t address,uint16_t value)959 void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
960 	struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
961 	UNUSED(address);
962 	UNUSED(value);
963 	glRenderer->paletteDirty = true;
964 	int r = M_R5(value);
965 	int g = M_G5(value) << 1;
966 	g |= g >> 5;
967 	int b = M_B5(value);
968 	glRenderer->paletteDirtyScanlines = GBA_VIDEO_VERTICAL_PIXELS;
969 	glRenderer->shadowPalette[glRenderer->nextPalette][address >> 1] = (r << 11) | (g << 5) | b;
970 }
971 
GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer * renderer,uint32_t address,uint16_t value)972 uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
973 	struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
974 	if (renderer->cache) {
975 		GBAVideoCacheWriteVideoRegister(renderer->cache, address, value);
976 	}
977 
978 	bool dirty = false;
979 	switch (address) {
980 	case REG_DISPCNT:
981 		value &= 0xFFF7;
982 		dirty = true;
983 		break;
984 	case REG_BG0CNT:
985 	case REG_BG1CNT:
986 		value &= 0xDFFF;
987 		dirty = true;
988 		break;
989 	case REG_BG0HOFS:
990 		value &= 0x01FF;
991 		glRenderer->bg[0].x = value;
992 		dirty = false;
993 		break;
994 	case REG_BG0VOFS:
995 		value &= 0x01FF;
996 		glRenderer->bg[0].y = value;
997 		dirty = false;
998 		break;
999 	case REG_BG1HOFS:
1000 		value &= 0x01FF;
1001 		glRenderer->bg[1].x = value;
1002 		dirty = false;
1003 		break;
1004 	case REG_BG1VOFS:
1005 		value &= 0x01FF;
1006 		glRenderer->bg[1].y = value;
1007 		dirty = false;
1008 		break;
1009 	case REG_BG2HOFS:
1010 		value &= 0x01FF;
1011 		glRenderer->bg[2].x = value;
1012 		dirty = false;
1013 		break;
1014 	case REG_BG2VOFS:
1015 		value &= 0x01FF;
1016 		glRenderer->bg[2].y = value;
1017 		dirty = false;
1018 		break;
1019 	case REG_BG3HOFS:
1020 		value &= 0x01FF;
1021 		glRenderer->bg[3].x = value;
1022 		dirty = false;
1023 		break;
1024 	case REG_BG3VOFS:
1025 		value &= 0x01FF;
1026 		glRenderer->bg[3].y = value;
1027 		dirty = false;
1028 		break;
1029 	case REG_BG2PA:
1030 		glRenderer->bg[2].affine.dx = value;
1031 		break;
1032 	case REG_BG2PB:
1033 		glRenderer->bg[2].affine.dmx = value;
1034 		break;
1035 	case REG_BG2PC:
1036 		glRenderer->bg[2].affine.dy = value;
1037 		break;
1038 	case REG_BG2PD:
1039 		glRenderer->bg[2].affine.dmy = value;
1040 		break;
1041 	case REG_BG2X_LO:
1042 		GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value);
1043 		break;
1044 	case REG_BG2X_HI:
1045 		GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[2], value);
1046 		break;
1047 	case REG_BG2Y_LO:
1048 		GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[2], value);
1049 		break;
1050 	case REG_BG2Y_HI:
1051 		GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value);
1052 		break;
1053 	case REG_BG3PA:
1054 		glRenderer->bg[3].affine.dx = value;
1055 		break;
1056 	case REG_BG3PB:
1057 		glRenderer->bg[3].affine.dmx = value;
1058 		break;
1059 	case REG_BG3PC:
1060 		glRenderer->bg[3].affine.dy = value;
1061 		break;
1062 	case REG_BG3PD:
1063 		glRenderer->bg[3].affine.dmy = value;
1064 		break;
1065 	case REG_BG3X_LO:
1066 		GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value);
1067 		break;
1068 	case REG_BG3X_HI:
1069 		GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[3], value);
1070 		break;
1071 	case REG_BG3Y_LO:
1072 		GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[3], value);
1073 		break;
1074 	case REG_BG3Y_HI:
1075 		GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[3], value);
1076 		break;
1077 	case REG_BLDALPHA:
1078 		value &= 0x1F1F;
1079 		dirty = true;
1080 		break;
1081 	case REG_BLDY:
1082 		value &= 0x1F;
1083 		if (value > 0x10) {
1084 			value = 0x10;
1085 		}
1086 		dirty = true;
1087 		break;
1088 			case REG_WIN0H:
1089 		glRenderer->winN[0].h.end = value;
1090 		glRenderer->winN[0].h.start = value >> 8;
1091 		if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[0].h.start > glRenderer->winN[0].h.end) {
1092 			glRenderer->winN[0].h.start = 0;
1093 		}
1094 		if (glRenderer->winN[0].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) {
1095 			glRenderer->winN[0].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;
1096 			if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) {
1097 				glRenderer->winN[0].h.start = GBA_VIDEO_HORIZONTAL_PIXELS;
1098 			}
1099 		}
1100 		break;
1101 	case REG_WIN1H:
1102 		glRenderer->winN[1].h.end = value;
1103 		glRenderer->winN[1].h.start = value >> 8;
1104 		if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[1].h.start > glRenderer->winN[1].h.end) {
1105 			glRenderer->winN[1].h.start = 0;
1106 		}
1107 		if (glRenderer->winN[1].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) {
1108 			glRenderer->winN[1].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;
1109 			if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) {
1110 				glRenderer->winN[1].h.start = GBA_VIDEO_HORIZONTAL_PIXELS;
1111 			}
1112 		}
1113 		break;
1114 	case REG_WIN0V:
1115 		glRenderer->winN[0].v.end = value;
1116 		glRenderer->winN[0].v.start = value >> 8;
1117 		if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[0].v.start > glRenderer->winN[0].v.end) {
1118 			glRenderer->winN[0].v.start = 0;
1119 		}
1120 		if (glRenderer->winN[0].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
1121 			glRenderer->winN[0].v.end = GBA_VIDEO_VERTICAL_PIXELS;
1122 			if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
1123 				glRenderer->winN[0].v.start = GBA_VIDEO_VERTICAL_PIXELS;
1124 			}
1125 		}
1126 		break;
1127 	case REG_WIN1V:
1128 		glRenderer->winN[1].v.end = value;
1129 		glRenderer->winN[1].v.start = value >> 8;
1130 		if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[1].v.start > glRenderer->winN[1].v.end) {
1131 			glRenderer->winN[1].v.start = 0;
1132 		}
1133 		if (glRenderer->winN[1].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
1134 			glRenderer->winN[1].v.end = GBA_VIDEO_VERTICAL_PIXELS;
1135 			if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
1136 				glRenderer->winN[1].v.start = GBA_VIDEO_VERTICAL_PIXELS;
1137 			}
1138 		}
1139 		break;
1140 	case REG_WININ:
1141 	case REG_WINOUT:
1142 		value &= 0x3F3F;
1143 		dirty = true;
1144 		break;
1145 	default:
1146 		dirty = true;
1147 		break;
1148 	}
1149 	if (glRenderer->shadowRegs[address >> 1] == value) {
1150 		dirty = false;
1151 	} else {
1152 		glRenderer->shadowRegs[address >> 1] = value;
1153 	}
1154 	if (dirty) {
1155 		glRenderer->regsDirty |= 1ULL << (address >> 1);
1156 	}
1157 	return value;
1158 }
1159 
_cleanRegister(struct GBAVideoGLRenderer * glRenderer,int address,uint16_t value)1160 void _cleanRegister(struct GBAVideoGLRenderer* glRenderer, int address, uint16_t value) {
1161 	switch (address) {
1162 	case REG_DISPCNT:
1163 		glRenderer->dispcnt = value;
1164 		GBAVideoGLRendererUpdateDISPCNT(glRenderer);
1165 		break;
1166 	case REG_BG0CNT:
1167 		GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[0], value);
1168 		break;
1169 	case REG_BG1CNT:
1170 		GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[1], value);
1171 		break;
1172 	case REG_BG2CNT:
1173 		GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[2], value);
1174 		break;
1175 	case REG_BG3CNT:
1176 		GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[3], value);
1177 		break;
1178 	case REG_BLDCNT:
1179 		GBAVideoGLRendererWriteBLDCNT(glRenderer, value);
1180 		break;
1181 	case REG_BLDALPHA:
1182 		glRenderer->blda = value & 0x1F;
1183 		if (glRenderer->blda > 0x10) {
1184 			glRenderer->blda = 0x10;
1185 		}
1186 		glRenderer->bldb = (value >> 8) & 0x1F;
1187 		if (glRenderer->bldb > 0x10) {
1188 			glRenderer->bldb = 0x10;
1189 		}
1190 		break;
1191 	case REG_BLDY:
1192 		glRenderer->bldy = value;
1193 		break;
1194 	case REG_WININ:
1195 		glRenderer->winN[0].control = value;
1196 		glRenderer->winN[1].control = value >> 8;
1197 		break;
1198 	case REG_WINOUT:
1199 		glRenderer->winout = value;
1200 		glRenderer->objwin = value >> 8;
1201 		break;
1202 	case REG_MOSAIC:
1203 		glRenderer->mosaic = value;
1204 		break;
1205 	default:
1206 		break;
1207 	}
1208 }
1209 
_dirtyMode0(struct GBAVideoGLRenderer * renderer,struct GBAVideoGLBackground * background,int y)1210 static bool _dirtyMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1211 	UNUSED(y);
1212 	if (!background->enabled) {
1213 		return false;
1214 	}
1215 	unsigned screenBase = background->screenBase >> 11; // Lops off one extra bit
1216 	unsigned screenMask = (7 << screenBase) & 0xFFFF; // Technically overzealous
1217 	if (renderer->vramDirty & screenMask) {
1218 		return true;
1219 	}
1220 	unsigned charBase = background->charBase >> 11;
1221 	unsigned charMask = (0xFFFF << charBase) & 0xFFFF;
1222 	if (renderer->vramDirty & charMask) {
1223 		return true;
1224 	}
1225 	return false;
1226 }
1227 
_dirtyMode2(struct GBAVideoGLRenderer * renderer,struct GBAVideoGLBackground * background,int y)1228 static bool _dirtyMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1229 	UNUSED(y);
1230 	if (!background->enabled) {
1231 		return false;
1232 	}
1233 	unsigned screenBase = background->screenBase >> 11; // Lops off one extra bit
1234 	unsigned screenMask = (0xF << screenBase) & 0xFFFF;
1235 	if (renderer->vramDirty & screenMask) {
1236 		return true;
1237 	}
1238 	unsigned charBase = background->charBase >> 11;
1239 	unsigned charMask = (0x3FFF << charBase) & 0xFFFF;
1240 	if (renderer->vramDirty & charMask) {
1241 		return true;
1242 	}
1243 	return false;
1244 }
1245 
_dirtyMode3(struct GBAVideoGLRenderer * renderer,struct GBAVideoGLBackground * background,int y)1246 static bool _dirtyMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1247 	UNUSED(y);
1248 	if (!background->enabled) {
1249 		return false;
1250 	}
1251 	if (renderer->vramDirty & 0xFFFFF) {
1252 		return true;
1253 	}
1254 	return false;
1255 }
1256 
_dirtyMode45(struct GBAVideoGLRenderer * renderer,struct GBAVideoGLBackground * background,int y)1257 static bool _dirtyMode45(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1258 	UNUSED(y);
1259 	if (!background->enabled) {
1260 		return false;
1261 	}
1262 	int start = GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt) ? 5 : 0;
1263 	int mask = 0x3FF << start;
1264 	if (renderer->vramDirty & mask) {
1265 		return true;
1266 	}
1267 	return false;
1268 }
1269 
_needsVramUpload(struct GBAVideoGLRenderer * renderer,int y)1270 static bool _needsVramUpload(struct GBAVideoGLRenderer* renderer, int y) {
1271 	if (!renderer->vramDirty) {
1272 		return false;
1273 	}
1274 	if (y == 0) {
1275 		return true;
1276 	}
1277 
1278 	if (GBARegisterDISPCNTIsObjEnable(renderer->dispcnt) && renderer->vramDirty & 0xFF0000) {
1279 		return true;
1280 	}
1281 
1282 	bool dirty = false;
1283 	switch (GBARegisterDISPCNTGetMode(renderer->dispcnt)) {
1284 	case 0:
1285 		dirty = dirty || _dirtyMode0(renderer, &renderer->bg[0], y);
1286 		dirty = dirty || _dirtyMode0(renderer, &renderer->bg[1], y);
1287 		dirty = dirty || _dirtyMode0(renderer, &renderer->bg[2], y);
1288 		dirty = dirty || _dirtyMode0(renderer, &renderer->bg[3], y);
1289 		break;
1290 	case 1:
1291 		dirty = dirty || _dirtyMode0(renderer, &renderer->bg[0], y);
1292 		dirty = dirty || _dirtyMode0(renderer, &renderer->bg[1], y);
1293 		dirty = dirty || _dirtyMode2(renderer, &renderer->bg[2], y);
1294 		break;
1295 	case 2:
1296 		dirty = dirty || _dirtyMode2(renderer, &renderer->bg[2], y);
1297 		dirty = dirty || _dirtyMode2(renderer, &renderer->bg[3], y);
1298 		break;
1299 	case 3:
1300 		dirty = _dirtyMode3(renderer, &renderer->bg[2], y);
1301 		break;
1302 	case 4:
1303 		dirty = _dirtyMode45(renderer, &renderer->bg[2], y);
1304 		break;
1305 	case 5:
1306 		dirty = _dirtyMode45(renderer, &renderer->bg[2], y);
1307 		break;
1308 	}
1309 	return dirty;
1310 }
1311 
GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer * renderer,int y)1312 void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
1313 	struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
1314 
1315 	if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
1316 		if (glRenderer->firstAffine < 0) {
1317 			glRenderer->firstAffine = y;
1318 		}
1319 	} else {
1320 		glRenderer->firstAffine = -1;
1321 	}
1322 
1323 	if (_needsVramUpload(glRenderer, y) || glRenderer->oamDirty || glRenderer->regsDirty) {
1324 		if (glRenderer->firstY >= 0) {
1325 			_drawScanlines(glRenderer, y - 1);
1326 			glBindVertexArray(0);
1327 		}
1328 	}
1329 	if (glRenderer->firstY < 0) {
1330 		glRenderer->firstY = y;
1331 	}
1332 
1333 	int i;
1334 	for (i = 0; i < 0x30; ++i) {
1335 		if (!(glRenderer->regsDirty & (1ULL << i))) {
1336 			continue;
1337 		}
1338 		_cleanRegister(glRenderer, i << 1, glRenderer->shadowRegs[i]);
1339 	}
1340 	glRenderer->regsDirty = 0;
1341 
1342 	glRenderer->winNHistory[0][y * 4 + 0] = glRenderer->winN[0].h.start;
1343 	glRenderer->winNHistory[0][y * 4 + 1] = glRenderer->winN[0].h.end;
1344 	glRenderer->winNHistory[0][y * 4 + 2] = glRenderer->winN[0].v.start;
1345 	glRenderer->winNHistory[0][y * 4 + 3] = glRenderer->winN[0].v.end;
1346 	glRenderer->winNHistory[1][y * 4 + 0] = glRenderer->winN[1].h.start;
1347 	glRenderer->winNHistory[1][y * 4 + 1] = glRenderer->winN[1].h.end;
1348 	glRenderer->winNHistory[1][y * 4 + 2] = glRenderer->winN[1].v.start;
1349 	glRenderer->winNHistory[1][y * 4 + 3] = glRenderer->winN[1].v.end;
1350 
1351 	glRenderer->bg[0].scanlineOffset[y] = glRenderer->bg[0].x;
1352 	glRenderer->bg[0].scanlineOffset[y] |= glRenderer->bg[0].y << 12;
1353 	glRenderer->bg[1].scanlineOffset[y] = glRenderer->bg[1].x;
1354 	glRenderer->bg[1].scanlineOffset[y] |= glRenderer->bg[1].y << 12;
1355 	glRenderer->bg[2].scanlineOffset[y] = glRenderer->bg[2].x;
1356 	glRenderer->bg[2].scanlineOffset[y] |= glRenderer->bg[2].y << 12;
1357 	glRenderer->bg[2].scanlineAffine[y * 4] = glRenderer->bg[2].affine.dx;
1358 	glRenderer->bg[2].scanlineAffine[y * 4 + 1] = glRenderer->bg[2].affine.dy;
1359 	glRenderer->bg[2].scanlineAffine[y * 4 + 2] = glRenderer->bg[2].affine.sx;
1360 	glRenderer->bg[2].scanlineAffine[y * 4 + 3] = glRenderer->bg[2].affine.sy;
1361 	glRenderer->bg[3].scanlineOffset[y] = glRenderer->bg[3].x;
1362 	glRenderer->bg[3].scanlineOffset[y] |= glRenderer->bg[3].y << 12;
1363 	glRenderer->bg[3].scanlineAffine[y * 4] = glRenderer->bg[3].affine.dx;
1364 	glRenderer->bg[3].scanlineAffine[y * 4 + 1] = glRenderer->bg[3].affine.dy;
1365 	glRenderer->bg[3].scanlineAffine[y * 4 + 2] = glRenderer->bg[3].affine.sx;
1366 	glRenderer->bg[3].scanlineAffine[y * 4 + 3] = glRenderer->bg[3].affine.sy;
1367 
1368 	int oldPalette = glRenderer->nextPalette;
1369 	glRenderer->nextPalette = y + 1;
1370 	if (glRenderer->nextPalette >= GBA_VIDEO_VERTICAL_PIXELS) {
1371 		glRenderer->nextPalette = 0;
1372 	}
1373 	if (glRenderer->paletteDirty) {
1374 		memcpy(glRenderer->shadowPalette[glRenderer->nextPalette], glRenderer->shadowPalette[oldPalette], sizeof(glRenderer->shadowPalette[0]));
1375 		if (glRenderer->paletteDirtyScanlines > 0) {
1376 			--glRenderer->paletteDirtyScanlines;
1377 		}
1378 		if (!glRenderer->paletteDirtyScanlines) {
1379 			glRenderer->paletteDirty = false;
1380 			glActiveTexture(GL_TEXTURE0);
1381 			glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
1382 			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, glRenderer->shadowPalette);
1383 		}
1384 	}
1385 
1386 	if (_needsVramUpload(glRenderer, y)) {
1387 		int first = -1;
1388 		glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex);
1389 		for (i = 0; i < 25; ++i) {
1390 			if (!(glRenderer->vramDirty & (1 << i))) {
1391 				if (first >= 0) {
1392 					glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 8 * first, 256, 8 * (i - first), GL_RED_INTEGER, GL_UNSIGNED_SHORT, &glRenderer->d.vram[2048 * first]);
1393 					first = -1;
1394 				}
1395 			} else if (first < 0) {
1396 				first = i;
1397 			}
1398 		}
1399 		glRenderer->vramDirty = 0;
1400 	}
1401 
1402 	if (glRenderer->oamDirty) {
1403 		glRenderer->oamMax = GBAVideoRendererCleanOAM(glRenderer->d.oam->obj, glRenderer->sprites, 0);
1404 		glRenderer->oamDirty = false;
1405 	}
1406 
1407 	if (y == 0) {
1408 		glDisable(GL_SCISSOR_TEST);
1409 		glClearColor(0, 0, 0, 0);
1410 #ifdef BUILD_GLES3
1411 		glClearDepthf(1.f);
1412 #else
1413 		glClearDepth(1);
1414 #endif
1415 		glClearStencil(0);
1416 		glDepthMask(GL_TRUE);
1417 		glStencilMask(1);
1418 		glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
1419 		glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1420 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1421 
1422 		for (i = 0; i < 4; ++i) {
1423 			glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo);
1424 			glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1425 			glClear(GL_COLOR_BUFFER_BIT);
1426 		}
1427 
1428 		int spriteCyclesRemaining = GBARegisterDISPCNTIsHblankIntervalFree(glRenderer->dispcnt) ? OBJ_HBLANK_FREE_LENGTH : OBJ_LENGTH;
1429 		for (i = 0; i < GBA_VIDEO_VERTICAL_PIXELS; ++i) {
1430 			glRenderer->spriteCycles[i] = spriteCyclesRemaining;
1431 		}
1432 	}
1433 
1434 	if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
1435 		glRenderer->bg[2].affine.sx += glRenderer->bg[2].affine.dmx;
1436 		glRenderer->bg[2].affine.sy += glRenderer->bg[2].affine.dmy;
1437 		glRenderer->bg[3].affine.sx += glRenderer->bg[3].affine.dmx;
1438 		glRenderer->bg[3].affine.sy += glRenderer->bg[3].affine.dmy;
1439 	}
1440 }
1441 
_drawScanlines(struct GBAVideoGLRenderer * glRenderer,int y)1442 void _drawScanlines(struct GBAVideoGLRenderer* glRenderer, int y) {
1443 	glEnable(GL_SCISSOR_TEST);
1444 
1445 	glViewport(0, 0, 1, GBA_VIDEO_VERTICAL_PIXELS);
1446 	glScissor(0, glRenderer->firstY, 1, y - glRenderer->firstY + 1);
1447 	glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_BACKDROP]);
1448 	glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1449 	glClearBufferiv(GL_COLOR, 0, (GLint[]) { 32, glRenderer->target1Bd | (glRenderer->target2Bd * 2) | (glRenderer->blendEffect * 4), glRenderer->blda, 0 });
1450 	int i;
1451 	for (i = 0; i < 4; ++i) {
1452 		glScissor(i + 1, glRenderer->firstY, 1, y - glRenderer->firstY + 1);
1453 		glClearBufferiv(GL_COLOR, 0, (GLint[]) { glRenderer->bg[i].priority,
1454 		                                         glRenderer->bg[i].target1 | (glRenderer->bg[i].target2 << 1) | (glRenderer->blendEffect << 2),
1455 		                                         glRenderer->blda, 0 });
1456 	}
1457 
1458 	if (glRenderer->paletteDirty) {
1459 		glActiveTexture(GL_TEXTURE0);
1460 		glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
1461 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, glRenderer->shadowPalette);
1462 	}
1463 
1464 	GBAVideoGLRendererDrawWindow(glRenderer, y);
1465 	if (GBARegisterDISPCNTIsObjEnable(glRenderer->dispcnt) && !glRenderer->d.disableOBJ) {
1466 		glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
1467 		glDepthFunc(GL_LESS);
1468 		for (i = 0; i < glRenderer->oamMax; ++i) {
1469 			struct GBAVideoRendererSprite* sprite = &glRenderer->sprites[i];
1470 			if ((y < sprite->y && (sprite->endY - 256 < 0 || glRenderer->firstY >= sprite->endY - 256)) || glRenderer->firstY >= sprite->endY) {
1471 				continue;
1472 			}
1473 
1474 			GBAVideoGLRendererDrawSprite(glRenderer, &sprite->obj, y, sprite->y);
1475 
1476 			int startY = sprite->y;
1477 			int endY = sprite->endY;
1478 
1479 			if (endY >= 256) {
1480 				startY -= 256;
1481 				endY -= 256;
1482 			}
1483 			if (startY < glRenderer->firstY) {
1484 				startY = glRenderer->firstY;
1485 			}
1486 			if (endY > y) {
1487 				endY = y;
1488 			}
1489 			int j;
1490 			for (j = startY; j <= endY; ++j) {
1491 				glRenderer->spriteCycles[j] -= sprite->cycles;
1492 			}
1493 		}
1494 		glDisable(GL_DEPTH_TEST);
1495 		glDisable(GL_STENCIL_TEST);
1496 	}
1497 
1498 	if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
1499 		GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[0], y);
1500 	}
1501 	if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
1502 		GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[1], y);
1503 	}
1504 	if (TEST_LAYER_ENABLED(2)) {
1505 		switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
1506 		case 0:
1507 			GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[2], y);
1508 			break;
1509 		case 1:
1510 		case 2:
1511 			GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[2], y);
1512 			break;
1513 		case 3:
1514 			GBAVideoGLRendererDrawBackgroundMode3(glRenderer, &glRenderer->bg[2], y);
1515 			break;
1516 		case 4:
1517 			GBAVideoGLRendererDrawBackgroundMode4(glRenderer, &glRenderer->bg[2], y);
1518 			break;
1519 		case 5:
1520 			GBAVideoGLRendererDrawBackgroundMode5(glRenderer, &glRenderer->bg[2], y);
1521 			break;
1522 		}
1523 	}
1524 	if (TEST_LAYER_ENABLED(3)) {
1525 		switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
1526 		case 0:
1527 			GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[3], y);
1528 			break;
1529 		case 2:
1530 			GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[3], y);
1531 			break;
1532 		}
1533 	}
1534 	glRenderer->firstY = -1;
1535 }
1536 
GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer * renderer)1537 void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) {
1538 	struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
1539 	_drawScanlines(glRenderer, GBA_VIDEO_VERTICAL_PIXELS - 1);
1540 	_finalizeLayers(glRenderer);
1541 	glDisable(GL_SCISSOR_TEST);
1542 	glBindVertexArray(0);
1543 	glRenderer->firstAffine = -1;
1544 	glRenderer->firstY = -1;
1545 	glRenderer->bg[2].affine.sx = glRenderer->bg[2].refx;
1546 	glRenderer->bg[2].affine.sy = glRenderer->bg[2].refy;
1547 	glRenderer->bg[3].affine.sx = glRenderer->bg[3].refx;
1548 	glRenderer->bg[3].affine.sy = glRenderer->bg[3].refy;
1549 }
1550 
GBAVideoGLRendererGetPixels(struct GBAVideoRenderer * renderer,size_t * stride,const void ** pixels)1551 void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
1552 	struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
1553 	*stride = GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale;
1554 	if (!glRenderer->temporaryBuffer) {
1555 		glRenderer->temporaryBuffer = anonymousMemoryMap(GBA_VIDEO_HORIZONTAL_PIXELS * GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale * glRenderer->scale * BYTES_PER_PIXEL);
1556 	}
1557 	glFinish();
1558 	glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OUTPUT]);
1559 	glPixelStorei(GL_PACK_ROW_LENGTH, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale);
1560 	glPixelStorei(GL_PACK_ALIGNMENT, 1);
1561 	glReadPixels(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, GL_RGBA, GL_UNSIGNED_BYTE, (void*) glRenderer->temporaryBuffer);
1562 	*pixels = glRenderer->temporaryBuffer;
1563 }
1564 
GBAVideoGLRendererPutPixels(struct GBAVideoRenderer * renderer,size_t stride,const void * pixels)1565 void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
1566 	// TODO
1567 	UNUSED(renderer);
1568 	UNUSED(stride);
1569 	UNUSED(pixels);
1570 }
1571 
_enableBg(struct GBAVideoGLRenderer * renderer,int bg,bool active)1572 static void _enableBg(struct GBAVideoGLRenderer* renderer, int bg, bool active) {
1573 	int wasActive = renderer->bg[bg].enabled;
1574 	if (!active) {
1575 		renderer->bg[bg].enabled = 0;
1576 	} else if (!wasActive && active) {
1577 		/*if (renderer->nextY == 0 || GBARegisterDISPCNTGetMode(renderer->dispcnt) > 2) {
1578 			// TODO: Investigate in more depth how switching background works in different modes
1579 			renderer->bg[bg].enabled = 4;
1580 		} else {
1581 			renderer->bg[bg].enabled = 1;
1582 		}*/
1583 		renderer->bg[bg].enabled = 4;
1584 	}
1585 }
1586 
GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer * renderer)1587 static void GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer* renderer) {
1588 	_enableBg(renderer, 0, GBARegisterDISPCNTGetBg0Enable(renderer->dispcnt));
1589 	_enableBg(renderer, 1, GBARegisterDISPCNTGetBg1Enable(renderer->dispcnt));
1590 	_enableBg(renderer, 2, GBARegisterDISPCNTGetBg2Enable(renderer->dispcnt));
1591 	_enableBg(renderer, 3, GBARegisterDISPCNTGetBg3Enable(renderer->dispcnt));
1592 }
1593 
GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground * bg,uint16_t value)1594 static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value) {
1595 	bg->priority = GBARegisterBGCNTGetPriority(value);
1596 	bg->charBase = GBARegisterBGCNTGetCharBase(value) << 13;
1597 	bg->mosaic = GBARegisterBGCNTGetMosaic(value);
1598 	bg->multipalette = GBARegisterBGCNTGet256Color(value);
1599 	bg->screenBase = GBARegisterBGCNTGetScreenBase(value) << 10;
1600 	bg->overflow = GBARegisterBGCNTGetOverflow(value);
1601 	bg->size = GBARegisterBGCNTGetSize(value);
1602 }
1603 
GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground * bg,uint16_t value)1604 static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
1605 	bg->refx = (bg->refx & 0xFFFF0000) | value;
1606 	bg->affine.sx = bg->refx;
1607 }
1608 
GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground * bg,uint16_t value)1609 static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
1610 	bg->refx = (bg->refx & 0x0000FFFF) | (value << 16);
1611 	bg->refx <<= 4;
1612 	bg->refx >>= 4;
1613 	bg->affine.sx = bg->refx;
1614 }
1615 
GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground * bg,uint16_t value)1616 static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
1617 	bg->refy = (bg->refy & 0xFFFF0000) | value;
1618 	bg->affine.sy = bg->refy;
1619 }
1620 
GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground * bg,uint16_t value)1621 static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
1622 	bg->refy = (bg->refy & 0x0000FFFF) | (value << 16);
1623 	bg->refy <<= 4;
1624 	bg->refy >>= 4;
1625 	bg->affine.sy = bg->refy;
1626 }
1627 
GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer * renderer,uint16_t value)1628 static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value) {
1629 	renderer->bg[0].target1 = GBARegisterBLDCNTGetTarget1Bg0(value);
1630 	renderer->bg[1].target1 = GBARegisterBLDCNTGetTarget1Bg1(value);
1631 	renderer->bg[2].target1 = GBARegisterBLDCNTGetTarget1Bg2(value);
1632 	renderer->bg[3].target1 = GBARegisterBLDCNTGetTarget1Bg3(value);
1633 	renderer->bg[0].target2 = GBARegisterBLDCNTGetTarget2Bg0(value);
1634 	renderer->bg[1].target2 = GBARegisterBLDCNTGetTarget2Bg1(value);
1635 	renderer->bg[2].target2 = GBARegisterBLDCNTGetTarget2Bg2(value);
1636 	renderer->bg[3].target2 = GBARegisterBLDCNTGetTarget2Bg3(value);
1637 
1638 	renderer->blendEffect = GBARegisterBLDCNTGetEffect(value);
1639 	renderer->target1Obj = GBARegisterBLDCNTGetTarget1Obj(value);
1640 	renderer->target1Bd = GBARegisterBLDCNTGetTarget1Bd(value);
1641 	renderer->target2Obj = GBARegisterBLDCNTGetTarget2Obj(value);
1642 	renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value);
1643 }
1644 
_finalizeLayers(struct GBAVideoGLRenderer * renderer)1645 void _finalizeLayers(struct GBAVideoGLRenderer* renderer) {
1646 	const GLuint* uniforms = renderer->finalizeShader.uniforms;
1647 	glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OUTPUT]);
1648 	glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1649 	glScissor(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1650 	if (GBARegisterDISPCNTIsForcedBlank(renderer->dispcnt)) {
1651 		glClearColor(1.f, 1.f, 1.f, 1.f);
1652 		glClear(GL_COLOR_BUFFER_BIT);
1653 	} else {
1654 		glUseProgram(renderer->finalizeShader.program);
1655 		glBindVertexArray(renderer->finalizeShader.vao);
1656 		glActiveTexture(GL_TEXTURE0);
1657 		glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_WINDOW]);
1658 		glActiveTexture(GL_TEXTURE0 + 1);
1659 		glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_OBJ_COLOR]);
1660 		glActiveTexture(GL_TEXTURE0 + 2);
1661 		glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_OBJ_FLAGS]);
1662 		glActiveTexture(GL_TEXTURE0 + 3);
1663 		glBindTexture(GL_TEXTURE_2D, renderer->bg[0].tex);
1664 		glActiveTexture(GL_TEXTURE0 + 4);
1665 		glBindTexture(GL_TEXTURE_2D, renderer->bg[1].tex);
1666 		glActiveTexture(GL_TEXTURE0 + 5);
1667 		glBindTexture(GL_TEXTURE_2D, renderer->bg[2].tex);
1668 		glActiveTexture(GL_TEXTURE0 + 6);
1669 		glBindTexture(GL_TEXTURE_2D, renderer->bg[3].tex);
1670 		glActiveTexture(GL_TEXTURE0 + 7);
1671 		glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
1672 		glActiveTexture(GL_TEXTURE0 + 8);
1673 		glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_BACKDROP]);
1674 
1675 		glUniform2i(uniforms[GBA_GL_VS_LOC], GBA_VIDEO_VERTICAL_PIXELS, 0);
1676 		glUniform2i(uniforms[GBA_GL_VS_MAXPOS], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1677 		glUniform1i(uniforms[GBA_GL_FINALIZE_SCALE], renderer->scale);
1678 		glUniform1iv(uniforms[GBA_GL_FINALIZE_LAYERS], 5, (GLint[]) { 3, 4, 5, 6, 1 });
1679 		glUniform1i(uniforms[GBA_GL_FINALIZE_FLAGS], 2);
1680 		glUniform1i(uniforms[GBA_GL_FINALIZE_WINDOW], 0);
1681 		glUniform1i(uniforms[GBA_GL_FINALIZE_PALETTE], 7);
1682 		glUniform1i(uniforms[GBA_GL_FINALIZE_BACKDROP], 8);
1683 		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1684 	}
1685 	glBindFramebuffer(GL_FRAMEBUFFER, 0);
1686 }
1687 
GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer * renderer,struct GBAObj * sprite,int y,int spriteY)1688 void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY) {
1689 	int width = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][0];
1690 	int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][1];
1691 	int32_t x = (uint32_t) GBAObjAttributesBGetX(sprite->b) << 23;
1692 	x >>= 23;
1693 
1694 	if (GBARegisterDISPCNTGetMode(renderer->dispcnt) >= 3 && GBAObjAttributesCGetTile(sprite->c) < 512) {
1695 		return;
1696 	}
1697 
1698 	int align = GBAObjAttributesAIs256Color(sprite->a) && !GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt);
1699 	unsigned charBase = (BASE_TILE >> 1) + (GBAObjAttributesCGetTile(sprite->c) & ~align) * 0x10;
1700 	int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x20 >> GBAObjAttributesAGet256Color(sprite->a));
1701 
1702 	int totalWidth = width;
1703 	int totalHeight = height;
1704 	if (GBAObjAttributesAIsTransformed(sprite->a) && GBAObjAttributesAIsDoubleSize(sprite->a)) {
1705 		totalWidth <<= 1;
1706 		totalHeight <<= 1;
1707 	}
1708 
1709 	if (spriteY + totalHeight >= 256) {
1710 		spriteY -= 256;
1711 	}
1712 
1713 	if (x + totalWidth <= 0 || x >= GBA_VIDEO_HORIZONTAL_PIXELS) {
1714 		// These sprites aren't displayed but affect cycle counting
1715 		return;
1716 	}
1717 
1718 	const struct GBAVideoGLShader* shader = &renderer->objShader[GBAObjAttributesAGet256Color(sprite->a)];
1719 	const GLuint* uniforms = shader->uniforms;
1720 	glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]);
1721 	glViewport(x * renderer->scale, spriteY * renderer->scale, totalWidth * renderer->scale, totalHeight * renderer->scale);
1722 	glScissor(x * renderer->scale, renderer->firstY * renderer->scale, totalWidth * renderer->scale, (y - renderer->firstY + 1) * renderer->scale);
1723 	glUseProgram(shader->program);
1724 	glBindVertexArray(shader->vao);
1725 	glActiveTexture(GL_TEXTURE0);
1726 	glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
1727 	glActiveTexture(GL_TEXTURE1);
1728 	glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
1729 	glUniform2i(uniforms[GBA_GL_VS_LOC], totalHeight, 0);
1730 	glUniform2i(uniforms[GBA_GL_VS_MAXPOS], totalWidth, totalHeight);
1731 	glUniform1i(uniforms[GBA_GL_OBJ_VRAM], 0);
1732 	glUniform1i(uniforms[GBA_GL_OBJ_PALETTE], 1);
1733 	glUniform1i(uniforms[GBA_GL_OBJ_CHARBASE], charBase);
1734 	glUniform1i(uniforms[GBA_GL_OBJ_STRIDE], stride);
1735 	glUniform1i(uniforms[GBA_GL_OBJ_LOCALPALETTE], GBAObjAttributesCGetPalette(sprite->c));
1736 	glUniform4i(uniforms[GBA_GL_OBJ_INFLAGS], GBAObjAttributesCGetPriority(sprite->c),
1737 	                                          (renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) | (renderer->target2Obj * 2) | (renderer->blendEffect * 4),
1738 	                                          renderer->blda, GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT);
1739 	glUniform1iv(uniforms[GBA_GL_OBJ_CYCLES], GBA_VIDEO_VERTICAL_PIXELS, renderer->spriteCycles);
1740 	if (GBAObjAttributesAIsTransformed(sprite->a)) {
1741 		struct GBAOAMMatrix mat;
1742 		LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a);
1743 		LOAD_16(mat.b, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].b);
1744 		LOAD_16(mat.c, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].c);
1745 		LOAD_16(mat.d, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].d);
1746 
1747 		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 });
1748 	} else {
1749 		int flipX = 1;
1750 		int flipY = 1;
1751 		if (GBAObjAttributesBIsHFlip(sprite->b)) {
1752 			flipX = -1;
1753 		}
1754 		if (GBAObjAttributesBIsVFlip(sprite->b)) {
1755 			flipY = -1;
1756 		}
1757 		glUniformMatrix2fv(uniforms[GBA_GL_OBJ_TRANSFORM], 1, GL_FALSE, (GLfloat[]) { flipX, 0, 0, flipY });
1758 	}
1759 	glUniform4i(uniforms[GBA_GL_OBJ_DIMS], width, height, totalWidth, totalHeight);
1760 	glDisable(GL_STENCIL_TEST);
1761 	if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_OBJWIN) {
1762 		// OBJWIN writes do not affect pixel priority
1763 		glDisable(GL_DEPTH_TEST);
1764 		glDepthMask(GL_FALSE);
1765 		glStencilMask(0);
1766 		int window = renderer->objwin & 0x3F;
1767 		glUniform3i(uniforms[GBA_GL_OBJ_OBJWIN], window, renderer->bldb, renderer->bldy);
1768 		glDrawBuffers(3, (GLenum[]) { GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT2 });
1769 	} else {
1770 		glEnable(GL_DEPTH_TEST);
1771 		glDepthMask(GL_TRUE);
1772 		glStencilMask(1);
1773 		glStencilFunc(GL_ALWAYS, 1, 1);
1774 		glUniform3i(uniforms[GBA_GL_OBJ_OBJWIN], 0, 0, 0);
1775 		glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
1776 	}
1777 	if (GBAObjAttributesAIsMosaic(sprite->a) && GBAObjAttributesAGetMode(sprite->a) != OBJ_MODE_OBJWIN) {
1778 		int mosaicH = GBAMosaicControlGetObjH(renderer->mosaic) + 1;
1779 		if (GBAObjAttributesBIsHFlip(sprite->b)) {
1780 			mosaicH = -mosaicH;
1781 		}
1782 		glUniform4i(uniforms[GBA_GL_OBJ_MOSAIC], mosaicH, GBAMosaicControlGetObjV(renderer->mosaic) + 1, x, spriteY);
1783 	} else {
1784 		glUniform4i(uniforms[GBA_GL_OBJ_MOSAIC], 0, 0, x, spriteY);
1785 	}
1786 	if (GBAObjAttributesAGetMode(sprite->a) != OBJ_MODE_OBJWIN || GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt)) {
1787 		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1788 	}
1789 
1790 	if (GBAObjAttributesAGetMode(sprite->a) != OBJ_MODE_OBJWIN) {
1791 		// Update the pixel priority for already-written pixels
1792 		shader = &renderer->objShader[2];
1793 		uniforms = shader->uniforms;
1794 		glEnable(GL_STENCIL_TEST);
1795 		glStencilFunc(GL_EQUAL, 1, 1);
1796 		glUseProgram(shader->program);
1797 		glDrawBuffers(2, (GLenum[]) { GL_NONE, GL_COLOR_ATTACHMENT1 });
1798 		glBindVertexArray(shader->vao);
1799 		glUniform2i(uniforms[GBA_GL_VS_LOC], totalHeight, 0);
1800 		glUniform2i(uniforms[GBA_GL_VS_MAXPOS], totalWidth, totalHeight);
1801 		glUniform4i(uniforms[GBA_GL_OBJ_INFLAGS], GBAObjAttributesCGetPriority(sprite->c),
1802 		                                          (renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) | (renderer->target2Obj * 2) | (renderer->blendEffect * 4),
1803 		                                          renderer->blda, GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT);
1804 		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1805 	}
1806 
1807 	glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1808 }
1809 
_prepareBackground(struct GBAVideoGLRenderer * renderer,struct GBAVideoGLBackground * background,const GLuint * uniforms)1810 void _prepareBackground(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, const GLuint* uniforms) {
1811 	glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
1812 	glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1813 	glActiveTexture(GL_TEXTURE0);
1814 	glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
1815 	glActiveTexture(GL_TEXTURE1);
1816 	glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
1817 	glUniform2i(uniforms[GBA_GL_VS_MAXPOS], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1818 	glUniform1i(uniforms[GBA_GL_BG_VRAM], 0);
1819 	glUniform1i(uniforms[GBA_GL_OBJ_PALETTE], 1);
1820 	if (background->mosaic) {
1821 		glUniform2i(uniforms[GBA_GL_BG_MOSAIC], GBAMosaicControlGetBgH(renderer->mosaic) + 1, GBAMosaicControlGetBgV(renderer->mosaic) + 1);
1822 	} else {
1823 		glUniform2i(uniforms[GBA_GL_BG_MOSAIC], 0, 0);
1824 	}
1825 	glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1826 }
1827 
GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer * renderer,struct GBAVideoGLBackground * background,int y)1828 void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1829 	const struct GBAVideoGLShader* shader = &renderer->bgShader[background->multipalette ? 1 : 0];
1830 	const GLuint* uniforms = shader->uniforms;
1831 	glUseProgram(shader->program);
1832 	glBindVertexArray(shader->vao);
1833 	_prepareBackground(renderer, background, uniforms);
1834 	glUniform1i(uniforms[GBA_GL_BG_SCREENBASE], background->screenBase);
1835 	glUniform1i(uniforms[GBA_GL_BG_CHARBASE], background->charBase);
1836 	glUniform1i(uniforms[GBA_GL_BG_SIZE], background->size);
1837 	glUniform1iv(uniforms[GBA_GL_BG_OFFSET], GBA_VIDEO_VERTICAL_PIXELS, background->scanlineOffset);
1838 
1839 	glScissor(0, renderer->firstY * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, (y - renderer->firstY + 1) * renderer->scale);
1840 	glUniform2i(uniforms[GBA_GL_VS_LOC], y - renderer->firstY + 1, renderer->firstY);
1841 	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1842 
1843 	glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1844 }
1845 
_prepareTransform(struct GBAVideoGLRenderer * renderer,struct GBAVideoGLBackground * background,const GLuint * uniforms,int y)1846 void _prepareTransform(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, const GLuint* uniforms, int y) {
1847 	glScissor(0, renderer->firstY * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale * (y - renderer->firstY + 1));
1848 	glUniform2i(uniforms[GBA_GL_VS_LOC], y - renderer->firstY + 1, renderer->firstY);
1849 	glUniform2i(uniforms[GBA_GL_BG_RANGE], renderer->firstAffine, y);
1850 
1851 	glUniform4iv(uniforms[GBA_GL_BG_TRANSFORM], GBA_VIDEO_VERTICAL_PIXELS, background->scanlineAffine);
1852 	_prepareBackground(renderer, background, uniforms);
1853 }
1854 
GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer * renderer,struct GBAVideoGLBackground * background,int y)1855 void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1856 	const struct GBAVideoGLShader* shader = &renderer->bgShader[background->overflow ? 2 : 3];
1857 	const GLuint* uniforms = shader->uniforms;
1858 	glUseProgram(shader->program);
1859 	glBindVertexArray(shader->vao);
1860 	_prepareTransform(renderer, background, uniforms, y);
1861 	glUniform1i(uniforms[GBA_GL_BG_SCREENBASE], background->screenBase);
1862 	glUniform1i(uniforms[GBA_GL_BG_CHARBASE], background->charBase);
1863 	glUniform1i(uniforms[GBA_GL_BG_SIZE], background->size);
1864 	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1865 	glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1866 }
1867 
GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer * renderer,struct GBAVideoGLBackground * background,int y)1868 void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1869 	const struct GBAVideoGLShader* shader = &renderer->bgShader[5];
1870 	const GLuint* uniforms = shader->uniforms;
1871 	glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
1872 	glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1873 	glUseProgram(shader->program);
1874 	glBindVertexArray(shader->vao);
1875 	_prepareTransform(renderer, background, uniforms, y);
1876 	glUniform1i(uniforms[GBA_GL_BG_CHARBASE], 0);
1877 	glUniform2i(uniforms[GBA_GL_BG_SIZE], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1878 	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1879 	glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1880 }
1881 
GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer * renderer,struct GBAVideoGLBackground * background,int y)1882 void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1883 	const struct GBAVideoGLShader* shader = &renderer->bgShader[4];
1884 	const GLuint* uniforms = shader->uniforms;
1885 	glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
1886 	glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1887 	glUseProgram(shader->program);
1888 	glBindVertexArray(shader->vao);
1889 	_prepareTransform(renderer, background, uniforms, y);
1890 	glUniform1i(uniforms[GBA_GL_BG_CHARBASE], GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt) ? 0xA000 : 0);
1891 	glUniform2i(uniforms[GBA_GL_BG_SIZE], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1892 	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1893 	glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1894 }
1895 
GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer * renderer,struct GBAVideoGLBackground * background,int y)1896 void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1897 	const struct GBAVideoGLShader* shader = &renderer->bgShader[5];
1898 	const GLuint* uniforms = shader->uniforms;
1899 	glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
1900 	glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1901 	glUseProgram(shader->program);
1902 	glBindVertexArray(shader->vao);
1903 	_prepareTransform(renderer, background, uniforms, y);
1904 	glUniform1i(uniforms[GBA_GL_BG_CHARBASE], GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt) ? 0x5000 : 0);
1905 	glUniform2i(uniforms[GBA_GL_BG_SIZE], 160, 128);
1906 	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1907 	glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1908 }
1909 
GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer * renderer,int y)1910 void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y) {
1911 	const struct GBAVideoGLShader* shader = &renderer->windowShader;
1912 	const GLuint* uniforms = shader->uniforms;
1913 	glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_WINDOW]);
1914 	glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1915 	glScissor(0, renderer->firstY * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale * (y - renderer->firstY + 1));
1916 	glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1917 	switch (renderer->dispcnt & 0xE000) {
1918 	case 0x0000:
1919 		// No windows are enabled
1920 		glClearBufferiv(GL_COLOR, 0, (GLint[]) { ((renderer->dispcnt >> 8) & 0x1F) | 0x20, renderer->bldb, renderer->bldy, 0 });
1921 		break;
1922 	case 0x8000:
1923 		// Only OBJWIN is enabled
1924 		glClearBufferiv(GL_COLOR, 0, (GLint[]) { renderer->winout, renderer->bldb, renderer->bldy, 0 });
1925 		break;
1926 	default:
1927 		glUseProgram(shader->program);
1928 		glBindVertexArray(shader->vao);
1929 		glUniform2i(uniforms[GBA_GL_VS_LOC], y - renderer->firstY + 1, renderer->firstY);
1930 		glUniform2i(uniforms[GBA_GL_VS_MAXPOS], GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1931 		glUniform1i(uniforms[GBA_GL_WIN_DISPCNT], renderer->dispcnt >> 8);
1932 		glUniform2i(uniforms[GBA_GL_WIN_BLEND], renderer->bldb, renderer->bldy);
1933 		glUniform3i(uniforms[GBA_GL_WIN_FLAGS], renderer->winN[0].control, renderer->winN[1].control, renderer->winout);
1934 		glUniform4iv(uniforms[GBA_GL_WIN_WIN0], GBA_VIDEO_VERTICAL_PIXELS, renderer->winNHistory[0]);
1935 		glUniform4iv(uniforms[GBA_GL_WIN_WIN1], GBA_VIDEO_VERTICAL_PIXELS, renderer->winNHistory[1]);
1936 		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1937 		break;
1938 	}
1939 }
1940 
GBAVideoGLRendererSetScale(struct GBAVideoGLRenderer * renderer,int scale)1941 void GBAVideoGLRendererSetScale(struct GBAVideoGLRenderer* renderer, int scale) {
1942 	if (scale == renderer->scale) {
1943 		return;
1944 	}
1945 	if (renderer->temporaryBuffer) {
1946 		mappedMemoryFree(renderer->temporaryBuffer, GBA_VIDEO_HORIZONTAL_PIXELS * GBA_VIDEO_VERTICAL_PIXELS * renderer->scale * renderer->scale * BYTES_PER_PIXEL);
1947 		renderer->temporaryBuffer = NULL;
1948 	}
1949 	renderer->scale = scale;
1950 	_initFramebuffers(renderer);
1951 	renderer->paletteDirty = true;
1952 }
1953 
1954 #endif
1955