all repos — mgba @ 3e8bb42e9f745f69f2137f071cfdc8fda0f3d435

mGBA Game Boy Advance Emulator

GBA Video: Windows in GL
Vicki Pfau vi@endrift.com
Mon, 13 May 2019 18:07:03 -0700
commit

3e8bb42e9f745f69f2137f071cfdc8fda0f3d435

parent

a50ea97bce0445171fddd7ecedd11adb321c1780

M include/mgba/internal/gba/renderers/gl.hinclude/mgba/internal/gba/renderers/gl.h

@@ -66,14 +66,20 @@

enum { GBA_GL_FBO_OBJ = 0, GBA_GL_FBO_COMPOSITE = 1, - GBA_GL_FBO_OUTPUT = 2, + GBA_GL_FBO_WINDOW = 2, + GBA_GL_FBO_OUTPUT = 3, + GBA_GL_FBO_MAX +}; +enum { GBA_GL_TEX_OBJ_COLOR = 0, GBA_GL_TEX_OBJ_FLAGS = 1, GBA_GL_TEX_COMPOSITE_COLOR = 2, GBA_GL_TEX_COMPOSITE_FLAGS = 3, GBA_GL_TEX_COMPOSITE_OLD_COLOR = 4, GBA_GL_TEX_COMPOSITE_OLD_FLAGS = 5, + GBA_GL_TEX_WINDOW = 6, + GBA_GL_TEX_MAX }; struct GBAVideoGLRenderer {

@@ -85,8 +91,8 @@ int oamMax;

bool oamDirty; struct GBAVideoRendererSprite sprites[128]; - GLuint fbo[3]; - GLuint layers[6]; + GLuint fbo[GBA_GL_FBO_MAX]; + GLuint layers[GBA_GL_TEX_MAX]; GLuint outputTex;

@@ -114,6 +120,15 @@ uint16_t bldb;

uint16_t bldy; GBAMosaicControl mosaic; + + struct GBAVideoGLWindowN { + struct GBAVideoWindowRegion h; + struct GBAVideoWindowRegion v; + GBAWindowControl control; + } winN[2]; + + GBAWindowControl winout; + GBAWindowControl objwin; int firstAffine;
M include/mgba/internal/gba/renderers/video-software.hinclude/mgba/internal/gba/renderers/video-software.h

@@ -70,11 +70,6 @@ #define FLAG_ORDER_MASK 0xF8000000

#define IS_WRITABLE(PIXEL) ((PIXEL) & 0xFE000000) -struct WindowRegion { - uint8_t end; - uint8_t start; -}; - struct WindowControl { GBAWindowControl packed; int8_t priority;

@@ -118,8 +113,8 @@

GBAMosaicControl mosaic; struct WindowN { - struct WindowRegion h; - struct WindowRegion v; + struct GBAVideoWindowRegion h; + struct GBAVideoWindowRegion v; struct WindowControl control; } winN[2];
M include/mgba/internal/gba/video.hinclude/mgba/internal/gba/video.h

@@ -97,6 +97,11 @@

uint16_t raw[512]; }; +struct GBAVideoWindowRegion { + uint8_t end; + uint8_t start; +}; + #define GBA_TEXT_MAP_TILE(MAP) ((MAP) & 0x03FF) #define GBA_TEXT_MAP_HFLIP(MAP) ((MAP) & 0x0400) #define GBA_TEXT_MAP_VFLIP(MAP) ((MAP) & 0x0800)
M src/gba/renderers/gl.csrc/gba/renderers/gl.c

@@ -36,8 +36,9 @@ static void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);

static void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y); +static void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y); -static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int y); +static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int id, int y); static void _finalizeLayers(struct GBAVideoGLRenderer* renderer, int y); #define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 && glRenderer->bg[X].priority == priority

@@ -216,11 +217,13 @@

static const char* const _composite = "varying vec2 texCoord;\n" "uniform int scale;\n" + "uniform int layerId\n;" "uniform sampler2D layer;\n" "uniform sampler2D layerFlags;\n" "uniform sampler2D oldLayer;\n" "uniform sampler2D oldLayerFlags;\n" "uniform sampler2D oldOldFlags;\n" + "uniform sampler2D window;\n" "out vec4 color;\n" "out vec4 flags;\n" "out vec4 oldColor;\n"

@@ -232,8 +235,15 @@ " vec4 pix = texelFetch(layer, ivec2(texCoord * scale), 0);\n"

" if (pix.a == 0) {\n" " discard;\n" " }\n" + " ivec2 windowFlags = ivec2(texelFetch(window, ivec2(texCoord * scale), 0).xy * 32.);\n" + " if (((windowFlags.x | (windowFlags.y << 4)) & layerId) != 0) {\n" + " discard;\n" + " }\n" " ivec4 inflags = ivec4(texelFetch(layerFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" " ivec4 oflags = ivec4(texelFetch(oldLayerFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" + " if ((windowFlags.y & 2) != 0) {\n" + " inflags.y = 0;\n" + " }\n" " if (inflags.x >= oflags.x) {\n" " ivec4 ooflags = ivec4(texelFetch(oldOldFlags, ivec2(texCoord * scale), 0) * flagCoeff);\n" " if (inflags.x >= ooflags.x) {\n"

@@ -339,8 +349,8 @@ }

void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; - glGenFramebuffers(3, glRenderer->fbo); - glGenTextures(6, glRenderer->layers); + glGenFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo); + glGenTextures(GBA_GL_TEX_MAX, glRenderer->layers); glGenTextures(1, &glRenderer->paletteTex); glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);

@@ -362,6 +372,9 @@ _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale);

_initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS], GL_RGBA, GL_COLOR_ATTACHMENT1, glRenderer->scale); _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_OLD_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT2, glRenderer->scale); _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_COMPOSITE_OLD_FLAGS], GL_RGBA, GL_COLOR_ATTACHMENT3, glRenderer->scale); + + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_WINDOW]); + _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_WINDOW], GL_RG, GL_COLOR_ATTACHMENT0, glRenderer->scale); glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OUTPUT]); _initFramebufferTexture(glRenderer->outputTex, GL_RGB, GL_COLOR_ATTACHMENT0, glRenderer->scale);

@@ -464,8 +477,8 @@ }

void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; - glDeleteFramebuffers(2, glRenderer->fbo); - glDeleteTextures(6, glRenderer->layers); + glDeleteFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo); + glDeleteTextures(GBA_GL_TEX_MAX, glRenderer->layers); glDeleteTextures(1, &glRenderer->paletteTex); glDeleteTextures(1, &glRenderer->vramTex);

@@ -638,7 +651,7 @@ }

glRenderer->bldy = value; break; case REG_WIN0H: - /*glRenderer->winN[0].h.end = value; + glRenderer->winN[0].h.end = value; glRenderer->winN[0].h.start = value >> 8; if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[0].h.start > glRenderer->winN[0].h.end) { glRenderer->winN[0].h.start = 0;

@@ -648,10 +661,10 @@ glRenderer->winN[0].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;

if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) { glRenderer->winN[0].h.start = GBA_VIDEO_HORIZONTAL_PIXELS; } - }*/ + } break; case REG_WIN1H: - /*glRenderer->winN[1].h.end = value; + glRenderer->winN[1].h.end = value; glRenderer->winN[1].h.start = value >> 8; if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[1].h.start > glRenderer->winN[1].h.end) { glRenderer->winN[1].h.start = 0;

@@ -661,10 +674,10 @@ glRenderer->winN[1].h.end = GBA_VIDEO_HORIZONTAL_PIXELS;

if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS) { glRenderer->winN[1].h.start = GBA_VIDEO_HORIZONTAL_PIXELS; } - }*/ + } break; case REG_WIN0V: - /*glRenderer->winN[0].v.end = value; + glRenderer->winN[0].v.end = value; glRenderer->winN[0].v.start = value >> 8; if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[0].v.start > glRenderer->winN[0].v.end) { glRenderer->winN[0].v.start = 0;

@@ -674,10 +687,10 @@ glRenderer->winN[0].v.end = GBA_VIDEO_VERTICAL_PIXELS;

if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS) { glRenderer->winN[0].v.start = GBA_VIDEO_VERTICAL_PIXELS; } - }*/ + } break; case REG_WIN1V: - /*glRenderer->winN[1].v.end = value; + glRenderer->winN[1].v.end = value; glRenderer->winN[1].v.start = value >> 8; if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[1].v.start > glRenderer->winN[1].v.end) { glRenderer->winN[1].v.start = 0;

@@ -687,26 +700,23 @@ glRenderer->winN[1].v.end = GBA_VIDEO_VERTICAL_PIXELS;

if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS) { glRenderer->winN[1].v.start = GBA_VIDEO_VERTICAL_PIXELS; } - }*/ + } break; case REG_WININ: value &= 0x3F3F; - //glRenderer->winN[0].control.packed = value; - //glRenderer->winN[1].control.packed = value >> 8; + glRenderer->winN[0].control = value; + glRenderer->winN[1].control = value >> 8; break; case REG_WINOUT: value &= 0x3F3F; - //glRenderer->winout.packed = value; - //glRenderer->objwin.packed = value >> 8; + glRenderer->winout = value; + glRenderer->objwin = value >> 8; break; case REG_MOSAIC: glRenderer->mosaic = value; break; - case REG_GREENSWP: - mLOG(GBA_VIDEO, STUB, "Stub video register write: 0x%03X", address); - break; default: - mLOG(GBA_VIDEO, GAME_ERROR, "Invalid video register: 0x%03X", address); + break; } return value; }

