GBA: Revamp frameskip

This commit is contained in:
Jeffrey Pfau 2015-09-21 20:32:15 -07:00
parent 4f24b82036
commit f128f844a6
15 changed files with 34 additions and 45 deletions

View File

@ -60,7 +60,7 @@ bool GBAContextInit(struct GBAContext* context, const char* port) {
GBAConfigLoadDefaults(&context->config, &opts); GBAConfigLoadDefaults(&context->config, &opts);
} }
context->gba->sync = &context->sync; context->gba->sync = 0;
return true; return true;
} }
@ -191,11 +191,6 @@ void GBAContextFrame(struct GBAContext* context, uint16_t keys) {
while (frameCounter == context->gba->video.frameCounter) { while (frameCounter == context->gba->video.frameCounter) {
ARMRunLoop(context->cpu); ARMRunLoop(context->cpu);
} }
if (context->sync.videoFrameSkip < 0) {
int frameskip = 0;
GBAConfigGetIntValue(&context->config, "frameskip", &frameskip);
context->sync.videoFrameSkip = frameskip;
}
} }
static void _GBAContextLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args) { static void _GBAContextLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args) {

View File

@ -24,7 +24,6 @@ struct GBAContext {
struct GBAConfig config; struct GBAConfig config;
struct GBAOptions opts; struct GBAOptions opts;
struct GBAInputMap inputMap; struct GBAInputMap inputMap;
struct GBASync sync;
}; };
bool GBAContextInit(struct GBAContext* context, const char* port); bool GBAContextInit(struct GBAContext* context, const char* port);

View File

