mirror of https://github.com/mgba-emu/mgba.git
GBA: Revamp frameskip
This commit is contained in:
parent
4f24b82036
commit
f128f844a6
src
gba
platform
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -199,6 +199,8 @@ struct GBAVideo {
|
|||
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 @@ 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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue