all repos — mgba @ 19758d711528b15a255b353d1ef740d516b8685e

mGBA Game Boy Advance Emulator

GBA Video: Refactor video routines to be in a more consistent state during callbacks
Jeffrey Pfau jeffrey@endrift.com
Sat, 24 Jan 2015 01:02:09 -0800
commit

19758d711528b15a255b353d1ef740d516b8685e

parent

a7357df857cf775d339fbc24fd56de3f1be4fba2

M src/gba/gba-cli.csrc/gba/gba-cli.c

@@ -66,12 +66,12 @@ static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {

struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger; if (gbaDebugger->frameAdvance) { - if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(gbaDebugger->context->gba->video.dispstat)) { + if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(gbaDebugger->context->gba->memory.io[REG_DISPSTAT >> 1])) { ARMDebuggerEnter(&gbaDebugger->d.p->d, DEBUGGER_ENTER_BREAKPOINT); gbaDebugger->frameAdvance = false; return false; } - gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(gbaDebugger->context->gba->video.dispstat); + gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(gbaDebugger->context->gba->memory.io[REG_DISPSTAT >> 1]); return true; } return false;

@@ -96,7 +96,7 @@ debugger->d.state = DEBUGGER_CUSTOM;

struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system; gbaDebugger->frameAdvance = true; - gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(gbaDebugger->context->gba->video.dispstat); + gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(gbaDebugger->context->gba->memory.io[REG_DISPSTAT >> 1]); } static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
M src/gba/gba-thread.csrc/gba/gba-thread.c