@@ -800,7 +810,8 @@ spriteLayers |= 1 << GBAObjAttributesCGetPriority(sprite->obj.c);

} } - _compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], y); + GBAVideoGLRendererDrawWindow(glRenderer, y); + _compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], 4, y); unsigned priority; for (priority = 4; priority--;) { if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {

@@ -842,7 +853,6 @@ }

} _finalizeLayers(glRenderer, y); - if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) { memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[2], sizeof(struct GBAVideoGLAffine)); memcpy(&glRenderer->bg[3].affine[3], &glRenderer->bg[3].affine[2], sizeof(struct GBAVideoGLAffine));

@@ -949,7 +959,7 @@ renderer->target2Obj = GBARegisterBLDCNTGetTarget2Obj(value);

renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value); } -static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int y) { +static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, GLuint flags, int id, int y) { if ((y & 0x1F) != 0x1F) { return; }

@@ -967,14 +977,18 @@ glActiveTexture(GL_TEXTURE0 + 3);

glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]); glActiveTexture(GL_TEXTURE0 + 4); glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_OLD_FLAGS]); + glActiveTexture(GL_TEXTURE0 + 5); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_WINDOW]); glUniform2i(0, 0x20, y & ~0x1F); glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); glUniform1i(2, renderer->scale); - glUniform1i(3, 0); - glUniform1i(4, 1); - glUniform1i(5, 2); - glUniform1i(6, 3); - glUniform1i(7, 4); + glUniform1i(3, 1 << id); + glUniform1i(4, 0); + glUniform1i(5, 1); + glUniform1i(6, 2); + glUniform1i(7, 3); + glUniform1i(8, 4); + glUniform1i(9, 5); glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices); glEnableVertexAttribArray(0); glDrawBuffers(4, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 });

@@ -1109,7 +1123,7 @@ glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });

glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - _compositeLayer(renderer, background->tex, background->flags, y); + _compositeLayer(renderer, background->tex, background->flags, background->index, y); } void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {

@@ -1164,5 +1178,28 @@ glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });

glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); - _compositeLayer(renderer, background->tex, background->flags, y); -}+ _compositeLayer(renderer, background->tex, background->flags, background->index, y); +} + +static void _clearWindow(GBAWindowControl window, int start, int end, int y, int scale) { + glScissor(start, y, end - start, scale); + window = ~window & 0xFF; + glClearColor((window & 0xF) / 32.f, (window >> 4) / 32.f, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); +} + +void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y) { + glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_WINDOW]); + if (!(renderer->dispcnt & 0xE000)) { + _clearWindow(0xFF, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, y * renderer->scale, renderer->scale); + } else { + _clearWindow(renderer->winout, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, y * renderer->scale, renderer->scale); + if (GBARegisterDISPCNTIsWin1Enable(renderer->dispcnt) && y >= renderer->winN[1].v.start && y < renderer->winN[1].v.end) { + _clearWindow(renderer->winN[1].control, renderer->winN[1].h.start * renderer->scale, renderer->winN[1].h.end * renderer->scale, y * renderer->scale, renderer->scale); + } + if (GBARegisterDISPCNTIsWin0Enable(renderer->dispcnt) && y >= renderer->winN[0].v.start && y < renderer->winN[0].v.end) { + _clearWindow(renderer->winN[0].control, renderer->winN[0].h.start * renderer->scale, renderer->winN[0].h.end * renderer->scale, y * renderer->scale, renderer->scale); + } + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); +}