src/gba/renderers/gl.c (view raw)
1/* Copyright (c) 2013-2019 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/gba/renderers/gl.h>
7
8#include <mgba/core/cache-set.h>
9#include <mgba/internal/arm/macros.h>
10#include <mgba/internal/gba/io.h>
11#include <mgba/internal/gba/renderers/cache-set.h>
12
13static void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer);
14static void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer);
15static void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer);
16static void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address);
17static void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam);
18static void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
19static uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
20static void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y);
21static void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer);
22static void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels);
23static void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);
24
25static void GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer* renderer);
26static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value);
27static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value);
28static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value);
29static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value);
30static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value);
31static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value);
32
33static void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY);
34static void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
35static void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
36static void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
37static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
38static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
39
40static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int y);
41
42#define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 && glRenderer->bg[X].priority == priority
43
44static const GLchar* const _gl3Header =
45 "#version 130\n";
46
47static const char* const _vertexShader =
48 "attribute vec2 position;\n"
49 "uniform ivec2 loc;\n"
50 "uniform ivec2 maxPos;\n"
51 "varying vec2 texCoord;\n"
52
53 "void main() {\n"
54 " vec2 local = vec2(position.x, float(position.y * loc.x + loc.y) / abs(maxPos.y));\n"
55 " gl_Position = vec4((local * 2. - 1.) * sign(maxPos), 0., 1.);\n"
56 " texCoord = local * abs(maxPos);\n"
57 "}";
58
59static const char* const _renderTile16 =
60 "vec4 renderTile(int tile, int paletteId, ivec2 localCoord) {\n"
61 " int address = charBase + tile * 16 + (localCoord.x >> 2) + (localCoord.y << 1);\n"
62 " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n"
63 " int entry = int(halfrow[3 - (localCoord.x & 3)] * 15.9);\n"
64 " vec4 color = texelFetch(palette, ivec2(entry, paletteId), 0);\n"
65 " if (entry == 0) {\n"
66 " discard;\n"
67 " }\n"
68 " color.a = 1;\n"
69 " return color;\n"
70 "}";
71
72static const char* const _renderTile256 =
73 "vec4 renderTile(int tile, int paletteId, ivec2 localCoord) {\n"
74 " int address = charBase + tile * 32 + (localCoord.x >> 1) + (localCoord.y << 2);\n"
75 " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n"
76 " int entry = int(halfrow[3 - 2 * (localCoord.x & 1)] * 15.9);\n"
77 " int pal2 = int(halfrow[2 - 2 * (localCoord.x & 1)] * 15.9);\n"
78 " vec4 color = texelFetch(palette, ivec2(entry, pal2 + (paletteId & 16)), 0);\n"
79 " if ((pal2 | entry) == 0) {\n"
80 " discard;\n"
81 " }\n"
82 " color.a = 1.;\n"
83 " return color;\n"
84 "}";
85
86static const char* const _renderMode0 =
87 "varying vec2 texCoord;\n"
88 "uniform sampler2D vram;\n"
89 "uniform sampler2D palette;\n"
90 "uniform int screenBase;\n"
91 "uniform int charBase;\n"
92 "uniform int size;\n"
93 "uniform ivec2 offset;\n"
94 "uniform ivec3 inflags;\n"
95 "out vec4 color;\n"
96 "out vec3 flags;\n"
97 "const vec3 flagCoeff = vec3(32., 8., 4.);\n"
98
99 "vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n"
100
101 "void main() {\n"
102 " ivec2 coord = ivec2(texCoord) + offset;\n"
103 " if ((size & 1) == 1) {\n"
104 " coord.y += coord.x & 256;\n"
105 " }\n"
106 " coord.x &= 255;\n"
107 " int mapAddress = screenBase + (coord.x >> 3) + (coord.y >> 3) * 32;\n"
108 " vec4 map = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0);\n"
109 " int tileFlags = int(map.g * 15.9);\n"
110 " if ((tileFlags & 4) == 4) {\n"
111 " coord.x ^= 7;\n"
112 " }\n"
113 " if ((tileFlags & 8) == 8) {\n"
114 " coord.y ^= 7;\n"
115 " }\n"
116 " int tile = int(map.a * 15.9) + int(map.b * 15.9) * 16 + (tileFlags & 0x3) * 256;\n"
117 " color = renderTile(tile, int(map.r * 15.9), coord & 7);\n"
118 " flags = inflags / flagCoeff;\n"
119 "}";
120
121static const char* const _fetchTileOverflow =
122 "vec4 fetchTile(ivec2 coord) {\n"
123 " int sizeAdjusted = (0x8000 << size) - 1;\n"
124 " coord &= sizeAdjusted;\n"
125 " return renderTile(coord);\n"
126 "}";
127
128static const char* const _fetchTileNoOverflow =
129 "vec4 fetchTile(ivec2 coord) {\n"
130 " int sizeAdjusted = (0x8000 << size) - 1;\n"
131 " ivec2 outerCoord = coord & ~sizeAdjusted;\n"
132 " if ((outerCoord.x | outerCoord.y) != 0) {\n"
133 " discard;\n"
134 " }\n"
135 " return renderTile(coord);\n"
136 "}";
137
138static const char* const _renderMode2 =
139 "varying vec2 texCoord;\n"
140 "uniform sampler2D vram;\n"
141 "uniform sampler2D palette;\n"
142 "uniform int screenBase;\n"
143 "uniform int charBase;\n"
144 "uniform int size;\n"
145 "uniform ivec3 inflags;\n"
146 "uniform ivec2[4] offset;\n"
147 "uniform ivec2[4] transform;\n"
148 "out vec4 color;\n"
149 "out vec3 flags;\n"
150 "const vec3 flagCoeff = vec3(32., 8., 4.);\n"
151 "precision highp float;\n"
152 "precision highp int;\n"
153
154 "vec4 fetchTile(ivec2 coord);\n"
155
156 "vec4 renderTile(ivec2 coord) {\n"
157 " int map = (coord.x >> 11) + (((coord.y >> 7) & 0x7F0) << size);\n"
158 " int mapAddress = screenBase + (map >> 1);\n"
159 " vec4 twomaps = texelFetch(vram, ivec2(mapAddress & 255, mapAddress >> 8), 0);\n"
160 " int tile = int(twomaps[3 - 2 * (map & 1)] * 15.9) + int(twomaps[2 - 2 * (map & 1)] * 15.9) * 16;\n"
161 " int address = charBase + tile * 32 + ((coord.x >> 9) & 3) + ((coord.y >> 6) & 0x1C);\n"
162 " vec4 halfrow = texelFetch(vram, ivec2(address & 255, address >> 8), 0);\n"
163 " int entry = int(halfrow[3 - ((coord.x >> 7) & 2)] * 15.9);\n"
164 " int pal2 = int(halfrow[2 - ((coord.x >> 7) & 2)] * 15.9);\n"
165 " vec4 color = texelFetch(palette, ivec2(entry, pal2), 0);\n"
166 " if ((pal2 | entry) == 0) {\n"
167 " discard;\n"
168 " }\n"
169 " color.a = 1.;\n"
170 " return color;\n"
171 "}\n"
172
173 "vec2 interpolate(ivec2 arr[4], float x) {\n"
174 " float x1m = 1. - x;\n"
175 " return x1m * x1m * x1m * arr[0] +"
176 " 3 * x1m * x1m * x * arr[1] +"
177 " 3 * x1m * x * x * arr[2] +"
178 " x * x * x * arr[3];\n"
179 "}\n"
180
181 "void main() {\n"
182 " float y = fract(texCoord.y);\n"
183 " float lin = 0.5 - y / ceil(y) * 0.25;\n"
184 " vec2 mixedTransform = interpolate(transform, lin);\n"
185 " vec2 mixedOffset = interpolate(offset, lin);\n"
186 " color = fetchTile(ivec2(mixedTransform * texCoord.x + mixedOffset));\n"
187 " flags = inflags / flagCoeff;\n"
188 "}";
189
190static const char* const _renderObj =
191 "varying vec2 texCoord;\n"
192 "uniform sampler2D vram;\n"
193 "uniform sampler2D palette;\n"
194 "uniform int charBase;\n"
195 "uniform int stride;\n"
196 "uniform int localPalette;\n"
197 "uniform ivec3 inflags;\n"
198 "uniform mat2x2 transform;\n"
199 "uniform ivec4 dims;\n"
200 "out vec4 color;\n"
201 "out vec3 flags;\n"
202 "const vec3 flagCoeff = vec3(32., 8., 4.);\n"
203
204 "vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n"
205
206 "void main() {\n"
207 " ivec2 coord = ivec2(transform * (texCoord - dims.zw / 2) + dims.xy / 2);\n"
208 " if ((coord & ~(dims.xy - 1)) != ivec2(0, 0)) {\n"
209 " discard;\n"
210 " }\n"
211 " color = renderTile((coord.x >> 3) + (coord.y >> 3) * stride, 16 + localPalette, coord & 7);\n"
212 " flags = inflags / flagCoeff;\n"
213 "}";
214
215static const char* const _composite =
216 "varying vec2 texCoord;\n"
217 "uniform int scale;\n"
218 "uniform vec3 blend;\n"
219 "uniform sampler2D layer;\n"
220 "uniform sampler2D layerFlags;\n"
221 "uniform sampler2D oldLayer;\n"
222 "uniform sampler2D oldFlags;\n"
223 "out vec4 color;\n"
224 "out vec3 flags;\n"
225 "const vec3 flagCoeff = vec3(32., 8., 4.);\n"
226
227 "void main() {\n"
228 " vec4 pix = texelFetch(layer, ivec2(texCoord * scale), 0);\n"
229 " if (pix.a == 0) {\n"
230 " discard;\n"
231 " }\n"
232 " ivec3 inflags = ivec3(texelFetch(layerFlags, ivec2(texCoord * scale), 0).xyz * flagCoeff);\n"
233 " ivec3 oflags = ivec3(texelFetch(oldFlags, ivec2(texCoord * scale), 0).xyz * flagCoeff);\n"
234 " ivec3 outflags = ivec3(0, 0, 0);\n"
235 " if (inflags.x < oflags.x) {\n"
236 " outflags = inflags;\n"
237 " if (inflags.z == 1 && (inflags.y & 1) == 1 && (oflags.y & 2) == 2) {\n"
238 " vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n"
239 " pix *= blend.x;\n"
240 " pix += oldpix * blend.y;\n"
241 " }\n"
242 " } else {\n"
243 " outflags = oflags;\n"
244 " vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n"
245 " if (oflags.z == 1 && (oflags.y & 1) == 1 && (inflags.y & 2) == 2) {\n"
246 " pix *= blend.y;\n"
247 " pix += oldpix * blend.x;\n"
248 " } else {\n"
249 " pix = oldpix;\n"
250 " }\n"
251 " }\n"
252 " color = pix;\n"
253 " flags = outflags / flagCoeff;\n"
254 "}";
255
256static const GLint _vertices[] = {
257 0, 0,
258 0, 1,
259 1, 1,
260 1, 0,
261};
262
263void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) {
264 renderer->d.init = GBAVideoGLRendererInit;
265 renderer->d.reset = GBAVideoGLRendererReset;
266 renderer->d.deinit = GBAVideoGLRendererDeinit;
267 renderer->d.writeVideoRegister = GBAVideoGLRendererWriteVideoRegister;
268 renderer->d.writeVRAM = GBAVideoGLRendererWriteVRAM;
269 renderer->d.writeOAM = GBAVideoGLRendererWriteOAM;
270 renderer->d.writePalette = GBAVideoGLRendererWritePalette;
271 renderer->d.drawScanline = GBAVideoGLRendererDrawScanline;
272 renderer->d.finishFrame = GBAVideoGLRendererFinishFrame;
273 renderer->d.getPixels = GBAVideoGLRendererGetPixels;
274 renderer->d.putPixels = GBAVideoGLRendererPutPixels;
275
276 renderer->d.disableBG[0] = false;
277 renderer->d.disableBG[1] = false;
278 renderer->d.disableBG[2] = false;
279 renderer->d.disableBG[3] = false;
280 renderer->d.disableOBJ = false;
281
282 renderer->scale = 1;
283}
284
285void _compileShader(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) {
286 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
287 glAttachShader(program, vs);
288 glAttachShader(program, fs);
289 glShaderSource(fs, shaderBufferLines, shaderBuffer, 0);
290 glCompileShader(fs);
291 glGetShaderInfoLog(fs, 1024, 0, log);
292 if (log[0]) {
293 mLOG(GBA_VIDEO, ERROR, "Fragment shader compilation failure: %s", log);
294 }
295 glLinkProgram(program);
296 glGetProgramInfoLog(program, 1024, 0, log);
297 if (log[0]) {
298 mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log);
299 }
300 glDeleteShader(fs);
301 glBindFragDataLocation(program, 0, "color");
302 glBindFragDataLocation(program, 1, "flags");
303}
304
305void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
306 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
307 glGenFramebuffers(2, glRenderer->fbo);
308 glGenTextures(3, glRenderer->layers);
309
310 glGenTextures(1, &glRenderer->paletteTex);
311 glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
313 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
314
315 glGenTextures(1, &glRenderer->vramTex);
316 glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex);
317 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
318 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
319 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 256, 192, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0);
320
321 glGenTextures(1, &glRenderer->oamTex);
322 glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex);
323 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
324 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
325
326 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
327 glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR]);
328 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
329 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
330 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
331 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
332 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
333 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], 0);
334
335 glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS]);
336 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
337 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
338 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
339 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
340 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
341 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], 0);
342
343 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]);
344 glBindTexture(GL_TEXTURE_2D, glRenderer->outputTex);
345 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
346 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
347 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
348 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
349 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
350 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->outputTex, 0);
351
352 glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]);
353 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
354 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
355 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
356 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
357 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
358 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS], 0);
359
360 glBindFramebuffer(GL_FRAMEBUFFER, 0);
361
362 int i;
363 for (i = 0; i < 4; ++i) {
364 glRenderer->bg[i].index = i;
365 glGenFramebuffers(1, &glRenderer->bg[i].fbo);
366 glGenTextures(1, &glRenderer->bg[i].tex);
367 glGenTextures(1, &glRenderer->bg[i].flags);
368 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo);
369
370 glBindTexture(GL_TEXTURE_2D, glRenderer->bg[i].tex);
371 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
372 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
373 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
374 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
375 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
376 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->bg[i].tex, 0);
377
378 glBindTexture(GL_TEXTURE_2D, glRenderer->bg[i].flags);
379 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
380 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
381 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
382 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
383 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
384 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->bg[i].flags, 0);
385
386 glBindFramebuffer(GL_FRAMEBUFFER, 0);
387 }
388
389 glRenderer->compositeProgram = glCreateProgram();
390 glRenderer->objProgram[0] = glCreateProgram();
391 glRenderer->objProgram[1] = glCreateProgram();
392 glRenderer->bgProgram[0] = glCreateProgram();
393 glRenderer->bgProgram[1] = glCreateProgram();
394 glRenderer->bgProgram[2] = glCreateProgram();
395 glRenderer->bgProgram[3] = glCreateProgram();
396 glRenderer->bgProgram[4] = glCreateProgram();
397 glRenderer->bgProgram[5] = glCreateProgram();
398
399 char log[1024];
400 const GLchar* shaderBuffer[8];
401 shaderBuffer[0] = _gl3Header;
402
403 GLuint vs = glCreateShader(GL_VERTEX_SHADER);
404 shaderBuffer[1] = _vertexShader;
405 glShaderSource(vs, 2, shaderBuffer, 0);
406 glCompileShader(vs);
407 glGetShaderInfoLog(vs, 1024, 0, log);
408 if (log[0]) {
409 mLOG(GBA_VIDEO, ERROR, "Vertex shader compilation failure: %s", log);
410 }
411
412 shaderBuffer[1] = _renderMode0;
413
414 shaderBuffer[2] = _renderTile16;
415 _compileShader(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log);
416
417 shaderBuffer[2] = _renderTile256;
418 _compileShader(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log);
419
420 shaderBuffer[1] = _renderMode2;
421
422 shaderBuffer[2] = _fetchTileOverflow;
423 _compileShader(glRenderer, glRenderer->bgProgram[2], shaderBuffer, 3, vs, log);
424
425 shaderBuffer[2] = _fetchTileNoOverflow;
426 _compileShader(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log);
427
428 shaderBuffer[1] = _renderObj;
429
430 shaderBuffer[2] = _renderTile16;
431 _compileShader(glRenderer, glRenderer->objProgram[0], shaderBuffer, 3, vs, log);
432
433 shaderBuffer[2] = _renderTile256;
434 _compileShader(glRenderer, glRenderer->objProgram[1], shaderBuffer, 3, vs, log);
435
436 shaderBuffer[1] = _composite;
437 _compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log);
438
439 glDeleteShader(vs);
440
441 GBAVideoGLRendererReset(renderer);
442}
443
444void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) {
445 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
446 glDeleteFramebuffers(2, glRenderer->fbo);
447 glDeleteTextures(3, glRenderer->layers);
448 glDeleteTextures(1, &glRenderer->paletteTex);
449 glDeleteTextures(1, &glRenderer->vramTex);
450 glDeleteTextures(1, &glRenderer->oamTex);
451
452 glDeleteProgram(glRenderer->bgProgram[0]);
453 glDeleteProgram(glRenderer->bgProgram[1]);
454 glDeleteProgram(glRenderer->bgProgram[2]);
455 glDeleteProgram(glRenderer->bgProgram[3]);
456 glDeleteProgram(glRenderer->bgProgram[4]);
457 glDeleteProgram(glRenderer->bgProgram[5]);
458 glDeleteProgram(glRenderer->bgProgram[6]);
459 glDeleteProgram(glRenderer->objProgram[0]);
460 glDeleteProgram(glRenderer->objProgram[1]);
461 glDeleteProgram(glRenderer->compositeProgram);
462}
463
464void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
465 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
466
467 glRenderer->paletteDirty = true;
468 glRenderer->vramDirty = 0xFFFFFF;
469 glRenderer->firstAffine = -1;
470}
471
472void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
473 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
474 glRenderer->vramDirty |= 1 << (address >> 12);
475}
476
477void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
478 UNUSED(oam);
479 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
480 glRenderer->oamDirty = true;
481}
482
483void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
484 UNUSED(address);
485 UNUSED(value);
486 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
487 glRenderer->paletteDirty = true;
488}
489
490uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
491 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
492 if (renderer->cache) {
493 GBAVideoCacheWriteVideoRegister(renderer->cache, address, value);
494 }
495
496 switch (address) {
497 case REG_DISPCNT:
498 value &= 0xFFF7;
499 glRenderer->dispcnt = value;
500 GBAVideoGLRendererUpdateDISPCNT(glRenderer);
501 break;
502 case REG_BG0CNT:
503 value &= 0xDFFF;
504 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[0], value);
505 break;
506 case REG_BG1CNT:
507 value &= 0xDFFF;
508 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[1], value);
509 break;
510 case REG_BG2CNT:
511 value &= 0xFFFF;
512 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[2], value);
513 break;
514 case REG_BG3CNT:
515 value &= 0xFFFF;
516 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[3], value);
517 break;
518 case REG_BG0HOFS:
519 value &= 0x01FF;
520 glRenderer->bg[0].x = value;
521 break;
522 case REG_BG0VOFS:
523 value &= 0x01FF;
524 glRenderer->bg[0].y = value;
525 break;
526 case REG_BG1HOFS:
527 value &= 0x01FF;
528 glRenderer->bg[1].x = value;
529 break;
530 case REG_BG1VOFS:
531 value &= 0x01FF;
532 glRenderer->bg[1].y = value;
533 break;
534 case REG_BG2HOFS:
535 value &= 0x01FF;
536 glRenderer->bg[2].x = value;
537 break;
538 case REG_BG2VOFS:
539 value &= 0x01FF;
540 glRenderer->bg[2].y = value;
541 break;
542 case REG_BG3HOFS:
543 value &= 0x01FF;
544 glRenderer->bg[3].x = value;
545 break;
546 case REG_BG3VOFS:
547 value &= 0x01FF;
548 glRenderer->bg[3].y = value;
549 break;
550 case REG_BG2PA:
551 glRenderer->bg[2].affine[0].dx = value;
552 break;
553 case REG_BG2PB:
554 glRenderer->bg[2].affine[0].dmx = value;
555 break;
556 case REG_BG2PC:
557 glRenderer->bg[2].affine[0].dy = value;
558 break;
559 case REG_BG2PD:
560 glRenderer->bg[2].affine[0].dmy = value;
561 break;
562 case REG_BG2X_LO:
563 GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value);
564 break;
565 case REG_BG2X_HI:
566 GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[2], value);
567 break;
568 case REG_BG2Y_LO:
569 GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[2], value);
570 break;
571 case REG_BG2Y_HI:
572 GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value);
573 break;
574 case REG_BG3PA:
575 glRenderer->bg[3].affine[0].dx = value;
576 break;
577 case REG_BG3PB:
578 glRenderer->bg[3].affine[0].dmx = value;
579 break;
580 case REG_BG3PC:
581 glRenderer->bg[3].affine[0].dy = value;
582 break;
583 case REG_BG3PD:
584 glRenderer->bg[3].affine[0].dmy = value;
585 break;
586 case REG_BG3X_LO:
587 GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value);
588 break;
589 case REG_BG3X_HI:
590 GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[3], value);
591 break;
592 case REG_BG3Y_LO:
593 GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[3], value);
594 break;
595 case REG_BG3Y_HI:
596 GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[3], value);
597 break;
598 case REG_BLDCNT:
599 GBAVideoGLRendererWriteBLDCNT(glRenderer, value);
600 value &= 0x3FFF;
601 break;
602 case REG_BLDALPHA:
603 glRenderer->blda = value & 0x1F;
604 if (glRenderer->blda > 0x10) {
605 glRenderer->blda = 0x10;
606 }
607 glRenderer->bldb = (value >> 8) & 0x1F;
608 if (glRenderer->bldb > 0x10) {
609 glRenderer->bldb = 0x10;
610 }
611 value &= 0x1F1F;
612 break;
613 case REG_BLDY:
614 value &= 0x1F;
615 if (value > 0x10) {
616 value = 0x10;
617 }
618 if (glRenderer->bldy != value) {
619 glRenderer->bldy = value;
620 }
621 break;
622 case REG_WIN0H:
623 /*glRenderer->winN[0].h.end = value;
624 glRenderer->winN[0].h.start = value >> 8;
625 if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[0].h.start > glRenderer->winN[0].h.end) {
626 glRenderer->winN[0].h.start = 0;
627 }
628 if (glRenderer->winN[0].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) {
629 glRenderer->winN[0].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;
630 if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) {
631 glRenderer->winN[0].h.start = GBA_VIDEO_HORIZONTAL_PIXELS;
632 }
633 }*/
634 break;
635 case REG_WIN1H:
636 /*glRenderer->winN[1].h.end = value;
637 glRenderer->winN[1].h.start = value >> 8;
638 if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[1].h.start > glRenderer->winN[1].h.end) {
639 glRenderer->winN[1].h.start = 0;
640 }
641 if (glRenderer->winN[1].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) {
642 glRenderer->winN[1].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;
643 if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) {
644 glRenderer->winN[1].h.start = GBA_VIDEO_HORIZONTAL_PIXELS;
645 }
646 }*/
647 break;
648 case REG_WIN0V:
649 /*glRenderer->winN[0].v.end = value;
650 glRenderer->winN[0].v.start = value >> 8;
651 if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[0].v.start > glRenderer->winN[0].v.end) {
652 glRenderer->winN[0].v.start = 0;
653 }
654 if (glRenderer->winN[0].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
655 glRenderer->winN[0].v.end = GBA_VIDEO_VERTICAL_PIXELS;
656 if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
657 glRenderer->winN[0].v.start = GBA_VIDEO_VERTICAL_PIXELS;
658 }
659 }*/
660 break;
661 case REG_WIN1V:
662 /*glRenderer->winN[1].v.end = value;
663 glRenderer->winN[1].v.start = value >> 8;
664 if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[1].v.start > glRenderer->winN[1].v.end) {
665 glRenderer->winN[1].v.start = 0;
666 }
667 if (glRenderer->winN[1].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
668 glRenderer->winN[1].v.end = GBA_VIDEO_VERTICAL_PIXELS;
669 if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
670 glRenderer->winN[1].v.start = GBA_VIDEO_VERTICAL_PIXELS;
671 }
672 }*/
673 break;
674 case REG_WININ:
675 value &= 0x3F3F;
676 //glRenderer->winN[0].control.packed = value;
677 //glRenderer->winN[1].control.packed = value >> 8;
678 break;
679 case REG_WINOUT:
680 value &= 0x3F3F;
681 //glRenderer->winout.packed = value;
682 //glRenderer->objwin.packed = value >> 8;
683 break;
684 case REG_MOSAIC:
685 glRenderer->mosaic = value;
686 break;
687 case REG_GREENSWP:
688 mLOG(GBA_VIDEO, STUB, "Stub video register write: 0x%03X", address);
689 break;
690 default:
691 mLOG(GBA_VIDEO, GAME_ERROR, "Invalid video register: 0x%03X", address);
692 }
693 return value;
694}
695
696void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
697 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
698 if (glRenderer->paletteDirty) {
699 glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
700 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette);
701 glRenderer->paletteDirty = false;
702 }
703 int i;
704 for (i = 0; i < 24; ++i) {
705 if (!(glRenderer->vramDirty & (1 << i))) {
706 continue;
707 }
708 // TODO: PBOs
709 glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex);
710 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 8 * i, 256, 8, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, &glRenderer->d.vram[2048 * i]);
711 }
712 glRenderer->vramDirty = 0;
713
714 uint32_t backdrop = M_RGB5_TO_RGB8(renderer->palette[0]);
715 glClearColor(((backdrop >> 16) & 0xFF) / 256., ((backdrop >> 8) & 0xFF) / 256., (backdrop & 0xFF) / 256., 0.f);
716 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]);
717 glEnable(GL_SCISSOR_TEST);
718 glScissor(0, y * glRenderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, glRenderer->scale);
719 glDrawBuffer(GL_COLOR_ATTACHMENT0);
720 glClear(GL_COLOR_BUFFER_BIT);
721 if (y == 0) {
722 glDisable(GL_SCISSOR_TEST);
723 glDrawBuffer(GL_COLOR_ATTACHMENT1);
724 glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2)) / 8.f, 0, 1);
725 glClear(GL_COLOR_BUFFER_BIT);
726
727 glClearColor(0, 0, 0, 0);
728 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
729 glDrawBuffer(GL_COLOR_ATTACHMENT0);
730 glClear(GL_COLOR_BUFFER_BIT);
731 glDrawBuffer(GL_COLOR_ATTACHMENT1);
732 glClear(GL_COLOR_BUFFER_BIT);
733
734 for (i = 0; i < 4; ++i) {
735 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo);
736 glDrawBuffer(GL_COLOR_ATTACHMENT0);
737 glClear(GL_COLOR_BUFFER_BIT);
738 glDrawBuffer(GL_COLOR_ATTACHMENT1);
739 glClear(GL_COLOR_BUFFER_BIT);
740 }
741 glDrawBuffer(GL_COLOR_ATTACHMENT0);
742 glEnable(GL_SCISSOR_TEST);
743 }
744 glBindFramebuffer(GL_FRAMEBUFFER, 0);
745
746 if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
747 if (glRenderer->firstAffine < 0) {
748 memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
749 memcpy(&glRenderer->bg[3].affine[3], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
750 memcpy(&glRenderer->bg[2].affine[2], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
751 memcpy(&glRenderer->bg[3].affine[2], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
752 memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
753 memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
754 glRenderer->firstAffine = y;
755 } else if (y - glRenderer->firstAffine == 1) {
756 memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
757 memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
758 }
759 } else {
760 glRenderer->firstAffine = -1;
761 }
762
763 int spriteLayers = 0;
764 if (GBARegisterDISPCNTIsObjEnable(glRenderer->dispcnt) && !glRenderer->d.disableOBJ) {
765 if (glRenderer->oamDirty) {
766 glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex);
767 glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 4, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, glRenderer->d.oam);
768 glRenderer->oamMax = GBAVideoRendererCleanOAM(glRenderer->d.oam->obj, glRenderer->sprites, 0);
769 glRenderer->oamDirty = false;
770 }
771 int i;
772 for (i = glRenderer->oamMax; i--;) {
773 struct GBAVideoRendererSprite* sprite = &glRenderer->sprites[i];
774 if ((y < sprite->y && (sprite->endY - 256 < 0 || y >= sprite->endY - 256)) || y >= sprite->endY) {
775 continue;
776 }
777
778 GBAVideoGLRendererDrawSprite(glRenderer, &sprite->obj, y, sprite->y);
779 spriteLayers |= 1 << GBAObjAttributesCGetPriority(sprite->obj.c);
780 }
781 }
782
783 _compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], y);
784 unsigned priority;
785 for (priority = 4; priority--;) {
786 if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
787 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[0], y);
788 }
789 if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
790 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[1], y);
791 }
792 if (TEST_LAYER_ENABLED(2)) {
793 switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
794 case 0:
795 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[2], y);
796 break;
797 case 1:
798 case 2:
799 GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[2], y);
800 break;
801 case 3:
802 //GBAVideoGLRendererDrawBackgroundMode3(glRenderer, &glRenderer->bg[2], y);
803 break;
804 case 4:
805 //GBAVideoGLRendererDrawBackgroundMode4(glRenderer, &glRenderer->bg[2], y);
806 break;
807 case 5:
808 //GBAVideoGLRendererDrawBackgroundMode5(glRenderer, &glRenderer->bg[2], y);
809 break;
810 }
811 }
812 if (TEST_LAYER_ENABLED(3)) {
813 switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
814 case 0:
815 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[3], y);
816 break;
817 case 2:
818 GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[3], y);
819 break;
820 }
821 }
822 }
823
824 if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
825 memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[2], sizeof(struct GBAVideoGLAffine));
826 memcpy(&glRenderer->bg[3].affine[3], &glRenderer->bg[3].affine[2], sizeof(struct GBAVideoGLAffine));
827 memcpy(&glRenderer->bg[2].affine[2], &glRenderer->bg[2].affine[1], sizeof(struct GBAVideoGLAffine));
828 memcpy(&glRenderer->bg[3].affine[2], &glRenderer->bg[3].affine[1], sizeof(struct GBAVideoGLAffine));
829 memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
830 memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
831
832 glRenderer->bg[2].affine[0].sx += glRenderer->bg[2].affine[0].dmx;
833 glRenderer->bg[2].affine[0].sy += glRenderer->bg[2].affine[0].dmy;
834 glRenderer->bg[3].affine[0].sx += glRenderer->bg[3].affine[0].dmx;
835 glRenderer->bg[3].affine[0].sy += glRenderer->bg[3].affine[0].dmy;
836 }
837}
838
839void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) {
840 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
841 glRenderer->firstAffine = -1;
842 glRenderer->bg[2].affine[0].sx = glRenderer->bg[2].refx;
843 glRenderer->bg[2].affine[0].sy = glRenderer->bg[2].refy;
844 glRenderer->bg[3].affine[0].sx = glRenderer->bg[3].refx;
845 glRenderer->bg[3].affine[0].sy = glRenderer->bg[3].refy;
846 glFlush();
847}
848
849void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
850
851}
852
853void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
854
855}
856
857static void _enableBg(struct GBAVideoGLRenderer* renderer, int bg, bool active) {
858 int wasActive = renderer->bg[bg].enabled;
859 if (!active) {
860 renderer->bg[bg].enabled = 0;
861 } else if (!wasActive && active) {
862 /*if (renderer->nextY == 0 || GBARegisterDISPCNTGetMode(renderer->dispcnt) > 2) {
863 // TODO: Investigate in more depth how switching background works in different modes
864 renderer->bg[bg].enabled = 4;
865 } else {
866 renderer->bg[bg].enabled = 1;
867 }*/
868 renderer->bg[bg].enabled = 4;
869 }
870}
871
872static void GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer* renderer) {
873 _enableBg(renderer, 0, GBARegisterDISPCNTGetBg0Enable(renderer->dispcnt));
874 _enableBg(renderer, 1, GBARegisterDISPCNTGetBg1Enable(renderer->dispcnt));
875 _enableBg(renderer, 2, GBARegisterDISPCNTGetBg2Enable(renderer->dispcnt));
876 _enableBg(renderer, 3, GBARegisterDISPCNTGetBg3Enable(renderer->dispcnt));
877}
878
879static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value) {
880 bg->priority = GBARegisterBGCNTGetPriority(value);
881 bg->charBase = GBARegisterBGCNTGetCharBase(value) << 13;
882 bg->mosaic = GBARegisterBGCNTGetMosaic(value);
883 bg->multipalette = GBARegisterBGCNTGet256Color(value);
884 bg->screenBase = GBARegisterBGCNTGetScreenBase(value) << 10;
885 bg->overflow = GBARegisterBGCNTGetOverflow(value);
886 bg->size = GBARegisterBGCNTGetSize(value);
887}
888
889static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
890 bg->refx = (bg->refx & 0xFFFF0000) | value;
891 bg->affine[0].sx = bg->refx;
892}
893
894static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
895 bg->refx = (bg->refx & 0x0000FFFF) | (value << 16);
896 bg->refx <<= 4;
897 bg->refx >>= 4;
898 bg->affine[0].sx = bg->refx;
899}
900
901static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
902 bg->refy = (bg->refy & 0xFFFF0000) | value;
903 bg->affine[0].sy = bg->refy;
904}
905
906static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
907 bg->refy = (bg->refy & 0x0000FFFF) | (value << 16);
908 bg->refy <<= 4;
909 bg->refy >>= 4;
910 bg->affine[0].sy = bg->refy;
911}
912
913static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value) {
914 renderer->bg[0].target1 = GBARegisterBLDCNTGetTarget1Bg0(value);
915 renderer->bg[1].target1 = GBARegisterBLDCNTGetTarget1Bg1(value);
916 renderer->bg[2].target1 = GBARegisterBLDCNTGetTarget1Bg2(value);
917 renderer->bg[3].target1 = GBARegisterBLDCNTGetTarget1Bg3(value);
918 renderer->bg[0].target2 = GBARegisterBLDCNTGetTarget2Bg0(value);
919 renderer->bg[1].target2 = GBARegisterBLDCNTGetTarget2Bg1(value);
920 renderer->bg[2].target2 = GBARegisterBLDCNTGetTarget2Bg2(value);
921 renderer->bg[3].target2 = GBARegisterBLDCNTGetTarget2Bg3(value);
922
923 renderer->blendEffect = GBARegisterBLDCNTGetEffect(value);
924 renderer->target1Obj = GBARegisterBLDCNTGetTarget1Obj(value);
925 renderer->target1Bd = GBARegisterBLDCNTGetTarget1Bd(value);
926 renderer->target2Obj = GBARegisterBLDCNTGetTarget2Obj(value);
927 renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value);
928}
929
930static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int y) {
931 if ((y & 0x1F) != 0x1F) {
932 return;
933 }
934 glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_COMPOSITE]);
935 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
936 glScissor(0, (y & ~0x1F) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale);
937 glUseProgram(renderer->compositeProgram);
938 glActiveTexture(GL_TEXTURE0);
939 glBindTexture(GL_TEXTURE_2D, tex);
940 glActiveTexture(GL_TEXTURE0 + 1);
941 glBindTexture(GL_TEXTURE_2D, flags);
942 glActiveTexture(GL_TEXTURE0 + 2);
943 glBindTexture(GL_TEXTURE_2D, renderer->outputTex);
944 glActiveTexture(GL_TEXTURE0 + 3);
945 glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]);
946 glUniform2i(0, 0x20, y & ~0x1F);
947 glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
948 glUniform1i(2, renderer->scale);
949 glUniform3f(3, renderer->blda / 16.f, renderer->bldb / 16.f, renderer->bldy / 16.f);
950 glUniform1i(4, 0);
951 glUniform1i(5, 1);
952 glUniform1i(6, 2);
953 glUniform1i(7, 3);
954 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
955 glEnableVertexAttribArray(0);
956 glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
957 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
958 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
959 glBindFramebuffer(GL_FRAMEBUFFER, 0);
960}
961
962void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY) {
963 int width = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][0];
964 int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][1];
965 int32_t x = (uint32_t) GBAObjAttributesBGetX(sprite->b) << 23;
966 x >>= 23;
967
968 int align = GBAObjAttributesAIs256Color(sprite->a) && !GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt);
969 unsigned charBase = (BASE_TILE >> 1) + (GBAObjAttributesCGetTile(sprite->c) & ~align) * 0x10;
970 int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x40 >> !GBAObjAttributesAIs256Color(sprite->a));
971
972 if (spriteY + height >= 256) {
973 spriteY -= 256;
974 }
975
976 if (!GBAObjAttributesAIsTransformed(sprite->a) && GBAObjAttributesBIsVFlip(sprite->b)) {
977 spriteY = (y - height) + (y - spriteY) + 1;
978 }
979
980 int totalWidth = width;
981 int totalHeight = height;
982 if (GBAObjAttributesAIsTransformed(sprite->a) && GBAObjAttributesAIsDoubleSize(sprite->a)) {
983 totalWidth <<= 1;
984 totalHeight <<= 1;
985 }
986
987 glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]);
988 glViewport(x * renderer->scale, spriteY * renderer->scale, totalWidth * renderer->scale, totalHeight * renderer->scale);
989 glScissor(x * renderer->scale, y * renderer->scale, totalWidth * renderer->scale, renderer->scale);
990 glUseProgram(renderer->objProgram[GBAObjAttributesAGet256Color(sprite->a)]);
991 glActiveTexture(GL_TEXTURE0);
992 glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
993 glActiveTexture(GL_TEXTURE0 + 1);
994 glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
995 glUniform2i(0, 1, y - spriteY);
996 glUniform2i(1, (GBAObjAttributesBIsHFlip(sprite->b) && !GBAObjAttributesAIsTransformed(sprite->a)) ? -totalWidth : totalWidth, totalHeight);
997 glUniform1i(2, 0);
998 glUniform1i(3, 1);
999 glUniform1i(4, charBase);
1000 glUniform1i(5, stride);
1001 glUniform1i(6, GBAObjAttributesCGetPalette(sprite->c));
1002 glUniform3i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, (renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) | (renderer->target2Obj * 2), GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT ? BLEND_ALPHA : renderer->blendEffect);
1003 if (GBAObjAttributesAIsTransformed(sprite->a)) {
1004 struct GBAOAMMatrix mat;
1005 LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a);
1006 LOAD_16(mat.b, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].b);
1007 LOAD_16(mat.c, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].c);
1008 LOAD_16(mat.d, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].d);
1009
1010 glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { mat.a / 256.f, mat.c / 256.f, mat.b / 256.f, mat.d / 256.f });
1011 } else {
1012 glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { 1.f, 0, 0, 1.f });
1013 }
1014 glUniform4i(9, width, height, totalWidth, totalHeight);
1015 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
1016 glEnableVertexAttribArray(0);
1017 glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
1018 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1019 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1020}
1021
1022void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1023 int inY = y + background->y;
1024 int yBase = inY & 0xFF;
1025 if (background->size == 2) {
1026 yBase += inY & 0x100;
1027 } else if (background->size == 3) {
1028 yBase += (inY & 0x100) << 1;
1029 }
1030 glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
1031 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1032 glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale);
1033 glUseProgram(renderer->bgProgram[background->multipalette ? 1 : 0]);
1034 glActiveTexture(GL_TEXTURE0);
1035 glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
1036 glActiveTexture(GL_TEXTURE0 + 1);
1037 glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
1038 glUniform2i(0, 1, y);
1039 glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1040 glUniform1i(2, 0);
1041 glUniform1i(3, 1);
1042 glUniform1i(4, background->screenBase);
1043 glUniform1i(5, background->charBase);
1044 glUniform1i(6, background->size);
1045 glUniform2i(7, background->x, yBase - y);
1046 glUniform3i(8, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2), renderer->blendEffect);
1047 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
1048 glEnableVertexAttribArray(0);
1049 glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
1050 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1051 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1052
1053 _compositeLayer(renderer, background->tex, background->flags, y);
1054}
1055
1056void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1057 glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
1058 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1059 glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale);
1060 glUseProgram(renderer->bgProgram[background->overflow ? 2 : 3]);
1061 glActiveTexture(GL_TEXTURE0);
1062 glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
1063 glActiveTexture(GL_TEXTURE0 + 1);
1064 glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
1065 glUniform2i(0, 1, y);
1066 glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1067 glUniform1i(2, 0);
1068 glUniform1i(3, 1);
1069 glUniform1i(4, background->screenBase);
1070 glUniform1i(5, background->charBase);
1071 glUniform1i(6, background->size);
1072 glUniform3i(7, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2), renderer->blendEffect);
1073 if (renderer->scale > 1) {
1074 glUniform2iv(8, 4, (GLint[]) {
1075 background->affine[0].sx, background->affine[0].sy,
1076 background->affine[1].sx, background->affine[1].sy,
1077 background->affine[2].sx, background->affine[2].sy,
1078 background->affine[3].sx, background->affine[3].sy,
1079 });
1080 glUniform2iv(12, 4, (GLint[]) {
1081 background->affine[0].dx, background->affine[0].dy,
1082 background->affine[1].dx, background->affine[1].dy,
1083 background->affine[2].dx, background->affine[2].dy,
1084 background->affine[3].dx, background->affine[3].dy,
1085 });
1086 } else {
1087 glUniform2iv(8, 4, (GLint[]) {
1088 background->affine[0].sx, background->affine[0].sy,
1089 background->affine[0].sx, background->affine[0].sy,
1090 background->affine[0].sx, background->affine[0].sy,
1091 background->affine[0].sx, background->affine[0].sy,
1092 });
1093 glUniform2iv(12, 4, (GLint[]) {
1094 background->affine[0].dx, background->affine[0].dy,
1095 background->affine[0].dx, background->affine[0].dy,
1096 background->affine[0].dx, background->affine[0].dy,
1097 background->affine[0].dx, background->affine[0].dy,
1098 });
1099 }
1100 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
1101 glEnableVertexAttribArray(0);
1102 glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
1103 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1104 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1105
1106 _compositeLayer(renderer, background->tex, background->flags, y);
1107}