@@ -616,25 +616,6 @@ }

} while (sync->videoFrameWait && sync->videoFramePending); } MutexUnlock(&sync->videoFrameMutex); - - struct GBAThread* thread = GBAThreadGetContext(); - if (!thread) { - return; - } - - if (thread->rewindBuffer) { - --thread->rewindBufferNext; - if (thread->rewindBufferNext <= 0) { - thread->rewindBufferNext = thread->rewindBufferInterval; - GBARecordFrame(thread); - } - } - if (thread->stream) { - thread->stream->postVideoFrame(thread->stream, thread->renderer); - } - if (thread->frameCallback) { - thread->frameCallback(thread); - } } bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip) {
M src/gba/gba-video.csrc/gba/gba-video.c

@@ -41,7 +41,6 @@ video->vram = 0;

} void GBAVideoReset(struct GBAVideo* video) { - video->dispstat = 0; video->vcount = VIDEO_VERTICAL_TOTAL_PIXELS - 1; video->lastHblank = 0;

@@ -96,53 +95,57 @@ video->lastHblank -= video->eventDiff;

video->nextHblank -= video->eventDiff; video->nextHblankIRQ -= video->eventDiff; video->nextVcounterIRQ -= video->eventDiff; + video->eventDiff = 0; + uint16_t dispstat = video->p->memory.io[REG_DISPSTAT >> 1]; - if (GBARegisterDISPSTATIsInHblank(video->dispstat)) { + if (GBARegisterDISPSTATIsInHblank(dispstat)) { // End Hblank - video->dispstat = GBARegisterDISPSTATClearInHblank(video->dispstat); + dispstat = GBARegisterDISPSTATClearInHblank(dispstat); video->nextEvent = video->nextHblank; ++video->vcount; + if (video->vcount == VIDEO_VERTICAL_TOTAL_PIXELS) { + video->vcount = 0; + } video->p->memory.io[REG_VCOUNT >> 1] = video->vcount; + if (video->vcount == GBARegisterDISPSTATGetVcountSetting(dispstat)) { + dispstat = GBARegisterDISPSTATFillVcounter(dispstat); + if (GBARegisterDISPSTATIsVcounterIRQ(dispstat)) { + GBARaiseIRQ(video->p, IRQ_VCOUNTER); + video->nextVcounterIRQ += VIDEO_TOTAL_LENGTH; + } + } else { + dispstat = GBARegisterDISPSTATClearVcounter(dispstat); + } + video->p->memory.io[REG_DISPSTAT >> 1] = dispstat; + + // Note: state may be recorded during callbacks, so ensure it is consistent! switch (video->vcount) { + case 0: + GBAFrameStarted(video->p); + break; case VIDEO_VERTICAL_PIXELS: - video->dispstat = GBARegisterDISPSTATFillInVblank(video->dispstat); + video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat); if (GBASyncDrawingFrame(video->p->sync)) { video->renderer->finishFrame(video->renderer); } video->nextVblankIRQ = video->nextEvent + VIDEO_TOTAL_LENGTH; GBAMemoryRunVblankDMAs(video->p, lastEvent); - if (GBARegisterDISPSTATIsVblankIRQ(video->dispstat)) { + if (GBARegisterDISPSTATIsVblankIRQ(dispstat)) { GBARaiseIRQ(video->p, IRQ_VBLANK); } + GBAFrameEnded(video->p); GBASyncPostFrame(video->p->sync); ++video->frameCounter; break; case VIDEO_VERTICAL_TOTAL_PIXELS - 1: - if (video->p->rr) { - GBARRNextFrame(video->p->rr); - } - video->dispstat = GBARegisterDISPSTATClearInVblank(video->dispstat); - break; - case VIDEO_VERTICAL_TOTAL_PIXELS: - video->vcount = 0; - video->p->memory.io[REG_VCOUNT >> 1] = 0; + video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATClearInVblank(dispstat); break; } - - if (video->vcount == GBARegisterDISPSTATGetVcountSetting(video->dispstat)) { - video->dispstat = GBARegisterDISPSTATFillVcounter(video->dispstat); - if (GBARegisterDISPSTATIsVcounterIRQ(video->dispstat)) { - GBARaiseIRQ(video->p, IRQ_VCOUNTER); - video->nextVcounterIRQ += VIDEO_TOTAL_LENGTH; - } - } else { - video->dispstat = GBARegisterDISPSTATClearVcounter(video->dispstat); - } } else { // Begin Hblank - video->dispstat = GBARegisterDISPSTATFillInHblank(video->dispstat); + dispstat = GBARegisterDISPSTATFillInHblank(dispstat); video->lastHblank = video->nextHblank; video->nextEvent = video->lastHblank + VIDEO_HBLANK_LENGTH; video->nextHblank = video->nextEvent + VIDEO_HDRAW_LENGTH;

@@ -155,25 +158,24 @@

if (video->vcount < VIDEO_VERTICAL_PIXELS) { GBAMemoryRunHblankDMAs(video->p, lastEvent); } - if (GBARegisterDISPSTATIsHblankIRQ(video->dispstat)) { + if (GBARegisterDISPSTATIsHblankIRQ(dispstat)) { GBARaiseIRQ(video->p, IRQ_HBLANK); } + video->p->memory.io[REG_DISPSTAT >> 1] = dispstat; } - - video->eventDiff = 0; } - video->p->memory.io[REG_DISPSTAT >> 1] &= 0xFFF8; - video->p->memory.io[REG_DISPSTAT >> 1] |= video->dispstat & 0x7; return video->nextEvent; } void GBAVideoWriteDISPSTAT(struct GBAVideo* video, uint16_t value) { - video->dispstat &= 0x7; - video->dispstat |= value & 0xFFF8; + video->p->memory.io[REG_DISPSTAT >> 1] &= 0x7; + video->p->memory.io[REG_DISPSTAT >> 1] |= value & 0xFFF8; + + uint16_t dispstat = video->p->memory.io[REG_DISPSTAT >> 1]; - if (GBARegisterDISPSTATIsVcounterIRQ(video->dispstat)) { + if (GBARegisterDISPSTATIsVcounterIRQ(dispstat)) { // FIXME: this can be too late if we're in the middle of an Hblank - video->nextVcounterIRQ = video->nextHblank + VIDEO_HBLANK_LENGTH + (GBARegisterDISPSTATGetVcountSetting(video->dispstat) - video->vcount) * VIDEO_HORIZONTAL_LENGTH; + video->nextVcounterIRQ = video->nextHblank + VIDEO_HBLANK_LENGTH + (GBARegisterDISPSTATGetVcountSetting(dispstat) - video->vcount) * VIDEO_HORIZONTAL_LENGTH; if (video->nextVcounterIRQ < video->nextEvent) { video->nextVcounterIRQ += VIDEO_TOTAL_LENGTH; }

@@ -237,7 +239,6 @@ void GBAVideoSerialize(struct GBAVideo* video, struct GBASerializedState* state) {

memcpy(state->vram, video->renderer->vram, SIZE_VRAM); memcpy(state->oam, video->oam.raw, SIZE_OAM); memcpy(state->pram, video->palette, SIZE_PALETTE_RAM); - state->io[REG_DISPSTAT >> 1] = video->dispstat; state->video.nextEvent = video->nextEvent; state->video.eventDiff = video->eventDiff; state->video.lastHblank = video->lastHblank;

@@ -257,7 +258,6 @@ }

for (i = 0; i < SIZE_PALETTE_RAM; i += 2) { GBAStore16(video->p->cpu, BASE_PALETTE_RAM | i, state->pram[i >> 1], 0); } - video->dispstat = state->io[REG_DISPSTAT >> 1]; video->nextEvent = state->video.nextEvent; video->eventDiff = state->video.eventDiff; video->lastHblank = state->video.lastHblank;
M src/gba/gba-video.hsrc/gba/gba-video.h

@@ -173,8 +173,6 @@ struct GBAVideo {

struct GBA* p; struct GBAVideoRenderer* renderer; - GBARegisterDISPSTAT dispstat; - // VCOUNT int vcount;
M src/gba/gba.csrc/gba/gba.c

@@ -8,6 +8,7 @@

#include "gba-bios.h" #include "gba-io.h" #include "gba-rr.h" +#include "gba-serialize.h" #include "gba-sio.h" #include "gba-thread.h"

@@ -634,3 +635,39 @@ if (gba->debugger) {

ARMDebuggerEnter(gba->debugger, DEBUGGER_ENTER_ILLEGAL_OP); } } + +void GBAFrameStarted(struct GBA* gba) { + UNUSED(gba); + + struct GBAThread* thread = GBAThreadGetContext(); + if (!thread) { + return; + } + + if (thread->rewindBuffer) { + --thread->rewindBufferNext; + if (thread->rewindBufferNext <= 0) { + thread->rewindBufferNext = thread->rewindBufferInterval; + GBARecordFrame(thread); + } + } +} + +void GBAFrameEnded(struct GBA* gba) { + if (gba->rr) { + GBARRNextFrame(gba->rr); + } + + struct GBAThread* thread = GBAThreadGetContext(); + if (!thread) { + return; + } + + if (thread->stream) { + thread->stream->postVideoFrame(thread->stream, thread->renderer); + } + + if (thread->frameCallback) { + thread->frameCallback(thread); + } +}
M src/gba/gba.hsrc/gba/gba.h

@@ -181,6 +181,9 @@ bool GBAIsBIOS(struct VFile* vf);

void GBAGetGameCode(struct GBA* gba, char* out); void GBAGetGameTitle(struct GBA* gba, char* out); +void GBAFrameStarted(struct GBA* gba); +void GBAFrameEnded(struct GBA* gba); + __attribute__((format (printf, 3, 4))) void GBALog(struct GBA* gba, enum GBALogLevel level, const char* format, ...);