mirror of https://github.com/mgba-emu/mgba.git
GBA Video: Refactor video routines to be in a more consistent state during callbacks
This commit is contained in:
parent
a7357df857
commit
19758d7115
|
@ -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 @@ static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
|||
|
||||
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) {
|
||||
|
|
|
@ -616,25 +616,6 @@ void GBASyncPostFrame(struct GBASync* sync) {
|
|||
} 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) {
|
||||
|
|
|
@ -41,7 +41,6 @@ void GBAVideoInit(struct GBAVideo* video) {
|
|||
}
|
||||
|
||||
void GBAVideoReset(struct GBAVideo* video) {
|
||||
video->dispstat = 0;
|
||||
video->vcount = VIDEO_VERTICAL_TOTAL_PIXELS - 1;
|
||||
|
||||
video->lastHblank = 0;
|
||||
|
@ -96,53 +95,57 @@ int32_t GBAVideoProcessEvents(struct GBAVideo* video, int32_t cycles) {
|
|||
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);
|
||||
video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATClearInVblank(dispstat);
|
||||
break;
|
||||
case VIDEO_VERTICAL_TOTAL_PIXELS:
|
||||
video->vcount = 0;
|
||||
video->p->memory.io[REG_VCOUNT >> 1] = 0;
|
||||
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 @@ int32_t GBAVideoProcessEvents(struct GBAVideo* video, int32_t cycles) {
|
|||
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;
|
||||
|
||||
if (GBARegisterDISPSTATIsVcounterIRQ(video->dispstat)) {
|
||||
uint16_t dispstat = video->p->memory.io[REG_DISPSTAT >> 1];
|
||||
|
||||
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 @@ void GBAVideoDeserialize(struct GBAVideo* video, struct GBASerializedState* stat
|
|||
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;
|
||||
|
|
|
@ -173,8 +173,6 @@ struct GBAVideo {
|
|||
struct GBA* p;
|
||||
struct GBAVideoRenderer* renderer;
|
||||
|
||||
GBARegisterDISPSTAT dispstat;
|
||||
|
||||
// VCOUNT
|
||||
int vcount;
|
||||
|
||||
|
|
|
@ -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 @@ void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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, ...);
|
||||
|
||||
|
|
Loading…
Reference in New Issue