From 031049cd067d98cfc1172c15ac448f09300bdfa3 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 10 Jun 2020 01:28:39 -0700 Subject: [PATCH] GBA Video: Simplify sprite cycle counting (fixes #1279) --- CHANGES | 1 + include/mgba/internal/gba/renderers/common.h | 1 + src/gba/renderers/common.c | 5 +++++ src/gba/renderers/software-obj.c | 10 ---------- src/gba/renderers/video-software.c | 5 ++--- 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/CHANGES b/CHANGES index 3f8a020ab..3892f0400 100644 --- a/CHANGES +++ b/CHANGES @@ -27,6 +27,7 @@ Emulation fixes: - GBA Video: Fix disabling OBJWIN in GL renderer (fixes mgba.io/i/1759) - GBA Video: Add missing parts of 256-color mode 0 mosaic (fixes mgba.io/i/1701) - GBA Video: Fix double-size OBJ wrapping in GL renderer (fixes mgba.io/i/1712) + - GBA Video: Simplify sprite cycle counting (fixes mgba.io/i/1279) - SM83: Emulate HALT bug Other fixes: - 3DS: Fix framelimiter on newer citro3d (fixes mgba.io/i/1771) diff --git a/include/mgba/internal/gba/renderers/common.h b/include/mgba/internal/gba/renderers/common.h index ba368edc9..ed16917b6 100644 --- a/include/mgba/internal/gba/renderers/common.h +++ b/include/mgba/internal/gba/renderers/common.h @@ -16,6 +16,7 @@ struct GBAVideoRendererSprite { struct GBAObj obj; int16_t y; int16_t endY; + int16_t cycles; int8_t index; }; diff --git a/src/gba/renderers/common.c b/src/gba/renderers/common.c index 2ec71b3f7..4c35706ca 100644 --- a/src/gba/renderers/common.c +++ b/src/gba/renderers/common.c @@ -16,14 +16,19 @@ int GBAVideoRendererCleanOAM(struct GBAObj* oam, struct GBAVideoRendererSprite* LOAD_16LE(obj.b, 0, &oam[i].b); LOAD_16LE(obj.c, 0, &oam[i].c); if (GBAObjAttributesAIsTransformed(obj.a) || !GBAObjAttributesAIsDisable(obj.a)) { + int width = GBAVideoObjSizes[GBAObjAttributesAGetShape(obj.a) * 4 + GBAObjAttributesBGetSize(obj.b)][0]; int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(obj.a) * 4 + GBAObjAttributesBGetSize(obj.b)][1]; + int cycles = width; if (GBAObjAttributesAIsTransformed(obj.a)) { height <<= GBAObjAttributesAGetDoubleSize(obj.a); + width <<= GBAObjAttributesAGetDoubleSize(obj.a); + cycles = 10 + width * 2; } if (GBAObjAttributesAGetY(obj.a) < GBA_VIDEO_VERTICAL_PIXELS || GBAObjAttributesAGetY(obj.a) + height >= VIDEO_VERTICAL_TOTAL_PIXELS) { int y = GBAObjAttributesAGetY(obj.a) + offsetY; sprites[oamMax].y = y; sprites[oamMax].endY = y + height; + sprites[oamMax].cycles = cycles; sprites[oamMax].obj = obj; sprites[oamMax].index = i; ++oamMax; diff --git a/src/gba/renderers/software-obj.c b/src/gba/renderers/software-obj.c index 11b6737df..73df3ddc1 100644 --- a/src/gba/renderers/software-obj.c +++ b/src/gba/renderers/software-obj.c @@ -9,7 +9,6 @@ SPRITE_YBASE_ ## DEPTH(inY); \ unsigned tileData; \ for (; outX < condition; ++outX, inX += xOffset) { \ - renderer->spriteCyclesRemaining -= 1; \ SPRITE_XBASE_ ## DEPTH(inX); \ SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(inX); \ } @@ -33,7 +32,6 @@ unsigned widthMask = ~(width - 1); \ unsigned heightMask = ~(height - 1); \ for (; outX < condition; ++outX, ++inX) { \ - renderer->spriteCyclesRemaining -= 2; \ xAccum += mat.a; \ yAccum += mat.c; \ int localX = xAccum >> 8; \ @@ -55,7 +53,6 @@ int localX = xAccum >> 8; \ int localY = yAccum >> 8; \ for (; outX < condition; ++outX, ++inX) { \ - renderer->spriteCyclesRemaining -= 2; \ xAccum += mat.a; \ yAccum += mat.c; \ \ @@ -272,7 +269,6 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re if (outX < start || outX >= condition) { return 0; } - renderer->spriteCyclesRemaining -= 10; if (!GBAObjAttributesAIs256Color(sprite->a)) { palette = &palette[GBAObjAttributesCGetPalette(sprite->c) << 4]; @@ -306,9 +302,6 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re SPRITE_TRANSFORMED_LOOP(256, NORMAL); } } - if (end == GBA_VIDEO_HORIZONTAL_PIXELS && x + totalWidth > GBA_VIDEO_HORIZONTAL_PIXELS) { - renderer->spriteCyclesRemaining -= (x + totalWidth - GBA_VIDEO_HORIZONTAL_PIXELS) * 2; - } } else { int outX = x >= start ? x : start; int condition = x + width; @@ -366,9 +359,6 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re SPRITE_NORMAL_LOOP(256, NORMAL); } } - if (end == GBA_VIDEO_HORIZONTAL_PIXELS && x + width > GBA_VIDEO_HORIZONTAL_PIXELS) { - renderer->spriteCyclesRemaining -= x + width - GBA_VIDEO_HORIZONTAL_PIXELS; - } } return 1; } diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index 54e4f90cb..035f10d6b 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -845,12 +845,10 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) { } } for (w = 0; w < renderer->nWindows; ++w) { - if (renderer->spriteCyclesRemaining <= 0) { - break; - } renderer->currentWindow = renderer->windows[w].control; renderer->start = renderer->end; renderer->end = renderer->windows[w].endX; + // TODO: partial sprite drawing if (!GBAWindowControlIsObjEnable(renderer->currentWindow.packed) && !GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt)) { continue; } @@ -858,6 +856,7 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) { int drawn = GBAVideoSoftwareRendererPreprocessSprite(renderer, &sprite->obj, sprite->index, localY); spriteLayers |= drawn << GBAObjAttributesCGetPriority(sprite->obj.c); } + renderer->spriteCyclesRemaining -= sprite->cycles; if (renderer->spriteCyclesRemaining <= 0) { break; }