@ -22,15 +22,12 @@ void GBASyncPostFrame(struct GBASync* sync) {
MutexLock(&sync->videoFrameMutex); MutexLock(&sync->videoFrameMutex);
++sync->videoFramePending; ++sync->videoFramePending;
--sync->videoFrameSkip;
if (sync->videoFrameSkip < 0) {
do { do {
ConditionWake(&sync->videoFrameAvailableCond); ConditionWake(&sync->videoFrameAvailableCond);
if (sync->videoFrameWait) { if (sync->videoFrameWait) {
ConditionWait(&sync->videoFrameRequiredCond, &sync->videoFrameMutex); ConditionWait(&sync->videoFrameRequiredCond, &sync->videoFrameMutex);
} }
} while (sync->videoFrameWait && sync->videoFramePending); } while (sync->videoFrameWait && sync->videoFramePending);
}
MutexUnlock(&sync->videoFrameMutex); MutexUnlock(&sync->videoFrameMutex);
} }
@ -44,7 +41,7 @@ void GBASyncForceFrame(struct GBASync* sync) {
MutexUnlock(&sync->videoFrameMutex); MutexUnlock(&sync->videoFrameMutex);
} }
bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip) { bool GBASyncWaitFrameStart(struct GBASync* sync) {
if (!sync) { if (!sync) {
return true; return true;
} }
@ -60,7 +57,6 @@ bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip) {
} }
} }
sync->videoFramePending = 0; sync->videoFramePending = 0;
sync->videoFrameSkip = frameskip;
return true; return true;
} }
@ -72,14 +68,6 @@ void GBASyncWaitFrameEnd(struct GBASync* sync) {
MutexUnlock(&sync->videoFrameMutex); MutexUnlock(&sync->videoFrameMutex);
} }
bool GBASyncDrawingFrame(struct GBASync* sync) {
if (!sync) {
return true;
}
return sync->videoFrameSkip <= 0;
}
void GBASyncSetVideoSync(struct GBASync* sync, bool wait) { void GBASyncSetVideoSync(struct GBASync* sync, bool wait) {
if (!sync) { if (!sync) {
return; return;

View File

@ -13,7 +13,6 @@
struct GBASync { struct GBASync {
int videoFramePending; int videoFramePending;
bool videoFrameWait; bool videoFrameWait;
int videoFrameSkip;
bool videoFrameOn; bool videoFrameOn;
Mutex videoFrameMutex; Mutex videoFrameMutex;
Condition videoFrameAvailableCond; Condition videoFrameAvailableCond;
@ -26,9 +25,8 @@ struct GBASync {
void GBASyncPostFrame(struct GBASync* sync); void GBASyncPostFrame(struct GBASync* sync);
void GBASyncForceFrame(struct GBASync* sync); void GBASyncForceFrame(struct GBASync* sync);
bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip); bool GBASyncWaitFrameStart(struct GBASync* sync);
void GBASyncWaitFrameEnd(struct GBASync* sync); void GBASyncWaitFrameEnd(struct GBASync* sync);
bool GBASyncDrawingFrame(struct GBASync* sync);
void GBASyncSetVideoSync(struct GBASync* sync, bool wait); void GBASyncSetVideoSync(struct GBASync* sync, bool wait);
void GBASyncProduceAudio(struct GBASync* sync, bool wait); void GBASyncProduceAudio(struct GBASync* sync, bool wait);

View File

@ -325,6 +325,7 @@ void GBAGUIRunloop(struct GBAGUIRunner* runner) {
break; break;
case RUNNER_CONFIG: case RUNNER_CONFIG:
GBAGUIShowConfig(runner, runner->configExtra, runner->nConfigExtra); GBAGUIShowConfig(runner, runner->configExtra, runner->nConfigExtra);
GBAConfigGetIntValue(&runner->context.config, "frameskip", &runner->context.gba->video.frameskip);
break; break;
case RUNNER_CONTINUE: case RUNNER_CONTINUE:
break; break;

View File

@ -140,6 +140,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
gba.logLevel = threadContext->logLevel; gba.logLevel = threadContext->logLevel;
gba.logHandler = threadContext->logHandler; gba.logHandler = threadContext->logHandler;
gba.stream = threadContext->stream; gba.stream = threadContext->stream;
gba.video.frameskip = threadContext->frameskip;
struct GBAThreadStop stop; struct GBAThreadStop stop;
if (threadContext->stopCallback) { if (threadContext->stopCallback) {
@ -386,7 +387,6 @@ bool GBAThreadStart(struct GBAThread* threadContext) {
threadContext->activeKeys = 0; threadContext->activeKeys = 0;
threadContext->state = THREAD_INITIALIZED; threadContext->state = THREAD_INITIALIZED;
threadContext->sync.videoFrameOn = true; threadContext->sync.videoFrameOn = true;
threadContext->sync.videoFrameSkip = 0;
threadContext->rewindBuffer = 0; threadContext->rewindBuffer = 0;
threadContext->rewindScreenBuffer = 0; threadContext->rewindScreenBuffer = 0;

View File

@ -59,6 +59,7 @@ static struct GBAVideoRenderer dummyRenderer = {
void GBAVideoInit(struct GBAVideo* video) { void GBAVideoInit(struct GBAVideo* video) {
video->renderer = &dummyRenderer; video->renderer = &dummyRenderer;
video->vram = 0; video->vram = 0;
video->frameskip = 0;
} }
void GBAVideoReset(struct GBAVideo* video) { void GBAVideoReset(struct GBAVideo* video) {
@ -80,6 +81,7 @@ void GBAVideoReset(struct GBAVideo* video) {
video->nextVcounterIRQ = 0; video->nextVcounterIRQ = 0;
video->frameCounter = 0; video->frameCounter = 0;
video->frameskipCounter = 0;
if (video->vram) { if (video->vram) {
mappedMemoryFree(video->vram, SIZE_VRAM); mappedMemoryFree(video->vram, SIZE_VRAM);
@ -154,7 +156,7 @@ int32_t GBAVideoProcessEvents(struct GBAVideo* video, int32_t cycles) {
break; break;
case VIDEO_VERTICAL_PIXELS: case VIDEO_VERTICAL_PIXELS:
video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat); video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat);
if (GBASyncDrawingFrame(video->p->sync)) { if (video->frameskipCounter <= 0) {
video->renderer->finishFrame(video->renderer); video->renderer->finishFrame(video->renderer);
} }
video->nextVblankIRQ = video->nextEvent + VIDEO_TOTAL_LENGTH; video->nextVblankIRQ = video->nextEvent + VIDEO_TOTAL_LENGTH;
@ -163,7 +165,10 @@ int32_t GBAVideoProcessEvents(struct GBAVideo* video, int32_t cycles) {
GBARaiseIRQ(video->p, IRQ_VBLANK); GBARaiseIRQ(video->p, IRQ_VBLANK);
} }
GBAFrameEnded(video->p); GBAFrameEnded(video->p);
GBASyncPostFrame(video->p->sync); --video->frameskipCounter;
if (video->frameskipCounter < 0) {
video->frameskipCounter = video->frameskip;
}
++video->frameCounter; ++video->frameCounter;
break; break;
case VIDEO_VERTICAL_TOTAL_PIXELS - 1: case VIDEO_VERTICAL_TOTAL_PIXELS - 1:
@ -178,7 +183,7 @@ int32_t GBAVideoProcessEvents(struct GBAVideo* video, int32_t cycles) {
video->nextHblank = video->nextEvent + VIDEO_HDRAW_LENGTH; video->nextHblank = video->nextEvent + VIDEO_HDRAW_LENGTH;
video->nextHblankIRQ = video->nextHblank; video->nextHblankIRQ = video->nextHblank;
if (video->vcount < VIDEO_VERTICAL_PIXELS && GBASyncDrawingFrame(video->p->sync)) { if (video->vcount < VIDEO_VERTICAL_PIXELS && video->frameskipCounter <= 0) {
video->renderer->drawScanline(video->renderer, video->vcount); video->renderer->drawScanline(video->renderer, video->vcount);
} }

View File

@ -199,6 +199,8 @@ struct GBAVideo {
union GBAOAM oam; union GBAOAM oam;
int32_t frameCounter; int32_t frameCounter;
int frameskip;
int frameskipCounter;
}; };
void GBAVideoInit(struct GBAVideo* video); void GBAVideoInit(struct GBAVideo* video);

View File

@ -208,7 +208,7 @@ void PainterGL::draw() {
if (m_queue.isEmpty()) { if (m_queue.isEmpty()) {
return; return;
} }
if (GBASyncWaitFrameStart(&m_context->sync, m_context->frameskip) || !m_queue.isEmpty()) { if (GBASyncWaitFrameStart(&m_context->sync) || !m_queue.isEmpty()) {
dequeue(); dequeue();
m_painter.begin(m_gl->context()->device()); m_painter.begin(m_gl->context()->device());
performDraw(); performDraw();

View File

@ -124,12 +124,8 @@ GameController::GameController(QObject* parent)
m_threadContext.frameCallback = [](GBAThread* context) { m_threadContext.frameCallback = [](GBAThread* context) {
GameController* controller = static_cast<GameController*>(context->userData); GameController* controller = static_cast<GameController*>(context->userData);
if (GBASyncDrawingFrame(&controller->m_threadContext.sync)) {
memcpy(controller->m_frontBuffer, controller->m_drawContext, 256 * VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL); memcpy(controller->m_frontBuffer, controller->m_drawContext, 256 * VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL);
QMetaObject::invokeMethod(controller, "frameAvailable", Q_ARG(const uint32_t*, controller->m_frontBuffer)); QMetaObject::invokeMethod(controller, "frameAvailable", Q_ARG(const uint32_t*, controller->m_frontBuffer));
} else {
QMetaObject::invokeMethod(controller, "frameAvailable", Q_ARG(const uint32_t*, nullptr));
}
if (controller->m_pauseAfterFrame.testAndSetAcquire(true, false)) { if (controller->m_pauseAfterFrame.testAndSetAcquire(true, false)) {
GBAThreadPauseFromThread(context); GBAThreadPauseFromThread(context);
QMetaObject::invokeMethod(controller, "gamePaused", Q_ARG(GBAThread*, context)); QMetaObject::invokeMethod(controller, "gamePaused", Q_ARG(GBAThread*, context));
@ -773,7 +769,12 @@ void GameController::setAudioSync(bool set) {
} }
void GameController::setFrameskip(int skip) { void GameController::setFrameskip(int skip) {
threadInterrupt();
m_threadContext.frameskip = skip; m_threadContext.frameskip = skip;
if (m_gameOpen) {
m_threadContext.gba->video.frameskip = skip;
}
threadContinue();
} }
void GameController::setVolume(int volume) { void GameController::setVolume(int volume) {

View File

@ -61,7 +61,7 @@ void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* rend
#endif #endif
} }
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { if (GBASyncWaitFrameStart(&context->sync)) {
v->postFrame(v, renderer->d.outputBuffer); v->postFrame(v, renderer->d.outputBuffer);
} }
v->drawFrame(v); v->drawFrame(v);

View File

@ -114,7 +114,7 @@ void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* r
GBASDLHandleEvent(context, &renderer->player, &event); GBASDLHandleEvent(context, &renderer->player, &event);
} }
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { if (GBASyncWaitFrameStart(&context->sync)) {
v->postFrame(v, renderer->d.outputBuffer); v->postFrame(v, renderer->d.outputBuffer);
} }
v->drawFrame(v); v->drawFrame(v);

View File

@ -71,7 +71,7 @@ void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* render
GBASDLHandleEvent(context, &renderer->player, &event); GBASDLHandleEvent(context, &renderer->player, &event);
} }
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { if (GBASyncWaitFrameStart(&context->sync)) {
int arg = 0; int arg = 0;
ioctl(renderer->fb, FBIO_WAITFORVSYNC, &arg); ioctl(renderer->fb, FBIO_WAITFORVSYNC, &arg);

View File

@ -93,7 +93,7 @@ void GBASDLSWRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* rend
GBASDLHandleEvent(context, &renderer->player, &event); GBASDLHandleEvent(context, &renderer->player, &event);
} }
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { if (GBASyncWaitFrameStart(&context->sync)) {
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_UnlockTexture(renderer->sdlTex); SDL_UnlockTexture(renderer->sdlTex);
SDL_RenderCopy(renderer->sdlRenderer, renderer->sdlTex, 0, 0); SDL_RenderCopy(renderer->sdlRenderer, renderer->sdlTex, 0, 0);

View File

@ -167,7 +167,7 @@ static void _GBAPerfRunloop(struct GBAThread* context, int* frames, bool quiet)
*frames = 0; *frames = 0;
int lastFrames = 0; int lastFrames = 0;
while (context->state < THREAD_EXITING) { while (context->state < THREAD_EXITING) {
if (GBASyncWaitFrameStart(&context->sync, 0)) { if (GBASyncWaitFrameStart(&context->sync)) {
++*frames; ++*frames;
++lastFrames; ++lastFrames;
if (!quiet) { if (!quiet) {