GBA Video: Improve sprite cycle counting (fixes #1274)

This commit is contained in:
Vicki Pfau 2019-01-19 22:01:41 -08:00
parent 6fecc6d379
commit 88ba6ee0b0
2 changed files with 20 additions and 16 deletions

View File

@ -8,6 +8,7 @@ Misc:
- GBA Savedata: Automatically map 1Mbit Flash files as 1Mbit Flash - GBA Savedata: Automatically map 1Mbit Flash files as 1Mbit Flash
- GB Memory: Support running from blocked memory - GB Memory: Support running from blocked memory
- Qt: Don't unload ROM immediately if it crashes - Qt: Don't unload ROM immediately if it crashes
- GBA Video: Improve sprite cycle counting (fixes mgba.io/i/1274)
0.7.0: (Future) 0.7.0: (Future)
Features: Features:

View File

@ -809,7 +809,6 @@ static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer*
static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) { static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) {
int w; int w;
renderer->end = 0;
int spriteLayers = 0; int spriteLayers = 0;
if (GBARegisterDISPCNTIsObjEnable(renderer->dispcnt) && !renderer->d.disableOBJ) { if (GBARegisterDISPCNTIsObjEnable(renderer->dispcnt) && !renderer->d.disableOBJ) {
if (renderer->oamDirty) { if (renderer->oamDirty) {
@ -818,31 +817,35 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) {
renderer->spriteCyclesRemaining = GBARegisterDISPCNTIsHblankIntervalFree(renderer->dispcnt) ? OBJ_HBLANK_FREE_LENGTH : OBJ_LENGTH; renderer->spriteCyclesRemaining = GBARegisterDISPCNTIsHblankIntervalFree(renderer->dispcnt) ? OBJ_HBLANK_FREE_LENGTH : OBJ_LENGTH;
int mosaicV = GBAMosaicControlGetObjV(renderer->mosaic) + 1; int mosaicV = GBAMosaicControlGetObjV(renderer->mosaic) + 1;
int mosaicY = y - (y % mosaicV); int mosaicY = y - (y % mosaicV);
for (w = 0; w < renderer->nWindows; ++w) {
renderer->start = renderer->end;
renderer->end = renderer->windows[w].endX;
renderer->currentWindow = renderer->windows[w].control;
if (!GBAWindowControlIsObjEnable(renderer->currentWindow.packed) && !GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt)) {
continue;
}
int i; int i;
int drawn;
for (i = 0; i < renderer->oamMax; ++i) { for (i = 0; i < renderer->oamMax; ++i) {
int localY = y;
if (renderer->spriteCyclesRemaining <= 0) {
break;
}
struct GBAVideoSoftwareSprite* sprite = &renderer->sprites[i]; struct GBAVideoSoftwareSprite* sprite = &renderer->sprites[i];
int localY = y;
renderer->end = 0;
if (GBAObjAttributesAIsMosaic(sprite->obj.a)) { if (GBAObjAttributesAIsMosaic(sprite->obj.a)) {
localY = mosaicY; localY = mosaicY;
} }
if ((localY < sprite->y && (sprite->endY - 256 < 0 || localY >= sprite->endY - 256)) || localY >= sprite->endY) { if ((localY < sprite->y && (sprite->endY - 256 < 0 || localY >= sprite->endY - 256)) || localY >= sprite->endY) {
continue; continue;
} }
for (w = 0; w < renderer->nWindows; ++w) {
if (renderer->spriteCyclesRemaining <= 0) {
break;
}
renderer->currentWindow = renderer->windows[w].control;
if (!GBAWindowControlIsObjEnable(renderer->currentWindow.packed) && !GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt)) {
continue;
}
int drawn;
renderer->start = renderer->end;
renderer->end = renderer->windows[w].endX;
drawn = GBAVideoSoftwareRendererPreprocessSprite(renderer, &sprite->obj, localY); drawn = GBAVideoSoftwareRendererPreprocessSprite(renderer, &sprite->obj, localY);
spriteLayers |= drawn << GBAObjAttributesCGetPriority(sprite->obj.c); spriteLayers |= drawn << GBAObjAttributesCGetPriority(sprite->obj.c);
} }
if (renderer->spriteCyclesRemaining <= 0) {
break;
}
} }
} }