mirror of https://github.com/mgba-emu/mgba.git
GBA Video: Improve emulation of window start/end conditions (fixes #1945)
This commit is contained in:
parent
e91da0f423
commit
eaee4228ba
1
CHANGES
1
CHANGES
|
@ -19,6 +19,7 @@ Emulation fixes:
|
|||
- GBA Serialize: Fix some minor save state edge cases
|
||||
- GBA SIO: Fix MULTI mode SIOCNT bit 7 writes on secondary GBAs (fixes mgba.io/i/3110)
|
||||
- GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722)
|
||||
- GBA Video: Improve emulation of window start/end conditions (fixes mgba.io/i/1945)
|
||||
Other fixes:
|
||||
- Core: Fix inconsistencies with setting game-specific overrides (fixes mgba.io/i/2963)
|
||||
- Debugger: Fix writing to specific segment in command-line debugger
|
||||
|
|
|
@ -118,6 +118,7 @@ struct GBAVideoSoftwareRenderer {
|
|||
struct WindowControl control;
|
||||
int16_t offsetX;
|
||||
int16_t offsetY;
|
||||
bool on;
|
||||
} winN[2];
|
||||
|
||||
struct WindowControl winout;
|
||||
|
@ -142,6 +143,7 @@ struct GBAVideoSoftwareRenderer {
|
|||
struct ScanlineCache {
|
||||
uint16_t io[GBA_REG(SOUND1CNT_LO)];
|
||||
int32_t scale[2][2];
|
||||
bool windowOn[2];
|
||||
} cache[GBA_VIDEO_VERTICAL_PIXELS];
|
||||
int nextY;
|
||||
|
||||
|
|
|
@ -35,14 +35,15 @@ static void GBAVideoSoftwareRendererWriteBGY_LO(struct GBAVideoSoftwareBackgroun
|
|||
static void GBAVideoSoftwareRendererWriteBGY_HI(struct GBAVideoSoftwareBackground* bg, uint16_t value);
|
||||
static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer, uint16_t value);
|
||||
|
||||
static void GBAVideoSoftwareRendererPreprocessBuffer(struct GBAVideoSoftwareRenderer* renderer, int y);
|
||||
static void GBAVideoSoftwareRendererStepWindow(struct GBAVideoSoftwareRenderer* renderer, int y);
|
||||
static void GBAVideoSoftwareRendererPreprocessBuffer(struct GBAVideoSoftwareRenderer* renderer);
|
||||
static void GBAVideoSoftwareRendererPostprocessBuffer(struct GBAVideoSoftwareRenderer* renderer);
|
||||
static int GBAVideoSoftwareRendererPreprocessSpriteLayer(struct GBAVideoSoftwareRenderer* renderer, int y);
|
||||
|
||||
static void _updatePalettes(struct GBAVideoSoftwareRenderer* renderer);
|
||||
static void _updateFlags(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* bg);
|
||||
|
||||
static void _breakWindow(struct GBAVideoSoftwareRenderer* softwareRenderer, struct WindowN* win, int y);
|
||||
static void _breakWindow(struct GBAVideoSoftwareRenderer* softwareRenderer, struct WindowN* win);
|
||||
static void _breakWindowInner(struct GBAVideoSoftwareRenderer* softwareRenderer, struct WindowN* win);
|
||||
|
||||
void GBAVideoSoftwareRendererCreate(struct GBAVideoSoftwareRenderer* renderer) {
|
||||
|
@ -343,28 +344,10 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender
|
|||
case GBA_REG_WIN0V:
|
||||
softwareRenderer->winN[0].v.end = value;
|
||||
softwareRenderer->winN[0].v.start = value >> 8;
|
||||
if (softwareRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && softwareRenderer->winN[0].v.start > softwareRenderer->winN[0].v.end) {
|
||||
softwareRenderer->winN[0].v.start = 0;
|
||||
}
|
||||
if (softwareRenderer->winN[0].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
|
||||
softwareRenderer->winN[0].v.end = GBA_VIDEO_VERTICAL_PIXELS;
|
||||
if (softwareRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
|
||||
softwareRenderer->winN[0].v.start = GBA_VIDEO_VERTICAL_PIXELS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GBA_REG_WIN1V:
|
||||
softwareRenderer->winN[1].v.end = value;
|
||||
softwareRenderer->winN[1].v.start = value >> 8;
|
||||
if (softwareRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && softwareRenderer->winN[1].v.start > softwareRenderer->winN[1].v.end) {
|
||||
softwareRenderer->winN[1].v.start = 0;
|
||||
}
|
||||
if (softwareRenderer->winN[1].v.end > GBA_VIDEO_VERTICAL_PIXELS) {
|
||||
softwareRenderer->winN[1].v.end = GBA_VIDEO_VERTICAL_PIXELS;
|
||||
if (softwareRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS) {
|
||||
softwareRenderer->winN[1].v.start = GBA_VIDEO_VERTICAL_PIXELS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GBA_REG_WININ:
|
||||
value &= 0x3F3F;
|
||||
|
@ -432,17 +415,7 @@ static void GBAVideoSoftwareRendererWritePalette(struct GBAVideoRenderer* render
|
|||
memset(softwareRenderer->scanlineDirty, 0xFFFFFFFF, sizeof(softwareRenderer->scanlineDirty));
|
||||
}
|
||||
|
||||
static void _breakWindow(struct GBAVideoSoftwareRenderer* softwareRenderer, struct WindowN* win, int y) {
|
||||
if (win->v.end >= win->v.start) {
|
||||
if (y >= win->v.end + win->offsetY) {
|
||||
return;
|
||||
}
|
||||
if (y < win->v.start + win->offsetY) {
|
||||
return;
|
||||
}
|
||||
} else if (y >= win->v.end + win->offsetY && y < win->v.start + win->offsetY) {
|
||||
return;
|
||||
}
|
||||
static void _breakWindow(struct GBAVideoSoftwareRenderer* softwareRenderer, struct WindowN* win) {
|
||||
if (win->h.end > GBA_VIDEO_HORIZONTAL_PIXELS || win->h.end < win->h.start) {
|
||||
struct WindowN splits[2] = { *win, *win };
|
||||
splits[0].h.start = 0;
|
||||
|
@ -585,6 +558,14 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
|
|||
softwareRenderer->cache[y].scale[1][0] = softwareRenderer->bg[3].sx;
|
||||
softwareRenderer->cache[y].scale[1][1] = softwareRenderer->bg[3].sy;
|
||||
|
||||
GBAVideoSoftwareRendererStepWindow(softwareRenderer, y);
|
||||
if (softwareRenderer->cache[y].windowOn[0] != softwareRenderer->winN[0].on ||
|
||||
softwareRenderer->cache[y].windowOn[1] != softwareRenderer->winN[1].on) {
|
||||
dirty = true;
|
||||
}
|
||||
softwareRenderer->cache[y].windowOn[0] = softwareRenderer->winN[0].on;
|
||||
softwareRenderer->cache[y].windowOn[1] = softwareRenderer->winN[1].on;
|
||||
|
||||
if (!dirty) {
|
||||
if (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt) != 0) {
|
||||
if (softwareRenderer->bg[2].enabled == ENABLED_MAX) {
|
||||
|
@ -610,7 +591,7 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render
|
|||
return;
|
||||
}
|
||||
|
||||
GBAVideoSoftwareRendererPreprocessBuffer(softwareRenderer, y);
|
||||
GBAVideoSoftwareRendererPreprocessBuffer(softwareRenderer);
|
||||
softwareRenderer->spriteCyclesRemaining = GBARegisterDISPCNTIsHblankIntervalFree(softwareRenderer->dispcnt) ? OBJ_HBLANK_FREE_LENGTH : OBJ_LENGTH;
|
||||
int spriteLayers = GBAVideoSoftwareRendererPreprocessSpriteLayer(softwareRenderer, y);
|
||||
|
||||
|
@ -747,6 +728,20 @@ static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* rendere
|
|||
if (softwareRenderer->bg[3].enabled > 0) {
|
||||
softwareRenderer->bg[3].enabled = ENABLED_MAX;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 2; ++i) {
|
||||
struct WindowN* win = &softwareRenderer->winN[i];
|
||||
if (win->v.end >= GBA_VIDEO_VERTICAL_PIXELS && win->v.end < VIDEO_VERTICAL_TOTAL_PIXELS) {
|
||||
win->on = false;
|
||||
}
|
||||
|
||||
if (win->v.start >= GBA_VIDEO_VERTICAL_PIXELS &&
|
||||
win->v.start < VIDEO_VERTICAL_TOTAL_PIXELS &&
|
||||
win->v.start > win->v.end) {
|
||||
win->on = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GBAVideoSoftwareRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {
|
||||
|
@ -855,7 +850,20 @@ static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer*
|
|||
}
|
||||
}
|
||||
|
||||
void GBAVideoSoftwareRendererPreprocessBuffer(struct GBAVideoSoftwareRenderer* softwareRenderer, int y) {
|
||||
void GBAVideoSoftwareRendererStepWindow(struct GBAVideoSoftwareRenderer* softwareRenderer, int y) {
|
||||
int i;
|
||||
for (i = 0; i < 2; ++i) {
|
||||
struct WindowN* win = &softwareRenderer->winN[i];
|
||||
if (y == win->v.start + win->offsetY) {
|
||||
win->on = true;
|
||||
}
|
||||
if (y == win->v.end + win->offsetY) {
|
||||
win->on = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GBAVideoSoftwareRendererPreprocessBuffer(struct GBAVideoSoftwareRenderer* softwareRenderer) {
|
||||
int x;
|
||||
for (x = 0; x < GBA_VIDEO_HORIZONTAL_PIXELS; x += 4) {
|
||||
softwareRenderer->spriteLayer[x] = FLAG_UNWRITTEN;
|
||||
|
@ -868,11 +876,11 @@ void GBAVideoSoftwareRendererPreprocessBuffer(struct GBAVideoSoftwareRenderer* s
|
|||
softwareRenderer->nWindows = 1;
|
||||
if (GBARegisterDISPCNTIsWin0Enable(softwareRenderer->dispcnt) || GBARegisterDISPCNTIsWin1Enable(softwareRenderer->dispcnt) || GBARegisterDISPCNTIsObjwinEnable(softwareRenderer->dispcnt)) {
|
||||
softwareRenderer->windows[0].control = softwareRenderer->winout;
|
||||
if (GBARegisterDISPCNTIsWin1Enable(softwareRenderer->dispcnt) && !softwareRenderer->d.disableWIN[1]) {
|
||||
_breakWindow(softwareRenderer, &softwareRenderer->winN[1], y);
|
||||
if (GBARegisterDISPCNTIsWin1Enable(softwareRenderer->dispcnt) && !softwareRenderer->d.disableWIN[1] && softwareRenderer->winN[1].on) {
|
||||
_breakWindow(softwareRenderer, &softwareRenderer->winN[1]);
|
||||
}
|
||||
if (GBARegisterDISPCNTIsWin0Enable(softwareRenderer->dispcnt) && !softwareRenderer->d.disableWIN[0]) {
|
||||
_breakWindow(softwareRenderer, &softwareRenderer->winN[0], y);
|
||||
if (GBARegisterDISPCNTIsWin0Enable(softwareRenderer->dispcnt) && !softwareRenderer->d.disableWIN[0] && softwareRenderer->winN[0].on) {
|
||||
_breakWindow(softwareRenderer, &softwareRenderer->winN[0]);
|
||||
}
|
||||
} else {
|
||||
softwareRenderer->windows[0].control.packed = 0xFF;
|
||||
|
|
Loading…
Reference in New Issue