GBA: Revamp frameskip
jump to
@@ -60,7 +60,7 @@ GBAConfigLoad(&context->config);
GBAConfigLoadDefaults(&context->config, &opts); } - context->gba->sync = &context->sync; + context->gba->sync = 0; return true; }@@ -190,11 +190,6 @@
int frameCounter = context->gba->video.frameCounter; 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; } }
@@ -24,7 +24,6 @@ struct ARMComponent* components[GBA_COMPONENT_MAX];
struct GBAConfig config; struct GBAOptions opts; struct GBAInputMap inputMap; - struct GBASync sync; }; bool GBAContextInit(struct GBAContext* context, const char* port);
@@ -22,15 +22,12 @@ }
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 @@ ConditionWake(&sync->videoFrameAvailableCond);
MutexUnlock(&sync->videoFrameMutex); } -bool GBASyncWaitFrameStart(struct GBASync* sync, int frameskip) { +bool GBASyncWaitFrameStart(struct GBASync* sync) { if (!sync) { return true; }@@ -60,7 +57,6 @@ return false;
} } sync->videoFramePending = 0; - sync->videoFrameSkip = frameskip; return true; }@@ -70,14 +66,6 @@ return;
} MutexUnlock(&sync->videoFrameMutex); -} - -bool GBASyncDrawingFrame(struct GBASync* sync) { - if (!sync) { - return true; - } - - return sync->videoFrameSkip <= 0; } void GBASyncSetVideoSync(struct GBASync* sync, bool wait) {
@@ -13,7 +13,6 @@
struct GBASync { int videoFramePending; bool videoFrameWait; - int videoFrameSkip; bool videoFrameOn; Mutex videoFrameMutex; Condition videoFrameAvailableCond;@@ -26,9 +25,8 @@ };
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);
@@ -325,6 +325,7 @@ GBATakeScreenshot(runner->context.gba, 0);
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;
@@ -140,6 +140,7 @@ threadContext->cpu = &cpu;
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 @@ // TODO: error check
threadContext->activeKeys = 0; threadContext->state = THREAD_INITIALIZED; threadContext->sync.videoFrameOn = true; - threadContext->sync.videoFrameSkip = 0; threadContext->rewindBuffer = 0; threadContext->rewindScreenBuffer = 0;
@@ -59,6 +59,7 @@
void GBAVideoInit(struct GBAVideo* video) { video->renderer = &dummyRenderer; video->vram = 0; + video->frameskip = 0; } void GBAVideoReset(struct GBAVideo* video) {@@ -80,6 +81,7 @@ video->nextVblankIRQ = 0;
video->nextVcounterIRQ = 0; video->frameCounter = 0; + video->frameskipCounter = 0; if (video->vram) { mappedMemoryFree(video->vram, SIZE_VRAM);@@ -154,7 +156,7 @@ GBAFrameStarted(video->p);
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 @@ if (GBARegisterDISPSTATIsVblankIRQ(dispstat)) {
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 @@ video->nextEvent = video->lastHblank + VIDEO_HBLANK_LENGTH;
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); }
@@ -199,6 +199,8 @@ uint16_t* vram;
union GBAOAM oam; int32_t frameCounter; + int frameskip; + int frameskipCounter; }; void GBAVideoInit(struct GBAVideo* video);
@@ -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();
@@ -124,12 +124,8 @@ };
m_threadContext.frameCallback = [](GBAThread* context) { 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); - 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::setFrameskip(int skip) { + threadInterrupt(); m_threadContext.frameskip = skip; + if (m_gameOpen) { + m_threadContext.gba->video.frameskip = skip; + } + threadContinue(); } void GameController::setVolume(int volume) {
@@ -61,7 +61,7 @@ }
#endif } - if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { + if (GBASyncWaitFrameStart(&context->sync)) { v->postFrame(v, renderer->d.outputBuffer); } v->drawFrame(v);
@@ -114,7 +114,7 @@ while (SDL_PollEvent(&event)) {
GBASDLHandleEvent(context, &renderer->player, &event); } - if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { + if (GBASyncWaitFrameStart(&context->sync)) { v->postFrame(v, renderer->d.outputBuffer); } v->drawFrame(v);
@@ -71,7 +71,7 @@ while (SDL_PollEvent(&event)) {
GBASDLHandleEvent(context, &renderer->player, &event); } - if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) { + if (GBASyncWaitFrameStart(&context->sync)) { int arg = 0; ioctl(renderer->fb, FBIO_WAITFORVSYNC, &arg);
@@ -93,7 +93,7 @@ while (SDL_PollEvent(&event)) {
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);
@@ -167,7 +167,7 @@ int duration = *frames;
*frames = 0; int lastFrames = 0; while (context->state < THREAD_EXITING) { - if (GBASyncWaitFrameStart(&context->sync, 0)) { + if (GBASyncWaitFrameStart(&context->sync)) { ++*frames; ++lastFrames; if (!quiet) {