Skip to content

Commit 1b4cb46

Browse files
committed
GBA Video: Fix background toggling in OpenGL renderer (fixes mgba-emu#2475)
1 parent 9e3239b commit 1b4cb46

File tree

3 files changed

+56
-32
lines changed

3 files changed

+56
-32
lines changed

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Emulation fixes:
3939
- GBA Video: Improve sprite drawing cycle counting (fixes mgba.io/i/3081)
4040
- GBA Video: Fix edge case with double-height sprites wrapping (fixes mgba.io/i/2824)
4141
- GBA Video: VCOUNTER flag should be updated on DISPSTAT write (fixes mgba.io/i/1873)
42+
- GBA Video: Fix background toggling in OpenGL renderer (fixes mgba.io/i/2475)
4243
Other fixes:
4344
- 3DS: Don't detach autosave thread (fixes mgba.io/i/3561)
4445
- Core: Fix inconsistencies with setting game-specific overrides (fixes mgba.io/i/2963)

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ struct GBAVideoGLBackground {
4444
GLuint tex;
4545

4646
unsigned index;
47-
int enabled;
47+
int enabledAtY;
4848
unsigned priority;
4949
uint32_t charBase;
5050
uint32_t oldCharBase;
@@ -204,6 +204,7 @@ struct GBAVideoGLRenderer {
204204

205205
int firstAffine;
206206
int firstY;
207+
int lastY;
207208

208209
int scale;
209210
};

src/gba/renderers/gl.c

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,9 @@ static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* ren
4747
static void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y);
4848

4949
static void _cleanRegister(struct GBAVideoGLRenderer* renderer, int address, uint16_t value);
50-
static void _drawScanlines(struct GBAVideoGLRenderer* renderer, int lastY);
50+
static void _drawScanlines(struct GBAVideoGLRenderer* renderer, int y);
5151
static void _finalizeLayers(struct GBAVideoGLRenderer* renderer);
5252

53-
#define TEST_LAYER_ENABLED(X) !glRenderer->d.disableBG[X] && glRenderer->bg[X].enabled == 4
54-
5553
struct GBAVideoGLUniform {
5654
const char* name;
5755
int type;
@@ -911,6 +909,7 @@ void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
911909
glRenderer->vramDirty = 0xFFFFFF;
912910
glRenderer->firstAffine = -1;
913911
glRenderer->firstY = -1;
912+
glRenderer->lastY = -1;
914913
glRenderer->dispcnt = 0x0080;
915914
glRenderer->mosaic = 0;
916915
glRenderer->nextPalette = 0;
@@ -926,7 +925,7 @@ void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
926925
for (i = 0; i < 4; ++i) {
927926
struct GBAVideoGLBackground* bg = &glRenderer->bg[i];
928927
bg->index = i;
929-
bg->enabled = 0;
928+
bg->enabledAtY = INT_MAX;
930929
bg->priority = 0;
931930
bg->charBase = 0;
932931
bg->mosaic = 0;
@@ -1243,8 +1242,7 @@ void _cleanRegister(struct GBAVideoGLRenderer* glRenderer, int address, uint16_t
12431242
}
12441243

12451244
static bool _dirtyMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1246-
UNUSED(y);
1247-
if (!background->enabled) {
1245+
if (y < background->enabledAtY) {
12481246
return false;
12491247
}
12501248
unsigned screenBase = background->screenBase >> 11; // Lops off one extra bit
@@ -1261,8 +1259,7 @@ static bool _dirtyMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBa
12611259
}
12621260

12631261
static bool _dirtyMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1264-
UNUSED(y);
1265-
if (!background->enabled) {
1262+
if (y < background->enabledAtY) {
12661263
return false;
12671264
}
12681265
unsigned screenBase = background->screenBase >> 11; // Lops off one extra bit
@@ -1279,8 +1276,7 @@ static bool _dirtyMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBa
12791276
}
12801277

12811278
static bool _dirtyMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1282-
UNUSED(y);
1283-
if (!background->enabled) {
1279+
if (y < background->enabledAtY) {
12841280
return false;
12851281
}
12861282
if (renderer->vramDirty & 0xFFFFF) {
@@ -1290,8 +1286,7 @@ static bool _dirtyMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBa
12901286
}
12911287

12921288
static bool _dirtyMode45(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
1293-
UNUSED(y);
1294-
if (!background->enabled) {
1289+
if (y < background->enabledAtY) {
12951290
return false;
12961291
}
12971292
int start = GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt) ? 5 : 0;
@@ -1365,6 +1360,7 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
13651360
if (glRenderer->firstY < 0) {
13661361
glRenderer->firstY = y;
13671362
}
1363+
glRenderer->lastY = y;
13681364

13691365
int i;
13701366
for (i = 0; i < 0x30; ++i) {
@@ -1468,11 +1464,11 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
14681464
}
14691465

14701466
if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
1471-
if (glRenderer->bg[2].enabled == 4) {
1467+
if (glRenderer->bg[2].enabledAtY <= y) {
14721468
glRenderer->bg[2].affine.sx += glRenderer->bg[2].affine.dmx;
14731469
glRenderer->bg[2].affine.sy += glRenderer->bg[2].affine.dmy;
14741470
}
1475-
if (glRenderer->bg[3].enabled == 4) {
1471+
if (glRenderer->bg[3].enabledAtY <= y) {
14761472
glRenderer->bg[3].affine.sx += glRenderer->bg[3].affine.dmx;
14771473
glRenderer->bg[3].affine.sy += glRenderer->bg[3].affine.dmy;
14781474
}
@@ -1535,13 +1531,13 @@ void _drawScanlines(struct GBAVideoGLRenderer* glRenderer, int y) {
15351531
glDisable(GL_STENCIL_TEST);
15361532
}
15371533

1538-
if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
1534+
if (glRenderer->bg[0].enabledAtY <= y && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
15391535
GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[0], y);
15401536
}
1541-
if (TEST_LAYER_ENABLED(1) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
1537+
if (glRenderer->bg[1].enabledAtY <= y && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
15421538
GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[1], y);
15431539
}
1544-
if (TEST_LAYER_ENABLED(2)) {
1540+
if (glRenderer->bg[2].enabledAtY <= y) {
15451541
switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
15461542
case 0:
15471543
GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[2], y);
@@ -1561,7 +1557,7 @@ void _drawScanlines(struct GBAVideoGLRenderer* glRenderer, int y) {
15611557
break;
15621558
}
15631559
}
1564-
if (TEST_LAYER_ENABLED(3)) {
1560+
if (glRenderer->bg[3].enabledAtY <= y) {
15651561
switch (GBARegisterDISPCNTGetMode(glRenderer->dispcnt)) {
15661562
case 0:
15671563
GBAVideoGLRendererDrawBackgroundMode0(glRenderer, &glRenderer->bg[3], y);
@@ -1582,6 +1578,19 @@ void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) {
15821578
glBindVertexArray(0);
15831579
glRenderer->firstAffine = -1;
15841580
glRenderer->firstY = -1;
1581+
glRenderer->lastY = -1;
1582+
if (glRenderer->bg[0].enabledAtY < INT_MAX) {
1583+
glRenderer->bg[0].enabledAtY = 0;
1584+
}
1585+
if (glRenderer->bg[1].enabledAtY < INT_MAX) {
1586+
glRenderer->bg[1].enabledAtY = 0;
1587+
}
1588+
if (glRenderer->bg[2].enabledAtY < INT_MAX) {
1589+
glRenderer->bg[2].enabledAtY = 0;
1590+
}
1591+
if (glRenderer->bg[3].enabledAtY < INT_MAX) {
1592+
glRenderer->bg[3].enabledAtY = 0;
1593+
}
15851594
glRenderer->bg[2].affine.sx = glRenderer->bg[2].refx;
15861595
glRenderer->bg[2].affine.sy = glRenderer->bg[2].refy;
15871596
glRenderer->bg[3].affine.sx = glRenderer->bg[3].refx;
@@ -1610,17 +1619,18 @@ void GBAVideoGLRendererPutPixels(struct GBAVideoRenderer* renderer, size_t strid
16101619
}
16111620

16121621
static void _enableBg(struct GBAVideoGLRenderer* renderer, int bg, bool active) {
1613-
int wasActive = renderer->bg[bg].enabled;
1622+
int wasActive = renderer->bg[bg].enabledAtY;
16141623
if (!active) {
1615-
renderer->bg[bg].enabled = 0;
1616-
} else if (!wasActive && active) {
1617-
/*if (renderer->nextY == 0 || GBARegisterDISPCNTGetMode(renderer->dispcnt) > 2) {
1624+
renderer->bg[bg].enabledAtY = INT_MAX;
1625+
} else if (wasActive == INT_MAX && active) {
1626+
if (renderer->lastY < 0) {
16181627
// TODO: Investigate in more depth how switching background works in different modes
1619-
renderer->bg[bg].enabled = 4;
1628+
renderer->bg[bg].enabledAtY = 0;
1629+
} else if (GBARegisterDISPCNTGetMode(renderer->dispcnt) > 2) {
1630+
renderer->bg[bg].enabledAtY = renderer->lastY + 2;
16201631
} else {
1621-
renderer->bg[bg].enabled = 1;
1622-
}*/
1623-
renderer->bg[bg].enabled = 4;
1632+
renderer->bg[bg].enabledAtY = renderer->lastY + 3;
1633+
}
16241634
}
16251635
}
16261636

@@ -1885,6 +1895,10 @@ void _prepareBackground(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBa
18851895
void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
18861896
const struct GBAVideoGLShader* shader = &renderer->bgShader[background->multipalette ? 1 : 0];
18871897
const GLuint* uniforms = shader->uniforms;
1898+
int firstY = renderer->firstY;
1899+
if (firstY < background->enabledAtY) {
1900+
firstY = background->enabledAtY;
1901+
}
18881902
glUseProgram(shader->program);
18891903
glBindVertexArray(shader->vao);
18901904
_prepareBackground(renderer, background, uniforms);
@@ -1893,16 +1907,20 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer,
18931907
glUniform1i(uniforms[GBA_GL_BG_SIZE], background->size);
18941908
glUniform1iv(uniforms[GBA_GL_BG_OFFSET], GBA_VIDEO_VERTICAL_PIXELS, background->scanlineOffset);
18951909

1896-
glScissor(0, renderer->firstY * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, (y - renderer->firstY + 1) * renderer->scale);
1897-
glUniform2i(uniforms[GBA_GL_VS_LOC], y - renderer->firstY + 1, renderer->firstY);
1910+
glScissor(0, firstY * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, (y - firstY + 1) * renderer->scale);
1911+
glUniform2i(uniforms[GBA_GL_VS_LOC], y - firstY + 1, firstY);
18981912
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
18991913

19001914
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
19011915
}
19021916

19031917
void _prepareTransform(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, const GLuint* uniforms, int y) {
1904-
glScissor(0, renderer->firstY * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale * (y - renderer->firstY + 1));
1905-
glUniform2i(uniforms[GBA_GL_VS_LOC], y - renderer->firstY + 1, renderer->firstY);
1918+
int firstY = renderer->firstY;
1919+
if (firstY < background->enabledAtY) {
1920+
firstY = background->enabledAtY;
1921+
}
1922+
glScissor(0, firstY * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale * (y - firstY + 1));
1923+
glUniform2i(uniforms[GBA_GL_VS_LOC], y - firstY + 1, firstY);
19061924
glUniform2i(uniforms[GBA_GL_BG_RANGE], renderer->firstAffine, y);
19071925

19081926
glUniform4iv(uniforms[GBA_GL_BG_TRANSFORM], GBA_VIDEO_VERTICAL_PIXELS, background->scanlineAffine);
@@ -1912,11 +1930,15 @@ void _prepareTransform(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBac
19121930
void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
19131931
const struct GBAVideoGLShader* shader = &renderer->bgShader[background->overflow ? 2 : 3];
19141932
const GLuint* uniforms = shader->uniforms;
1933+
int firstY = renderer->firstY;
1934+
if (firstY < background->enabledAtY) {
1935+
firstY = background->enabledAtY;
1936+
}
19151937
glUseProgram(shader->program);
19161938
glBindVertexArray(shader->vao);
19171939
_prepareTransform(renderer, background, uniforms, y);
19181940
glUniform1i(uniforms[GBA_GL_BG_SCREENBASE], background->screenBase);
1919-
glUniform2i(uniforms[GBA_GL_BG_OLDCHARBASE], background->oldCharBase, renderer->firstY);
1941+
glUniform2i(uniforms[GBA_GL_BG_OLDCHARBASE], background->oldCharBase, firstY);
19201942
glUniform1i(uniforms[GBA_GL_BG_CHARBASE], background->charBase);
19211943
glUniform1i(uniforms[GBA_GL_BG_SIZE], background->size);
19221944
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

0 commit comments

Comments
 (0)