diff --git a/CHANGES b/CHANGES index 7cc88f132..04eb39e17 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,7 @@ Emulation fixes: - GBA: Reset now reloads multiboot ROMs - GBA BIOS: Fix multiboot entry point (fixes Magic Floor) - GB Video: Delay LYC STAT check (fixes mgba.io/i/1331) + - GB Video: Fix window being enabled mid-scanline (fixes mgba.io/i/1328) Other fixes: - Qt: More app metadata fixes - Qt: Fix load recent from archive (fixes mgba.io/i/1325) diff --git a/include/mgba/internal/gb/renderers/software.h b/include/mgba/internal/gb/renderers/software.h index 3b8f7a210..fe4b1ff98 100644 --- a/include/mgba/internal/gb/renderers/software.h +++ b/include/mgba/internal/gb/renderers/software.h @@ -32,7 +32,9 @@ struct GBVideoSoftwareRenderer { uint8_t wy; uint8_t wx; uint8_t currentWy; + uint8_t currentWx; int lastY; + int lastX; bool hasWindow; GBRegisterLCDC lcdc; diff --git a/src/gb/renderers/software.c b/src/gb/renderers/software.c index c5e0d3c7a..4b1517ae0 100644 --- a/src/gb/renderers/software.c +++ b/src/gb/renderers/software.c @@ -190,7 +190,9 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum G softwareRenderer->scx = 0; softwareRenderer->wy = 0; softwareRenderer->currentWy = 0; + softwareRenderer->currentWx = 0; softwareRenderer->lastY = GB_VIDEO_VERTICAL_PIXELS; + softwareRenderer->lastX = 0; softwareRenderer->hasWindow = false; softwareRenderer->wx = 0; softwareRenderer->model = model; @@ -232,6 +234,9 @@ static void GBVideoSoftwareRendererUpdateWindow(struct GBVideoSoftwareRenderer* renderer->currentWy = GB_VIDEO_VERTICAL_PIXELS; } else { renderer->currentWy = renderer->lastY - renderer->wy; + if (renderer->lastY == renderer->wy && renderer->lastX > renderer->wx) { + ++renderer->currentWy; + } } } else { renderer->currentWy += renderer->lastY; @@ -489,6 +494,7 @@ static void GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, ui static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj* obj, size_t oamMax) { struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; softwareRenderer->lastY = y; + softwareRenderer->lastX = endX; uint8_t* maps = &softwareRenderer->d.vram[GB_BASE_MAP]; if (GBRegisterLCDCIsTileMap(softwareRenderer->lcdc)) { maps += GB_SIZE_MAP; @@ -498,9 +504,10 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i } if (GBRegisterLCDCIsBgEnable(softwareRenderer->lcdc) || softwareRenderer->model >= GB_MODEL_CGB) { int wy = softwareRenderer->wy + softwareRenderer->currentWy; - if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && wy <= y && endX >= softwareRenderer->wx - 7) { - if (softwareRenderer->wx - 7 > 0 && !softwareRenderer->d.disableBG) { - GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, softwareRenderer->wx - 7, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy); + int wx = softwareRenderer->wx + softwareRenderer->currentWx - 7; + if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && wy <= y && wx <= endX) { + if (wx > 0 && !softwareRenderer->d.disableBG) { + GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, wx, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy); } maps = &softwareRenderer->d.vram[GB_BASE_MAP]; @@ -508,7 +515,7 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i maps += GB_SIZE_MAP; } if (!softwareRenderer->d.disableWIN) { - GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, softwareRenderer->wx - 7, endX, 7 - softwareRenderer->wx - softwareRenderer->offsetWx, y - wy - softwareRenderer->offsetWy); + GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, wx, endX, -wx - softwareRenderer->offsetWx, y - wy - softwareRenderer->offsetWy); } } else if (!softwareRenderer->d.disableBG) { GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, endX, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy); @@ -612,6 +619,9 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* renderer, int y) { struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + softwareRenderer->lastX = 0; + softwareRenderer->currentWx = 0; + if (softwareRenderer->sgbTransfer == 1) { size_t offset = 2 * ((y & 7) + (y >> 3) * GB_VIDEO_HORIZONTAL_PIXELS); if (offset >= 0x1000) { @@ -702,7 +712,9 @@ static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer) } } softwareRenderer->lastY = GB_VIDEO_VERTICAL_PIXELS; + softwareRenderer->lastX = 0; softwareRenderer->currentWy = 0; + softwareRenderer->currentWx = 0; softwareRenderer->hasWindow = false; }