all repos — mgba @ e11dc3fad05bd655228c078147d5af2ec5733c1e

mGBA Game Boy Advance Emulator

GBA Video: Emulate sprite cycle limits in OpenGL renderer (fixes #1635)
Vicki Pfau vi@endrift.com
Sat, 26 Sep 2020 02:30:54 -0700
commit

e11dc3fad05bd655228c078147d5af2ec5733c1e

parent

e83a371e50638abfe513ef971e16c270f00f012b

3 files changed, 35 insertions(+), 3 deletions(-)

jump to
M CHANGESCHANGES

@@ -46,6 +46,7 @@ - GBA Video: Invalidate map cache when modifying BGCNT (fixes mgba.io/i/1846)

- GBA Video: Don't draw sprites using unmapped VRAM in GL renderer (fixes mgba.io/i/1865) - GBA Video: Implement green swap (fixes mgba.io/i/1609) - GBA Video: Fix rare regression blending semitransparent sprites (fixes mgba.io/i/1876) + - GBA Video: Emulate sprite cycle limits in OpenGL renderer (fixes mgba.io/i/1635) - SM83: Emulate HALT bug Other fixes: - 3DS: Redo video sync to be more precise
M include/mgba/internal/gba/renderers/gl.hinclude/mgba/internal/gba/renderers/gl.h

@@ -109,6 +109,7 @@ GBA_GL_OBJ_TRANSFORM,

GBA_GL_OBJ_DIMS, GBA_GL_OBJ_OBJWIN, GBA_GL_OBJ_MOSAIC, + GBA_GL_OBJ_CYCLES, GBA_GL_WIN_DISPCNT = 2, GBA_GL_WIN_BLEND,

@@ -123,7 +124,7 @@ GBA_GL_FINALIZE_WINDOW,

GBA_GL_FINALIZE_BACKDROP, GBA_GL_FINALIZE_BACKDROPFLAGS, - GBA_GL_UNIFORM_MAX = 12 + GBA_GL_UNIFORM_MAX = 14 }; struct GBAVideoGLShader {

@@ -183,6 +184,7 @@ GBAWindowControl control;

} winN[2]; GLint winNHistory[2][GBA_VIDEO_VERTICAL_PIXELS * 4]; + GLint spriteCycles[GBA_VIDEO_VERTICAL_PIXELS]; GBAWindowControl winout; GBAWindowControl objwin;

@@ -200,4 +202,4 @@ #endif

CXX_GUARD_END -#endif+#endif
M src/gba/renderers/gl.csrc/gba/renderers/gl.c

@@ -413,6 +413,7 @@ { "transform", GBA_GL_OBJ_TRANSFORM, },

{ "dims", GBA_GL_OBJ_DIMS, }, { "objwin", GBA_GL_OBJ_OBJWIN, }, { "mosaic", GBA_GL_OBJ_MOSAIC, }, + { "cyclesRemaining", GBA_GL_OBJ_CYCLES, }, { 0 } };

@@ -428,6 +429,7 @@ "uniform mat2x2 transform;\n"

"uniform ivec4 dims;\n" "uniform ivec4 objwin;\n" "uniform ivec4 mosaic;\n" + "uniform int cyclesRemaining[160];\n" "OUT(0) out vec4 color;\n" "OUT(1) out ivec4 flags;\n" "OUT(2) out ivec4 window;\n"

@@ -442,6 +444,9 @@ " incoord.x = float(clamp(x - (mosaic.z + x) % mosaic.x, 0, dims.z - 1));\n"

" } else if (mosaic.x < -1) {\n" " int x = dims.z - int(incoord.x) - 1;\n" " incoord.x = float(clamp(dims.z - x + (mosaic.z + x) % -mosaic.x - 1, 0, dims.z - 1));\n" + " }\n" + " if (cyclesRemaining[int(incoord.y) + mosaic.w] <= 0) {\n" + " discard;\n" " }\n" " if (mosaic.y > 1) {\n" " int y = int(incoord.y);\n"

@@ -1383,6 +1388,11 @@ glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo);

glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 }); glClear(GL_COLOR_BUFFER_BIT); } + + int spriteCyclesRemaining = GBARegisterDISPCNTIsHblankIntervalFree(glRenderer->dispcnt) ? OBJ_HBLANK_FREE_LENGTH : OBJ_LENGTH; + for (i = 0; i < GBA_VIDEO_VERTICAL_PIXELS; ++i) { + glRenderer->spriteCycles[i] = spriteCyclesRemaining; + } } if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {

@@ -1428,6 +1438,24 @@ continue;

} GBAVideoGLRendererDrawSprite(glRenderer, &sprite->obj, y, sprite->y); + + int startY = sprite->y; + int endY = sprite->endY; + + if (endY >= 256) { + startY -= 256; + endY -= 256; + } + if (startY < glRenderer->firstY) { + startY = glRenderer->firstY; + } + if (endY > y) { + endY = y; + } + int j; + for (j = startY; j <= endY; ++j) { + glRenderer->spriteCycles[j] -= sprite->cycles; + } } glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST);

@@ -1668,6 +1696,7 @@ glUniform1i(uniforms[GBA_GL_OBJ_LOCALPALETTE], GBAObjAttributesCGetPalette(sprite->c));

glUniform4i(uniforms[GBA_GL_OBJ_INFLAGS], GBAObjAttributesCGetPriority(sprite->c), (renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) | (renderer->target2Obj * 2) | (renderer->blendEffect * 4), renderer->blda, GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT); + glUniform1iv(uniforms[GBA_GL_OBJ_CYCLES], GBA_VIDEO_VERTICAL_PIXELS, renderer->spriteCycles); if (GBAObjAttributesAIsTransformed(sprite->a)) { struct GBAOAMMatrix mat; LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a);

@@ -1705,7 +1734,7 @@ mosaicH = -mosaicH;

} glUniform4i(uniforms[GBA_GL_OBJ_MOSAIC], mosaicH, GBAMosaicControlGetObjV(renderer->mosaic) + 1, x, spriteY); } else { - glUniform4i(uniforms[GBA_GL_OBJ_MOSAIC], 0, 0, 0, 0); + glUniform4i(uniforms[GBA_GL_OBJ_MOSAIC], 0, 0, x, spriteY); } glStencilFunc(GL_ALWAYS, 1, 1); if (GBAObjAttributesAGetMode(sprite->a) != OBJ_MODE_OBJWIN || GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt)) {