GBA Video: Fix Hblank timing (fixes #2131, #2310)

This commit is contained in:
Vicki Pfau 2022-01-26 18:22:33 -08:00
parent 1d8141e1fd
commit d071bffe0a
3 changed files with 8 additions and 19 deletions

View File

@ -25,6 +25,7 @@ Emulation fixes:
- GBA Memory: Fix misaligned 32-bit I/O loads (fixes mgba.io/i/2307) - GBA Memory: Fix misaligned 32-bit I/O loads (fixes mgba.io/i/2307)
- GBA Video: Fix OpenGL rendering on M1 Macs - GBA Video: Fix OpenGL rendering on M1 Macs
- GBA Video: Ignore horizontally off-screen sprite timing (fixes mgba.io/i/2391) - GBA Video: Ignore horizontally off-screen sprite timing (fixes mgba.io/i/2391)
- GBA Video: Fix Hblank timing (fixes mgba.io/i/2131, mgba.io/i/2310)
Other fixes: Other fixes:
- Core: Don't attempt to restore rewind diffs past start of rewind - Core: Don't attempt to restore rewind diffs past start of rewind
- FFmpeg: Fix crash when encoding audio with some containers - FFmpeg: Fix crash when encoding audio with some containers

View File

@ -18,9 +18,8 @@ mLOG_DECLARE_CATEGORY(GBA_VIDEO);
enum { enum {
VIDEO_HBLANK_PIXELS = 68, VIDEO_HBLANK_PIXELS = 68,
VIDEO_HDRAW_LENGTH = 960, VIDEO_HDRAW_LENGTH = 1008,
VIDEO_HBLANK_LENGTH = 272, VIDEO_HBLANK_LENGTH = 224,
VIDEO_HBLANK_FLIP = 46,
VIDEO_HORIZONTAL_LENGTH = 1232, VIDEO_HORIZONTAL_LENGTH = 1232,
VIDEO_VBLANK_PIXELS = 68, VIDEO_VBLANK_PIXELS = 68,

View File

@ -31,7 +31,6 @@ static void GBAVideoDummyRendererGetPixels(struct GBAVideoRenderer* renderer, si
static void GBAVideoDummyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels); static void GBAVideoDummyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels);
static void _startHblank(struct mTiming*, void* context, uint32_t cyclesLate); static void _startHblank(struct mTiming*, void* context, uint32_t cyclesLate);
static void _midHblank(struct mTiming*, void* context, uint32_t cyclesLate);
static void _startHdraw(struct mTiming*, void* context, uint32_t cyclesLate); static void _startHdraw(struct mTiming*, void* context, uint32_t cyclesLate);
MGBA_EXPORT const int GBAVideoObjSizes[16][2] = { MGBA_EXPORT const int GBAVideoObjSizes[16][2] = {
@ -138,15 +137,6 @@ void GBAVideoAssociateRenderer(struct GBAVideo* video, struct GBAVideoRenderer*
} }
} }
void _midHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) {
struct GBAVideo* video = context;
GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1];
dispstat = GBARegisterDISPSTATClearInHblank(dispstat);
video->p->memory.io[REG_DISPSTAT >> 1] = dispstat;
video->event.callback = _startHdraw;
mTimingSchedule(timing, &video->event, VIDEO_HBLANK_FLIP - cyclesLate);
}
void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) { void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) {
struct GBAVideo* video = context; struct GBAVideo* video = context;
video->event.callback = _startHblank; video->event.callback = _startHblank;
@ -163,6 +153,7 @@ void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) {
} }
GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1]; GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1];
dispstat = GBARegisterDISPSTATClearInHblank(dispstat);
if (video->vcount == GBARegisterDISPSTATGetVcountSetting(dispstat)) { if (video->vcount == GBARegisterDISPSTATGetVcountSetting(dispstat)) {
dispstat = GBARegisterDISPSTATFillVcounter(dispstat); dispstat = GBARegisterDISPSTATFillVcounter(dispstat);
if (GBARegisterDISPSTATIsVcounterIRQ(dispstat)) { if (GBARegisterDISPSTATIsVcounterIRQ(dispstat)) {
@ -204,8 +195,8 @@ void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) {
void _startHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) { void _startHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) {
struct GBAVideo* video = context; struct GBAVideo* video = context;
video->event.callback = _midHblank; video->event.callback = _startHdraw;
mTimingSchedule(timing, &video->event, VIDEO_HBLANK_LENGTH - VIDEO_HBLANK_FLIP - cyclesLate); mTimingSchedule(timing, &video->event, VIDEO_HBLANK_LENGTH - cyclesLate);
// Begin Hblank // Begin Hblank
GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1]; GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1];
@ -221,7 +212,7 @@ void _startHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) {
GBADMARunDisplayStart(video->p, -cyclesLate); GBADMARunDisplayStart(video->p, -cyclesLate);
} }
if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) { if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) {
GBARaiseIRQ(video->p, IRQ_HBLANK, cyclesLate); GBARaiseIRQ(video->p, IRQ_HBLANK, cyclesLate - 6); // TODO: Where does this fudge factor come from?
} }
video->shouldStall = 0; video->shouldStall = 0;
video->p->memory.io[REG_DISPSTAT >> 1] = dispstat; video->p->memory.io[REG_DISPSTAT >> 1] = dispstat;
@ -343,8 +334,6 @@ void GBAVideoSerialize(const struct GBAVideo* video, struct GBASerializedState*
flags = GBASerializedVideoFlagsSetMode(flags, 1); flags = GBASerializedVideoFlagsSetMode(flags, 1);
} else if (video->event.callback == _startHblank) { } else if (video->event.callback == _startHblank) {
flags = GBASerializedVideoFlagsSetMode(flags, 2); flags = GBASerializedVideoFlagsSetMode(flags, 2);
} else if (video->event.callback == _midHblank) {
flags = GBASerializedVideoFlagsSetMode(flags, 3);
} }
STORE_32(flags, 0, &state->video.flags); STORE_32(flags, 0, &state->video.flags);
STORE_32(video->frameCounter, 0, &state->video.frameCounter); STORE_32(video->frameCounter, 0, &state->video.frameCounter);
@ -384,7 +373,7 @@ void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState
video->shouldStall = 1; video->shouldStall = 1;
break; break;
case 3: case 3:
video->event.callback = _midHblank; video->event.callback = _startHdraw;
break; break;
} }
uint32_t when; uint32_t when;