GBA Video: Simplify sprite cycle counting (fixes #1279)

This commit is contained in:
Vicki Pfau 2020-06-10 01:28:39 -07:00
parent d61d9ef6a6
commit 031049cd06
5 changed files with 9 additions and 13 deletions

View File

@ -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)

View File

@ -16,6 +16,7 @@ struct GBAVideoRendererSprite {
struct GBAObj obj;
int16_t y;
int16_t endY;
int16_t cycles;
int8_t index;
};

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}