From f128f844a67e4cf6ddbe5b90171a4f983c1b5459 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 21 Sep 2015 20:32:15 -0700 Subject: [PATCH] GBA: Revamp frameskip --- src/gba/context/context.c | 7 +------ src/gba/context/context.h | 1 - src/gba/context/sync.c | 26 +++++++------------------- src/gba/context/sync.h | 4 +--- src/gba/gui/gui-runner.c | 1 + src/gba/supervisor/thread.c | 2 +- src/gba/video.c | 11 ++++++++--- src/gba/video.h | 2 ++ src/platform/qt/DisplayGL.cpp | 2 +- src/platform/qt/GameController.cpp | 13 +++++++------ src/platform/sdl/gl-sdl.c | 2 +- src/platform/sdl/gles2-sdl.c | 2 +- src/platform/sdl/pandora-sdl.c | 2 +- src/platform/sdl/sw-sdl.c | 2 +- src/platform/test/perf-main.c | 2 +- 15 files changed, 34 insertions(+), 45 deletions(-) diff --git a/src/gba/context/context.c b/src/gba/context/context.c index 3aecf2a55..18f70094c 100644 --- a/src/gba/context/context.c +++ b/src/gba/context/context.c @@ -60,7 +60,7 @@ bool GBAContextInit(struct GBAContext* context, const char* port) { GBAConfigLoadDefaults(&context->config, &opts); } - context->gba->sync = &context->sync; + context->gba->sync = 0; return true; } @@ -191,11 +191,6 @@ void GBAContextFrame(struct GBAContext* context, uint16_t keys) { while (frameCounter == context->gba->video.frameCounter) { 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) { diff --git a/src/gba/context/context.h b/src/gba/context/context.h index 1fcde3f24..0269e90af 100644 --- a/src/gba/context/context.h +++ b/src/gba/context/context.h @@ -24,7 +24,6 @@ struct GBAContext { struct GBAConfig config; struct GBAOptions opts; struct GBAInputMap inputMap; - struct GBASync sync; }; bool GBAContextInit(struct GBAContext* context, const char* port); diff --git a/src/gba/context/sync.c b/src/gba/context/sync.c index 335ebda4d..d0b13cf47 100644 --- a/src/gba/context/sync.c +++ b/src/gba/context/sync.c @@ -22,15 +22,12 @@ void GBASyncPostFrame(struct GBASync* sync) { MutexLock(&sync->videoFrameMutex); ++sync->videoFramePending; - --sync->videoFrameSkip; - if (sync->videoFrameSkip < 0) { - do { - ConditionWake(&sync->videoFrameAvailableCond); - if (sync->videoFrameWait) { - ConditionWait(&sync->videoFrameRequiredCond, &sync->videoFrameMutex); - } - } while (sync->videoFrameWait && sync->videoFramePending); - } + do { + ConditionWake(&sync->videoFrameAvailableCond); + if (sync->videoFrameWait) { + ConditionWait(&sync->videoFrameRequiredCond, &sync->videoFrameMutex); + } + } while (sync->videoFrameWait && sync->videoFramePending); MutexUnlock(&sync->videoFrameMutex); } @@ -44,7 +41,7 @@ void GBASyncForceFrame(struct GBASync* sync) { MutexUnlock(&sync->videoFrameMutex); } -bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip) { +bool GBASyncWaitFrameStart(struct GBASync* sync) { if (!sync) { return true; } @@ -60,7 +57,6 @@ bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip) { } } sync->videoFramePending = 0; - sync->videoFrameSkip = frameskip; return true; } @@ -72,14 +68,6 @@ void GBASyncWaitFrameEnd(struct GBASync* sync) { MutexUnlock(&sync->videoFrameMutex); } -bool GBASyncDrawingFrame(struct GBASync* sync) { - if (!sync) { - return true; - } - - return sync->videoFrameSkip <= 0; -} - void GBASyncSetVideoSync(struct GBASync* sync, bool wait) { if (!sync) { return; diff --git a/src/gba/context/sync.h b/src/gba/context/sync.h index a1aa65bcc..7440cc502 100644 --- a/src/gba/context/sync.h +++ b/src/gba/context/sync.h @@ -13,7 +13,6 @@ struct GBASync { int videoFramePending; bool videoFrameWait; - int videoFrameSkip; bool videoFrameOn; Mutex videoFrameMutex; Condition videoFrameAvailableCond; @@ -26,9 +25,8 @@ struct GBASync { void GBASyncPostFrame(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); -bool GBASyncDrawingFrame(struct GBASync* sync); void GBASyncSetVideoSync(struct GBASync* sync, bool wait); void GBASyncProduceAudio(struct GBASync* sync, bool wait); diff --git a/src/gba/gui/gui-runner.c b/src/gba/gui/gui-runner.c index 5a604fa60..ffded97cd 100644 --- a/src/gba/gui/gui-runner.c +++ b/src/gba/gui/gui-runner.c @@ -325,6 +325,7 @@ void GBAGUIRunloop(struct GBAGUIRunner* runner) { break; case RUNNER_CONFIG: GBAGUIShowConfig(runner, runner->configExtra, runner->nConfigExtra); + GBAConfigGetIntValue(&runner->context.config, "frameskip", &runner->context.gba->video.frameskip); break; case RUNNER_CONTINUE: break; diff --git a/src/gba/supervisor/thread.c b/src/gba/supervisor/thread.c index 2b0ef4bb8..d5c35e190 100644 --- a/src/gba/supervisor/thread.c +++ b/src/gba/supervisor/thread.c @@ -140,6 +140,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { gba.logLevel = threadContext->logLevel; gba.logHandler = threadContext->logHandler; gba.stream = threadContext->stream; + gba.video.frameskip = threadContext->frameskip; struct GBAThreadStop stop; if (threadContext->stopCallback) { @@ -386,7 +387,6 @@ bool GBAThreadStart(struct GBAThread* threadContext) { threadContext->activeKeys = 0; threadContext->state = THREAD_INITIALIZED; threadContext->sync.videoFrameOn = true; - threadContext->sync.videoFrameSkip = 0; threadContext->rewindBuffer = 0; threadContext->rewindScreenBuffer = 0; diff --git a/src/gba/video.c b/src/gba/video.c index d843d2470..6e9804f36 100644 --- a/src/gba/video.c +++ b/src/gba/video.c @@ -59,6 +59,7 @@ static struct GBAVideoRenderer dummyRenderer = { void GBAVideoInit(struct GBAVideo* video) { video->renderer = &dummyRenderer; video->vram = 0; + video->frameskip = 0; } void GBAVideoReset(struct GBAVideo* video) { @@ -80,6 +81,7 @@ void GBAVideoReset(struct GBAVideo* video) { video->nextVcounterIRQ = 0; video->frameCounter = 0; + video->frameskipCounter = 0; if (video->vram) { mappedMemoryFree(video->vram, SIZE_VRAM); @@ -154,7 +156,7 @@ int32_t GBAVideoProcessEvents(struct GBAVideo* video, int32_t cycles) { break; case VIDEO_VERTICAL_PIXELS: video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat); - if (GBASyncDrawingFrame(video->p->sync)) { + if (video->frameskipCounter <= 0) { video->renderer->finishFrame(video->renderer); } 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); } GBAFrameEnded(video->p); - GBASyncPostFrame(video->p->sync); + --video->frameskipCounter; + if (video->frameskipCounter < 0) { + video->frameskipCounter = video->frameskip; + } ++video->frameCounter; break; 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->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); } diff --git a/src/gba/video.h b/src/gba/video.h index 11957e4de..5250c123e 100644 --- a/src/gba/video.h +++ b/src/gba/video.h @@ -199,6 +199,8 @@ struct GBAVideo { union GBAOAM oam; int32_t frameCounter; + int frameskip; + int frameskipCounter; }; void GBAVideoInit(struct GBAVideo* video); diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index d0a5f4db3..62fb91ede 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -208,7 +208,7 @@ void PainterGL::draw() { if (m_queue.isEmpty()) { return; } - if (GBASyncWaitFrameStart(&m_context->sync, m_context->frameskip) || !m_queue.isEmpty()) { + if (GBASyncWaitFrameStart(&m_context->sync) || !m_queue.isEmpty()) { dequeue(); m_painter.begin(m_gl->context()->device()); performDraw(); diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index 68023a07a..a4db8ba5f 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -124,12 +124,8 @@ GameController::GameController(QObject* parent) m_threadContext.frameCallback = [](GBAThread* context) { GameController* controller = static_cast(context->userData); - if (GBASyncDrawingFrame(&controller->m_threadContext.sync)) { - 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)); - } else { - QMetaObject::invokeMethod(controller, "frameAvailable", Q_ARG(const uint32_t*, nullptr)); - } + 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)); if (controller->m_pauseAfterFrame.testAndSetAcquire(true, false)) { GBAThreadPauseFromThread(context); QMetaObject::invokeMethod(controller, "gamePaused", Q_ARG(GBAThread*, context)); @@ -773,7 +769,12 @@ void GameController::setAudioSync(bool set) { } void GameController::setFrameskip(int skip) { + threadInterrupt(); m_threadContext.frameskip = skip; + if (m_gameOpen) { + m_threadContext.gba->video.frameskip = skip; + } + threadContinue(); } void GameController::setVolume(int volume) { diff --git a/src/platform/sdl/gl-sdl.c b/src/platform/sdl/gl-sdl.c index 12073b12a..e343f1a8b 100644 --- a/src/platform/sdl/gl-sdl.c +++ b/src/platform/sdl/gl-sdl.c @@ -61,7 +61,7 @@ void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* rend #endif } - if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { + if (GBASyncWaitFrameStart(&context->sync)) { v->postFrame(v, renderer->d.outputBuffer); } v->drawFrame(v); diff --git a/src/platform/sdl/gles2-sdl.c b/src/platform/sdl/gles2-sdl.c index a3a617471..cf2bf8dc5 100644 --- a/src/platform/sdl/gles2-sdl.c +++ b/src/platform/sdl/gles2-sdl.c @@ -114,7 +114,7 @@ void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* r GBASDLHandleEvent(context, &renderer->player, &event); } - if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { + if (GBASyncWaitFrameStart(&context->sync)) { v->postFrame(v, renderer->d.outputBuffer); } v->drawFrame(v); diff --git a/src/platform/sdl/pandora-sdl.c b/src/platform/sdl/pandora-sdl.c index 0c95838e5..e9b2e19f4 100644 --- a/src/platform/sdl/pandora-sdl.c +++ b/src/platform/sdl/pandora-sdl.c @@ -71,7 +71,7 @@ void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* render GBASDLHandleEvent(context, &renderer->player, &event); } - if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { + if (GBASyncWaitFrameStart(&context->sync)) { int arg = 0; ioctl(renderer->fb, FBIO_WAITFORVSYNC, &arg); diff --git a/src/platform/sdl/sw-sdl.c b/src/platform/sdl/sw-sdl.c index b7090f61d..1a3a9b96c 100644 --- a/src/platform/sdl/sw-sdl.c +++ b/src/platform/sdl/sw-sdl.c @@ -93,7 +93,7 @@ void GBASDLSWRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* rend GBASDLHandleEvent(context, &renderer->player, &event); } - if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { + if (GBASyncWaitFrameStart(&context->sync)) { #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_UnlockTexture(renderer->sdlTex); SDL_RenderCopy(renderer->sdlRenderer, renderer->sdlTex, 0, 0); diff --git a/src/platform/test/perf-main.c b/src/platform/test/perf-main.c index a7009c01a..c99ef6177 100644 --- a/src/platform/test/perf-main.c +++ b/src/platform/test/perf-main.c @@ -167,7 +167,7 @@ static void _GBAPerfRunloop(struct GBAThread* context, int* frames, bool quiet) *frames = 0; int lastFrames = 0; while (context->state < THREAD_EXITING) { - if (GBASyncWaitFrameStart(&context->sync, 0)) { + if (GBASyncWaitFrameStart(&context->sync)) { ++*frames; ++lastFrames; if (!quiet) {