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);
}
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) {

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

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

View File

@ -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();

View File

@ -124,12 +124,8 @@ GameController::GameController(QObject* parent)
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::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) {

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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) {