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 " pix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n"
244 " outflags = oflags;\n"
245 " }\n"
246 " color = pix;\n"
247 " flags = outflags / flagCoeff;\n"
248 "}";
249
250static const GLint _vertices[] = {
251 0, 0,
252 0, 1,
253 1, 1,
254 1, 0,
255};
256
257void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) {
258 renderer->d.init = GBAVideoGLRendererInit;
259 renderer->d.reset = GBAVideoGLRendererReset;
260 renderer->d.deinit = GBAVideoGLRendererDeinit;
261 renderer->d.writeVideoRegister = GBAVideoGLRendererWriteVideoRegister;
262 renderer->d.writeVRAM = GBAVideoGLRendererWriteVRAM;
263 renderer->d.writeOAM = GBAVideoGLRendererWriteOAM;
264 renderer->d.writePalette = GBAVideoGLRendererWritePalette;
265 renderer->d.drawScanline = GBAVideoGLRendererDrawScanline;
266 renderer->d.finishFrame = GBAVideoGLRendererFinishFrame;
267 renderer->d.getPixels = GBAVideoGLRendererGetPixels;
268 renderer->d.putPixels = GBAVideoGLRendererPutPixels;
269
270 renderer->d.disableBG[0] = false;
271 renderer->d.disableBG[1] = false;
272 renderer->d.disableBG[2] = false;
273 renderer->d.disableBG[3] = false;
274 renderer->d.disableOBJ = false;
275
276 renderer->scale = 1;
277}
278
279void _compileShader(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) {
280 GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
281 glAttachShader(program, vs);
282 glAttachShader(program, fs);
283 glShaderSource(fs, shaderBufferLines, shaderBuffer, 0);
284 glCompileShader(fs);
285 glGetShaderInfoLog(fs, 1024, 0, log);
286 if (log[0]) {
287 mLOG(GBA_VIDEO, ERROR, "Fragment shader compilation failure: %s", log);
288 }
289 glLinkProgram(program);
290 glGetProgramInfoLog(program, 1024, 0, log);
291 if (log[0]) {
292 mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log);
293 }
294 glDeleteShader(fs);
295 glBindFragDataLocation(program, 0, "color");
296 glBindFragDataLocation(program, 1, "flags");
297}
298
299void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
300 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
301 glGenFramebuffers(2, glRenderer->fbo);
302 glGenTextures(3, glRenderer->layers);
303
304 glGenTextures(1, &glRenderer->paletteTex);
305 glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
306 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
307 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
308
309 glGenTextures(1, &glRenderer->vramTex);
310 glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex);
311 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
313 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 256, 192, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0);
314
315 glGenTextures(1, &glRenderer->oamTex);
316 glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex);
317 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
318 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
319
320 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
321 glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR]);
322 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
323 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
324 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
325 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
326 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);
327 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], 0);
328
329 glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS]);
330 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
331 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
332 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
333 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
334 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);
335 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], 0);
336
337 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]);
338 glBindTexture(GL_TEXTURE_2D, glRenderer->outputTex);
339 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
340 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
341 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
342 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
343 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);
344 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->outputTex, 0);
345
346 glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]);
347 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
348 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
349 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
350 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
351 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);
352 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS], 0);
353
354 glBindFramebuffer(GL_FRAMEBUFFER, 0);
355
356 int i;
357 for (i = 0; i < 4; ++i) {
358 glRenderer->bg[i].index = i;
359 glGenFramebuffers(1, &glRenderer->bg[i].fbo);
360 glGenTextures(1, &glRenderer->bg[i].tex);
361 glGenTextures(1, &glRenderer->bg[i].flags);
362 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo);
363
364 glBindTexture(GL_TEXTURE_2D, glRenderer->bg[i].tex);
365 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
367 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
369 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);
370 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->bg[i].tex, 0);
371
372 glBindTexture(GL_TEXTURE_2D, glRenderer->bg[i].flags);
373 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
374 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
375 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
376 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
377 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);
378 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->bg[i].flags, 0);
379
380 glBindFramebuffer(GL_FRAMEBUFFER, 0);
381 }
382
383 glRenderer->compositeProgram = glCreateProgram();
384 glRenderer->objProgram[0] = glCreateProgram();
385 glRenderer->objProgram[1] = glCreateProgram();
386 glRenderer->bgProgram[0] = glCreateProgram();
387 glRenderer->bgProgram[1] = glCreateProgram();
388 glRenderer->bgProgram[2] = glCreateProgram();
389 glRenderer->bgProgram[3] = glCreateProgram();
390 glRenderer->bgProgram[4] = glCreateProgram();
391 glRenderer->bgProgram[5] = glCreateProgram();
392
393 char log[1024];
394 const GLchar* shaderBuffer[8];
395 shaderBuffer[0] = _gl3Header;
396
397 GLuint vs = glCreateShader(GL_VERTEX_SHADER);
398 shaderBuffer[1] = _vertexShader;
399 glShaderSource(vs, 2, shaderBuffer, 0);
400 glCompileShader(vs);
401 glGetShaderInfoLog(vs, 1024, 0, log);
402 if (log[0]) {
403 mLOG(GBA_VIDEO, ERROR, "Vertex shader compilation failure: %s", log);
404 }
405
406 shaderBuffer[1] = _renderMode0;
407
408 shaderBuffer[2] = _renderTile16;
409 _compileShader(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log);
410
411 shaderBuffer[2] = _renderTile256;
412 _compileShader(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log);
413
414 shaderBuffer[1] = _renderMode2;
415
416 shaderBuffer[2] = _fetchTileOverflow;
417 _compileShader(glRenderer, glRenderer->bgProgram[2], shaderBuffer, 3, vs, log);
418
419 shaderBuffer[2] = _fetchTileNoOverflow;
420 _compileShader(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log);
421
422 shaderBuffer[1] = _renderObj;
423
424 shaderBuffer[2] = _renderTile16;
425 _compileShader(glRenderer, glRenderer->objProgram[0], shaderBuffer, 3, vs, log);
426
427 shaderBuffer[2] = _renderTile256;
428 _compileShader(glRenderer, glRenderer->objProgram[1], shaderBuffer, 3, vs, log);
429
430 shaderBuffer[1] = _composite;
431 _compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log);
432
433 glDeleteShader(vs);
434
435 GBAVideoGLRendererReset(renderer);
436}
437
438void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) {
439 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
440 glDeleteFramebuffers(2, glRenderer->fbo);
441 glDeleteTextures(3, glRenderer->layers);
442 glDeleteTextures(1, &glRenderer->paletteTex);
443 glDeleteTextures(1, &glRenderer->vramTex);
444 glDeleteTextures(1, &glRenderer->oamTex);
445
446 glDeleteProgram(glRenderer->bgProgram[0]);
447 glDeleteProgram(glRenderer->bgProgram[1]);
448 glDeleteProgram(glRenderer->bgProgram[2]);
449 glDeleteProgram(glRenderer->bgProgram[3]);
450 glDeleteProgram(glRenderer->bgProgram[4]);
451 glDeleteProgram(glRenderer->bgProgram[5]);
452 glDeleteProgram(glRenderer->bgProgram[6]);
453 glDeleteProgram(glRenderer->objProgram[0]);
454 glDeleteProgram(glRenderer->objProgram[1]);
455 glDeleteProgram(glRenderer->compositeProgram);
456}
457
458void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
459 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
460
461 glRenderer->paletteDirty = true;
462 glRenderer->vramDirty = 0xFFFFFF;
463 glRenderer->firstAffine = -1;
464}
465
466void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
467 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
468 glRenderer->vramDirty |= 1 << (address >> 12);
469}
470
471void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {
472 UNUSED(oam);
473 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
474 glRenderer->oamDirty = true;
475}
476
477void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
478 UNUSED(address);
479 UNUSED(value);
480 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
481 glRenderer->paletteDirty = true;
482}
483
484uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
485 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
486 if (renderer->cache) {
487 GBAVideoCacheWriteVideoRegister(renderer->cache, address, value);
488 }
489
490 switch (address) {
491 case REG_DISPCNT:
492 value &= 0xFFF7;
493 glRenderer->dispcnt = value;
494 GBAVideoGLRendererUpdateDISPCNT(glRenderer);
495 break;
496 case REG_BG0CNT:
497 value &= 0xDFFF;
498 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[0], value);
499 break;
500 case REG_BG1CNT:
501 value &= 0xDFFF;
502 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[1], value);
503 break;
504 case REG_BG2CNT:
505 value &= 0xFFFF;
506 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[2], value);
507 break;
508 case REG_BG3CNT:
509 value &= 0xFFFF;
510 GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[3], value);
511 break;
512 case REG_BG0HOFS:
513 value &= 0x01FF;
514 glRenderer->bg[0].x = value;
515 break;
516 case REG_BG0VOFS:
517 value &= 0x01FF;
518 glRenderer->bg[0].y = value;
519 break;
520 case REG_BG1HOFS:
521 value &= 0x01FF;
522 glRenderer->bg[1].x = value;
523 break;
524 case REG_BG1VOFS:
525 value &= 0x01FF;
526 glRenderer->bg[1].y = value;
527 break;
528 case REG_BG2HOFS:
529 value &= 0x01FF;
530 glRenderer->bg[2].x = value;
531 break;
532 case REG_BG2VOFS:
533 value &= 0x01FF;
534 glRenderer->bg[2].y = value;
535 break;
536 case REG_BG3HOFS:
537 value &= 0x01FF;
538 glRenderer->bg[3].x = value;
539 break;
540 case REG_BG3VOFS:
541 value &= 0x01FF;
542 glRenderer->bg[3].y = value;
543 break;
544 case REG_BG2PA:
545 glRenderer->bg[2].affine[0].dx = value;
546 break;
547 case REG_BG2PB:
548 glRenderer->bg[2].affine[0].dmx = value;
549 break;
550 case REG_BG2PC:
551 glRenderer->bg[2].affine[0].dy = value;
552 break;
553 case REG_BG2PD:
554 glRenderer->bg[2].affine[0].dmy = value;
555 break;
556 case REG_BG2X_LO:
557 GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value);
558 break;
559 case REG_BG2X_HI:
560 GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[2], value);
561 break;
562 case REG_BG2Y_LO:
563 GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[2], value);
564 break;
565 case REG_BG2Y_HI:
566 GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value);
567 break;
568 case REG_BG3PA:
569 glRenderer->bg[3].affine[0].dx = value;
570 break;
571 case REG_BG3PB:
572 glRenderer->bg[3].affine[0].dmx = value;
573 break;
574 case REG_BG3PC:
575 glRenderer->bg[3].affine[0].dy = value;
576 break;
577 case REG_BG3PD:
578 glRenderer->bg[3].affine[0].dmy = value;
579 break;
580 case REG_BG3X_LO:
581 GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value);
582 break;
583 case REG_BG3X_HI:
584 GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[3], value);
585 break;
586 case REG_BG3Y_LO:
587 GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[3], value);
588 break;
589 case REG_BG3Y_HI:
590 GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[3], value);
591 break;
592 case REG_BLDCNT:
593 GBAVideoGLRendererWriteBLDCNT(glRenderer, value);
594 value &= 0x3FFF;
595 break;
596 case REG_BLDALPHA:
597 glRenderer->blda = value & 0x1F;
598 if (glRenderer->blda > 0x10) {
599 glRenderer->blda = 0x10;
600 }
601 glRenderer->bldb = (value >> 8) & 0x1F;
602 if (glRenderer->bldb > 0x10) {
603 glRenderer->bldb = 0x10;
604 }
605 value &= 0x1F1F;
606 break;
607 case REG_BLDY:
608 value &= 0x1F;
609 if (value > 0x10) {
610 value = 0x10;
611 }
612 if (glRenderer->bldy != value) {
613 glRenderer->bldy = value;
614 }
615 break;
616 case REG_WIN0H:
617 /*glRenderer->winN[0].h.end = value;
618 glRenderer->winN[0].h.start = value >> 8;
619 if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[0].h.start > glRenderer->winN[0].h.end) {
620 glRenderer->winN[0].h.start = 0;
621 }
622 if (glRenderer->winN[0].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) {
623 glRenderer->winN[0].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;
624 if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) {
625 glRenderer->winN[0].h.start = GBA_VIDEO_HORIZONTAL_PIXELS;
626 }
627 }*/
628 break;
629 case REG_WIN1H:
630 /*glRenderer->winN[1].h.end = value;
631 glRenderer->winN[1].h.start = value >> 8;
632 if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[1].h.start > glRenderer->winN[1].h.end) {
633 glRenderer->winN[1].h.start = 0;
634 }
635 if (glRenderer->winN[1].h.end > GBA_VIDEO_HORIZONTAL_PIXELS) {
636 glRenderer->winN[1].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;
637 if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) {
638 glRenderer->winN[1].h.start = GBA_VIDEO_HORIZONTAL_PIXELS;
639 }
640 }*/
641 break;
642 case REG_WIN0V:
643 /*glRenderer->winN[0].v.end = value;
644 glRenderer->winN[0].v.start = value >> 8;
645 if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[0].v.start > glRenderer->winN[0].v.end) {
646 glRenderer->winN[0].v.start = 0;
647 }
648 if (glRenderer->winN[0].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
649 glRenderer->winN[0].v.end = GBA_VIDEO_VERTICAL_PIXELS;
650 if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
651 glRenderer->winN[0].v.start = GBA_VIDEO_VERTICAL_PIXELS;
652 }
653 }*/
654 break;
655 case REG_WIN1V:
656 /*glRenderer->winN[1].v.end = value;
657 glRenderer->winN[1].v.start = value >> 8;
658 if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[1].v.start > glRenderer->winN[1].v.end) {
659 glRenderer->winN[1].v.start = 0;
660 }
661 if (glRenderer->winN[1].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
662 glRenderer->winN[1].v.end = GBA_VIDEO_VERTICAL_PIXELS;
663 if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
664 glRenderer->winN[1].v.start = GBA_VIDEO_VERTICAL_PIXELS;
665 }
666 }*/
667 break;
668 case REG_WININ:
669 value &= 0x3F3F;
670 //glRenderer->winN[0].control.packed = value;
671 //glRenderer->winN[1].control.packed = value >> 8;
672 break;
673 case REG_WINOUT:
674 value &= 0x3F3F;
675 //glRenderer->winout.packed = value;
676 //glRenderer->objwin.packed = value >> 8;
677 break;
678 case REG_MOSAIC:
679 glRenderer->mosaic = value;
680 break;
681 case REG_GREENSWP:
682 mLOG(GBA_VIDEO, STUB, "Stub video register write: 0x%03X", address);
683 break;
684 default:
685 mLOG(GBA_VIDEO, GAME_ERROR, "Invalid video register: 0x%03X", address);
686 }
687 return value;
688}
689
690void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
691 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
692 if (glRenderer->paletteDirty) {
693 glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
694 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette);
695 glRenderer->paletteDirty = false;
696 }
697 int i;
698 for (i = 0; i < 24; ++i) {
699 if (!(glRenderer->vramDirty & (1 << i))) {
700 continue;
701 }
702 // TODO: PBOs
703 glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex);
704 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 8 * i, 256, 8, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, &glRenderer->d.vram[2048 * i]);
705 }
706 glRenderer->vramDirty = 0;
707
708 uint32_t backdrop = M_RGB5_TO_RGB8(renderer->palette[0]);
709 glClearColor(((backdrop >> 16) & 0xFF) / 256., ((backdrop >> 8) & 0xFF) / 256., (backdrop & 0xFF) / 256., 0.f);
710 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]);
711 glEnable(GL_SCISSOR_TEST);
712 glScissor(0, y * glRenderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, glRenderer->scale);
713 glDrawBuffer(GL_COLOR_ATTACHMENT0);
714 glClear(GL_COLOR_BUFFER_BIT);
715 if (y == 0) {
716 glDisable(GL_SCISSOR_TEST);
717 glDrawBuffer(GL_COLOR_ATTACHMENT1);
718 glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2)) / 8.f, 0, 1);
719 glClear(GL_COLOR_BUFFER_BIT);
720
721 glClearColor(0, 0, 0, 0);
722 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
723 glDrawBuffer(GL_COLOR_ATTACHMENT0);
724 glClear(GL_COLOR_BUFFER_BIT);
725 glDrawBuffer(GL_COLOR_ATTACHMENT1);
726 glClear(GL_COLOR_BUFFER_BIT);
727
728 for (i = 0; i < 4; ++i) {
729 glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo);
730 glDrawBuffer(GL_COLOR_ATTACHMENT0);
731 glClear(GL_COLOR_BUFFER_BIT);
732 glDrawBuffer(GL_COLOR_ATTACHMENT1);
733 glClear(GL_COLOR_BUFFER_BIT);
734 }
735 glDrawBuffer(GL_COLOR_ATTACHMENT0);
736 glEnable(GL_SCISSOR_TEST);
737 }
738 glBindFramebuffer(GL_FRAMEBUFFER, 0);
739
740 if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
741 if (glRenderer->firstAffine < 0) {
742 memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
743 memcpy(&glRenderer->bg[3].affine[3], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
744 memcpy(&glRenderer->bg[2].affine[2], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
745 memcpy(&glRenderer->bg[3].affine[2], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
746 memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
747 memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
748 glRenderer->firstAffine = y;
749 } else if (y - glRenderer->firstAffine == 1) {
750 memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
751 memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
752 }
753 } else {
754 glRenderer->firstAffine = -1;
755 }
756
757 int spriteLayers = 0;
758 if (GBARegisterDISPCNTIsObjEnable(glRenderer->dispcnt) && !glRenderer->d.disableOBJ) {
759 if (glRenderer->oamDirty) {
760 glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex);
761 glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 4, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, glRenderer->d.oam);
762 glRenderer->oamMax = GBAVideoRendererCleanOAM(glRenderer->d.oam->obj, glRenderer->sprites, 0);
763 glRenderer->oamDirty = false;
764 }
765 int i;
766 for (i = glRenderer->oamMax; i--;) {
767 struct GBAVideoRendererSprite* sprite = &glRenderer->sprites[i];
768 if ((y < sprite->y && (sprite->endY - 256 < 0 || y >= sprite->endY - 256)) || y >= sprite->endY) {
769 continue;
770 }
771
772 GBAVideoGLRendererDrawSprite(glRenderer, &sprite->obj, y, sprite->y);
773 spriteLayers |= 1 << GBAObjAttributesCGetPriority(sprite->obj.c);
774 }
775 }
776
777 _compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], y);
778 unsigned priority;
779 for (priority = 4; priority--;) {
780 if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
781 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[0], y);
782 }
783 if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
784 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[1], y);
785 }
786 if (TEST_LAYER_ENABLED(2)) {
787 switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
788 case 0:
789 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[2], y);
790 break;
791 case 1:
792 case 2:
793 GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[2], y);
794 break;
795 case 3:
796 //GBAVideoGLRendererDrawBackgroundMode3(glRenderer, &glRenderer->bg[2], y);
797 break;
798 case 4:
799 //GBAVideoGLRendererDrawBackgroundMode4(glRenderer, &glRenderer->bg[2], y);
800 break;
801 case 5:
802 //GBAVideoGLRendererDrawBackgroundMode5(glRenderer, &glRenderer->bg[2], y);
803 break;
804 }
805 }
806 if (TEST_LAYER_ENABLED(3)) {
807 switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
808 case 0:
809 GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[3], y);
810 break;
811 case 2:
812 GBAVideoGLRendererDrawBackgroundMode2(glRenderer, &glRenderer->bg[3], y);
813 break;
814 }
815 }
816 }
817
818 if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
819 memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[2], sizeof(struct GBAVideoGLAffine));
820 memcpy(&glRenderer->bg[3].affine[3], &glRenderer->bg[3].affine[2], sizeof(struct GBAVideoGLAffine));
821 memcpy(&glRenderer->bg[2].affine[2], &glRenderer->bg[2].affine[1], sizeof(struct GBAVideoGLAffine));
822 memcpy(&glRenderer->bg[3].affine[2], &glRenderer->bg[3].affine[1], sizeof(struct GBAVideoGLAffine));
823 memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
824 memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
825
826 glRenderer->bg[2].affine[0].sx += glRenderer->bg[2].affine[0].dmx;
827 glRenderer->bg[2].affine[0].sy += glRenderer->bg[2].affine[0].dmy;
828 glRenderer->bg[3].affine[0].sx += glRenderer->bg[3].affine[0].dmx;
829 glRenderer->bg[3].affine[0].sy += glRenderer->bg[3].affine[0].dmy;
830 }
831}
832
833void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) {
834 struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
835 glRenderer->firstAffine = -1;
836 glRenderer->bg[2].affine[0].sx = glRenderer->bg[2].refx;
837 glRenderer->bg[2].affine[0].sy = glRenderer->bg[2].refy;
838 glRenderer->bg[3].affine[0].sx = glRenderer->bg[3].refx;
839 glRenderer->bg[3].affine[0].sy = glRenderer->bg[3].refy;
840 glFlush();
841}
842
843void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
844
845}
846
847void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels) {
848
849}
850
851static void _enableBg(struct GBAVideoGLRenderer* renderer, int bg, bool active) {
852 int wasActive = renderer->bg[bg].enabled;
853 if (!active) {
854 renderer->bg[bg].enabled = 0;
855 } else if (!wasActive && active) {
856 /*if (renderer->nextY == 0 || GBARegisterDISPCNTGetMode(renderer->dispcnt) > 2) {
857 // TODO: Investigate in more depth how switching background works in different modes
858 renderer->bg[bg].enabled = 4;
859 } else {
860 renderer->bg[bg].enabled = 1;
861 }*/
862 renderer->bg[bg].enabled = 4;
863 }
864}
865
866static void GBAVideoGLRendererUpdateDISPCNT(struct GBAVideoGLRenderer* renderer) {
867 _enableBg(renderer, 0, GBARegisterDISPCNTGetBg0Enable(renderer->dispcnt));
868 _enableBg(renderer, 1, GBARegisterDISPCNTGetBg1Enable(renderer->dispcnt));
869 _enableBg(renderer, 2, GBARegisterDISPCNTGetBg2Enable(renderer->dispcnt));
870 _enableBg(renderer, 3, GBARegisterDISPCNTGetBg3Enable(renderer->dispcnt));
871}
872
873static void GBAVideoGLRendererWriteBGCNT(struct GBAVideoGLBackground* bg, uint16_t value) {
874 bg->priority = GBARegisterBGCNTGetPriority(value);
875 bg->charBase = GBARegisterBGCNTGetCharBase(value) << 13;
876 bg->mosaic = GBARegisterBGCNTGetMosaic(value);
877 bg->multipalette = GBARegisterBGCNTGet256Color(value);
878 bg->screenBase = GBARegisterBGCNTGetScreenBase(value) << 10;
879 bg->overflow = GBARegisterBGCNTGetOverflow(value);
880 bg->size = GBARegisterBGCNTGetSize(value);
881}
882
883static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
884 bg->refx = (bg->refx & 0xFFFF0000) | value;
885 bg->affine[0].sx = bg->refx;
886}
887
888static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
889 bg->refx = (bg->refx & 0x0000FFFF) | (value << 16);
890 bg->refx <<= 4;
891 bg->refx >>= 4;
892 bg->affine[0].sx = bg->refx;
893}
894
895static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value) {
896 bg->refy = (bg->refy & 0xFFFF0000) | value;
897 bg->affine[0].sy = bg->refy;
898}
899
900static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value) {
901 bg->refy = (bg->refy & 0x0000FFFF) | (value << 16);
902 bg->refy <<= 4;
903 bg->refy >>= 4;
904 bg->affine[0].sy = bg->refy;
905}
906
907static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value) {
908 renderer->bg[0].target1 = GBARegisterBLDCNTGetTarget1Bg0(value);
909 renderer->bg[1].target1 = GBARegisterBLDCNTGetTarget1Bg1(value);
910 renderer->bg[2].target1 = GBARegisterBLDCNTGetTarget1Bg2(value);
911 renderer->bg[3].target1 = GBARegisterBLDCNTGetTarget1Bg3(value);
912 renderer->bg[0].target2 = GBARegisterBLDCNTGetTarget2Bg0(value);
913 renderer->bg[1].target2 = GBARegisterBLDCNTGetTarget2Bg1(value);
914 renderer->bg[2].target2 = GBARegisterBLDCNTGetTarget2Bg2(value);
915 renderer->bg[3].target2 = GBARegisterBLDCNTGetTarget2Bg3(value);
916
917 renderer->blendEffect = GBARegisterBLDCNTGetEffect(value);
918 renderer->target1Obj = GBARegisterBLDCNTGetTarget1Obj(value);
919 renderer->target1Bd = GBARegisterBLDCNTGetTarget1Bd(value);
920 renderer->target2Obj = GBARegisterBLDCNTGetTarget2Obj(value);
921 renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value);
922}
923
924static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int y) {
925 if ((y & 0x1F) != 0x1F) {
926 return;
927 }
928 glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_COMPOSITE]);
929 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
930 glScissor(0, (y & ~0x1F) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale);
931 glUseProgram(renderer->compositeProgram);
932 glActiveTexture(GL_TEXTURE0);
933 glBindTexture(GL_TEXTURE_2D, tex);
934 glActiveTexture(GL_TEXTURE0 + 1);
935 glBindTexture(GL_TEXTURE_2D, flags);
936 glActiveTexture(GL_TEXTURE0 + 2);
937 glBindTexture(GL_TEXTURE_2D, renderer->outputTex);
938 glActiveTexture(GL_TEXTURE0 + 3);
939 glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]);
940 glUniform2i(0, 0x20, y & ~0x1F);
941 glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
942 glUniform1i(2, renderer->scale);
943 glUniform3f(3, renderer->blda / 16.f, renderer->bldb / 16.f, renderer->bldy / 16.f);
944 glUniform1i(4, 0);
945 glUniform1i(5, 1);
946 glUniform1i(6, 2);
947 glUniform1i(7, 3);
948 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
949 glEnableVertexAttribArray(0);
950 glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
951 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
952 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
953 glBindFramebuffer(GL_FRAMEBUFFER, 0);
954}
955
956void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY) {
957 int width = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][0];
958 int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][1];
959 int32_t x = (uint32_t) GBAObjAttributesBGetX(sprite->b) << 23;
960 x >>= 23;
961
962 int align = GBAObjAttributesAIs256Color(sprite->a) && !GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt);
963 unsigned charBase = (BASE_TILE >> 1) + (GBAObjAttributesCGetTile(sprite->c) & ~align) * 0x10;
964 int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x40 >> !GBAObjAttributesAIs256Color(sprite->a));
965
966 if (spriteY + height >= 256) {
967 spriteY -= 256;
968 }
969
970 if (!GBAObjAttributesAIsTransformed(sprite->a) && GBAObjAttributesBIsVFlip(sprite->b)) {
971 spriteY = (y - height) + (y - spriteY) + 1;
972 }
973
974 int totalWidth = width;
975 int totalHeight = height;
976 if (GBAObjAttributesAIsTransformed(sprite->a) && GBAObjAttributesAIsDoubleSize(sprite->a)) {
977 totalWidth <<= 1;
978 totalHeight <<= 1;
979 }
980
981 glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]);
982 glViewport(x * renderer->scale, spriteY * renderer->scale, totalWidth * renderer->scale, totalHeight * renderer->scale);
983 glScissor(x * renderer->scale, y * renderer->scale, totalWidth * renderer->scale, renderer->scale);
984 glUseProgram(renderer->objProgram[GBAObjAttributesAGet256Color(sprite->a)]);
985 glActiveTexture(GL_TEXTURE0);
986 glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
987 glActiveTexture(GL_TEXTURE0 + 1);
988 glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
989 glUniform2i(0, 1, y - spriteY);
990 glUniform2i(1, (GBAObjAttributesBIsHFlip(sprite->b) && !GBAObjAttributesAIsTransformed(sprite->a)) ? -totalWidth : totalWidth, totalHeight);
991 glUniform1i(2, 0);
992 glUniform1i(3, 1);
993 glUniform1i(4, charBase);
994 glUniform1i(5, stride);
995 glUniform1i(6, GBAObjAttributesCGetPalette(sprite->c));
996 glUniform3i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, renderer->target1Obj | (renderer->target2Obj * 2), 0);
997 if (GBAObjAttributesAIsTransformed(sprite->a)) {
998 struct GBAOAMMatrix mat;
999 LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a);
1000 LOAD_16(mat.b, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].b);
1001 LOAD_16(mat.c, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].c);
1002 LOAD_16(mat.d, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].d);
1003
1004 glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { mat.a / 256.f, mat.c / 256.f, mat.b / 256.f, mat.d / 256.f });
1005 } else {
1006 glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { 1.f, 0, 0, 1.f });
1007 }
1008 glUniform4i(9, width, height, totalWidth, totalHeight);
1009 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
1010 glEnableVertexAttribArray(0);
1011 glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
1012 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1013 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1014}
1015
1016void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1017 int inY = y + background->y;
1018 int yBase = inY & 0xFF;
1019 if (background->size == 2) {
1020 yBase += inY & 0x100;
1021 } else if (background->size == 3) {
1022 yBase += (inY & 0x100) << 1;
1023 }
1024 glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
1025 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1026 glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale);
1027 glUseProgram(renderer->bgProgram[background->multipalette ? 1 : 0]);
1028 glActiveTexture(GL_TEXTURE0);
1029 glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
1030 glActiveTexture(GL_TEXTURE0 + 1);
1031 glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
1032 glUniform2i(0, 1, y);
1033 glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1034 glUniform1i(2, 0);
1035 glUniform1i(3, 1);
1036 glUniform1i(4, background->screenBase);
1037 glUniform1i(5, background->charBase);
1038 glUniform1i(6, background->size);
1039 glUniform2i(7, background->x, yBase - y);
1040 glUniform3i(8, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2), renderer->blendEffect);
1041 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
1042 glEnableVertexAttribArray(0);
1043 glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
1044 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1045 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1046
1047 _compositeLayer(renderer, background->tex, background->flags, y);
1048}
1049
1050void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1051 glBindFramebuffer(GL_FRAMEBUFFER, background->fbo);
1052 glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
1053 glScissor(0, y * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale);
1054 glUseProgram(renderer->bgProgram[background->overflow ? 2 : 3]);
1055 glActiveTexture(GL_TEXTURE0);
1056 glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
1057 glActiveTexture(GL_TEXTURE0 + 1);
1058 glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
1059 glUniform2i(0, 1, y);
1060 glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
1061 glUniform1i(2, 0);
1062 glUniform1i(3, 1);
1063 glUniform1i(4, background->screenBase);
1064 glUniform1i(5, background->charBase);
1065 glUniform1i(6, background->size);
1066 glUniform3i(7, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2), renderer->blendEffect);
1067 if (renderer->scale > 1) {
1068 glUniform2iv(8, 4, (GLint[]) {
1069 background->affine[0].sx, background->affine[0].sy,
1070 background->affine[1].sx, background->affine[1].sy,
1071 background->affine[2].sx, background->affine[2].sy,
1072 background->affine[3].sx, background->affine[3].sy,
1073 });
1074 glUniform2iv(12, 4, (GLint[]) {
1075 background->affine[0].dx, background->affine[0].dy,
1076 background->affine[1].dx, background->affine[1].dy,
1077 background->affine[2].dx, background->affine[2].dy,
1078 background->affine[3].dx, background->affine[3].dy,
1079 });
1080 } else {
1081 glUniform2iv(8, 4, (GLint[]) {
1082 background->affine[0].sx, background->affine[0].sy,
1083 background->affine[0].sx, background->affine[0].sy,
1084 background->affine[0].sx, background->affine[0].sy,
1085 background->affine[0].sx, background->affine[0].sy,
1086 });
1087 glUniform2iv(12, 4, (GLint[]) {
1088 background->affine[0].dx, background->affine[0].dy,
1089 background->affine[0].dx, background->affine[0].dy,
1090 background->affine[0].dx, background->affine[0].dy,
1091 background->affine[0].dx, background->affine[0].dy,
1092 });
1093 }
1094 glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
1095 glEnableVertexAttribArray(0);
1096 glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
1097 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1098 glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
1099
1100 _compositeLayer(renderer, background->tex, background->flags, y);
1101}