mirror of https://github.com/mgba-emu/mgba.git
Core: Put back rewind
This commit is contained in:
parent
e9d83bafe3
commit
56722324ef
|
@ -307,7 +307,6 @@ void mCoreConfigMap(const struct mCoreConfig* config, struct mCoreOptions* opts)
|
|||
_lookupIntValue(config, "frameskip", &opts->frameskip);
|
||||
_lookupIntValue(config, "volume", &opts->volume);
|
||||
_lookupIntValue(config, "rewindBufferCapacity", &opts->rewindBufferCapacity);
|
||||
_lookupIntValue(config, "rewindBufferInterval", &opts->rewindBufferInterval);
|
||||
_lookupFloatValue(config, "fpsTarget", &opts->fpsTarget);
|
||||
unsigned audioBuffers;
|
||||
if (_lookupUIntValue(config, "audioBuffers", &audioBuffers)) {
|
||||
|
@ -363,7 +362,6 @@ void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptio
|
|||
ConfigurationSetIntValue(&config->defaultsTable, 0, "frameskip", opts->frameskip);
|
||||
ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindEnable", opts->rewindEnable);
|
||||
ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferCapacity", opts->rewindBufferCapacity);
|
||||
ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferInterval", opts->rewindBufferInterval);
|
||||
ConfigurationSetFloatValue(&config->defaultsTable, 0, "fpsTarget", opts->fpsTarget);
|
||||
ConfigurationSetUIntValue(&config->defaultsTable, 0, "audioBuffers", opts->audioBuffers);
|
||||
ConfigurationSetUIntValue(&config->defaultsTable, 0, "sampleRate", opts->sampleRate);
|
||||
|
|
|
@ -25,7 +25,6 @@ struct mCoreOptions {
|
|||
int frameskip;
|
||||
bool rewindEnable;
|
||||
int rewindBufferCapacity;
|
||||
int rewindBufferInterval;
|
||||
float fpsTarget;
|
||||
size_t audioBuffers;
|
||||
unsigned sampleRate;
|
||||
|
|
|
@ -145,6 +145,9 @@ void mCoreTakeScreenshot(struct mCore* core);
|
|||
struct mCore* mCoreFindVF(struct VFile* vf);
|
||||
enum mPlatform mCoreIsCompatible(struct VFile* vf);
|
||||
|
||||
bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags);
|
||||
bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags);
|
||||
|
||||
void mCoreInitConfig(struct mCore* core, const char* port);
|
||||
void mCoreLoadConfig(struct mCore* core);
|
||||
void mCoreLoadForeignConfig(struct mCore* core, const struct mCoreConfig* config);
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "rewind.h"
|
||||
|
||||
#include "core/core.h"
|
||||
#include "util/patch-fast.h"
|
||||
#include "util/vfs.h"
|
||||
|
||||
DEFINE_VECTOR(mCoreRewindPatches, struct PatchFast);
|
||||
|
||||
void mCoreRewindContextInit(struct mCoreRewindContext* context, size_t entries) {
|
||||
mCoreRewindPatchesInit(&context->patchMemory, entries);
|
||||
size_t e;
|
||||
for (e = 0; e < entries; ++e) {
|
||||
initPatchFast(mCoreRewindPatchesAppend(&context->patchMemory));
|
||||
}
|
||||
context->previousState = VFileMemChunk(0, 0);
|
||||
context->currentState = VFileMemChunk(0, 0);
|
||||
context->size = 0;
|
||||
}
|
||||
|
||||
void mCoreRewindContextDeinit(struct mCoreRewindContext* context) {
|
||||
context->previousState->close(context->previousState);
|
||||
context->currentState->close(context->currentState);
|
||||
size_t s;
|
||||
for (s = 0; s < mCoreRewindPatchesSize(&context->patchMemory); ++s) {
|
||||
deinitPatchFast(mCoreRewindPatchesGetPointer(&context->patchMemory, s));
|
||||
}
|
||||
mCoreRewindPatchesDeinit(&context->patchMemory);
|
||||
}
|
||||
|
||||
void mCoreRewindAppend(struct mCoreRewindContext* context, struct mCore* core) {
|
||||
struct VFile* nextState = context->previousState;
|
||||
++context->current;
|
||||
if (context->size < mCoreRewindPatchesSize(&context->patchMemory)) {
|
||||
++context->size;
|
||||
}
|
||||
if (context->current >= mCoreRewindPatchesSize(&context->patchMemory)) {
|
||||
context->current = 0;
|
||||
}
|
||||
mCoreSaveStateNamed(core, nextState, 0);
|
||||
struct PatchFast* patch = mCoreRewindPatchesGetPointer(&context->patchMemory, context->current);
|
||||
size_t size2 = nextState->size(nextState);
|
||||
size_t size = context->currentState->size(context->currentState);
|
||||
if (size2 > size) {
|
||||
context->currentState->truncate(context->currentState, size2);
|
||||
size = size2;
|
||||
}
|
||||
void* current = context->currentState->map(context->currentState, size, MAP_READ);
|
||||
void* next = nextState->map(nextState, size, MAP_READ);
|
||||
diffPatchFast(patch, current, next, size);
|
||||
context->currentState->unmap(context->currentState, current, size);
|
||||
nextState->unmap(next, nextState, size);
|
||||
context->previousState = context->currentState;
|
||||
context->currentState = nextState;
|
||||
}
|
||||
|
||||
bool mCoreRewindRestore(struct mCoreRewindContext* context, struct mCore* core) {
|
||||
if (!context->size) {
|
||||
return false;
|
||||
}
|
||||
--context->size;
|
||||
|
||||
struct PatchFast* patch = mCoreRewindPatchesGetPointer(&context->patchMemory, context->current);
|
||||
size_t size2 = context->previousState->size(context->previousState);
|
||||
size_t size = context->currentState->size(context->currentState);
|
||||
if (size2 < size) {
|
||||
size = size2;
|
||||
}
|
||||
void* current = context->currentState->map(context->currentState, size, MAP_READ);
|
||||
void* previous = context->previousState->map(context->previousState, size, MAP_WRITE);
|
||||
patch->d.applyPatch(&patch->d, current, size, previous, size);
|
||||
context->currentState->unmap(context->currentState, current, size);
|
||||
context->previousState->unmap(context->previousState, previous, size);
|
||||
mCoreLoadStateNamed(core, context->previousState, 0);
|
||||
struct VFile* nextState = context->previousState;
|
||||
context->previousState = context->currentState;
|
||||
context->currentState = nextState;
|
||||
|
||||
if (context->current == 0) {
|
||||
context->current = mCoreRewindPatchesSize(&context->patchMemory);
|
||||
}
|
||||
--context->current;
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/* Copyright (c) 2013-2016 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef M_CORE_REWIND_H
|
||||
#define M_CORE_REWIND_H
|
||||
|
||||
#include "util/common.h"
|
||||
|
||||
#include "util/vector.h"
|
||||
|
||||
DECLARE_VECTOR(mCoreRewindPatches, struct PatchFast);
|
||||
|
||||
struct VFile;
|
||||
struct mCoreRewindContext {
|
||||
struct mCoreRewindPatches patchMemory;
|
||||
size_t current;
|
||||
size_t size;
|
||||
struct VFile* previousState;
|
||||
struct VFile* currentState;
|
||||
};
|
||||
|
||||
void mCoreRewindContextInit(struct mCoreRewindContext*, size_t entries);
|
||||
void mCoreRewindContextDeinit(struct mCoreRewindContext*);
|
||||
|
||||
struct mCore;
|
||||
void mCoreRewindAppend(struct mCoreRewindContext*, struct mCore*);
|
||||
bool mCoreRewindRestore(struct mCoreRewindContext*, struct mCore*);
|
||||
|
||||
#endif
|
|
@ -109,6 +109,10 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
|||
core->setSync(core, &threadContext->sync);
|
||||
core->reset(core);
|
||||
|
||||
if (core->opts.rewindEnable) {
|
||||
mCoreRewindContextInit(&threadContext->rewind, core->opts.rewindBufferCapacity);
|
||||
}
|
||||
|
||||
_changeState(threadContext, THREAD_RUNNING, true);
|
||||
|
||||
if (threadContext->startCallback) {
|
||||
|
@ -126,14 +130,14 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
|||
_changeState(threadContext, THREAD_EXITING, false);
|
||||
}
|
||||
} else {
|
||||
while (threadContext->state == THREAD_RUNNING) {
|
||||
while (threadContext->state <= THREAD_MAX_RUNNING) {
|
||||
core->runLoop(core);
|
||||
}
|
||||
}
|
||||
|
||||
int resetScheduled = 0;
|
||||
MutexLock(&threadContext->stateMutex);
|
||||
while (threadContext->state > THREAD_RUNNING && threadContext->state < THREAD_EXITING) {
|
||||
while (threadContext->state > THREAD_MAX_RUNNING && threadContext->state < THREAD_EXITING) {
|
||||
if (threadContext->state == THREAD_PAUSING) {
|
||||
threadContext->state = THREAD_PAUSED;
|
||||
ConditionWake(&threadContext->stateCond);
|
||||
|
@ -170,6 +174,10 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
|||
_changeState(threadContext, THREAD_SHUTDOWN, false);
|
||||
}
|
||||
|
||||
if (core->opts.rewindEnable) {
|
||||
mCoreRewindContextDeinit(&threadContext->rewind);
|
||||
}
|
||||
|
||||
if (threadContext->cleanCallback) {
|
||||
threadContext->cleanCallback(threadContext);
|
||||
}
|
||||
|
@ -422,6 +430,18 @@ void mCoreThreadPauseFromThread(struct mCoreThread* threadContext) {
|
|||
mCoreSyncSetVideoSync(&threadContext->sync, frameOn);
|
||||
}
|
||||
|
||||
void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool rewinding) {
|
||||
MutexLock(&threadContext->stateMutex);
|
||||
_waitOnInterrupt(threadContext);
|
||||
if (rewinding && threadContext->state == THREAD_RUNNING) {
|
||||
threadContext->state = THREAD_REWINDING;
|
||||
}
|
||||
if (!rewinding && threadContext->state == THREAD_REWINDING) {
|
||||
threadContext->state = THREAD_RUNNING;
|
||||
}
|
||||
MutexUnlock(&threadContext->stateMutex);
|
||||
}
|
||||
|
||||
#ifdef USE_PTHREADS
|
||||
struct mCoreThread* mCoreThreadGet(void) {
|
||||
pthread_once(&_contextOnce, _createTLS);
|
||||
|
@ -438,10 +458,41 @@ struct mCoreThread* mCoreThreadGet(void) {
|
|||
}
|
||||
#endif
|
||||
|
||||
void mCoreThreadFrameStarted(struct mCoreThread* thread) {
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
if (thread->core->opts.rewindEnable && thread->state != THREAD_REWINDING) {
|
||||
mCoreRewindAppend(&thread->rewind, thread->core);
|
||||
} else if (thread->state == THREAD_REWINDING) {
|
||||
if (!mCoreRewindRestore(&thread->rewind, thread->core)) {
|
||||
mCoreRewindAppend(&thread->rewind, thread->core);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mCoreThreadFrameEnded(struct mCoreThread* thread) {
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
if (thread->frameCallback) {
|
||||
thread->frameCallback(thread);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
struct mCoreThread* mCoreThreadGet(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mCoreThreadFrameStarted(struct mCoreThread* thread) {
|
||||
UNUSED(thread);
|
||||
}
|
||||
|
||||
void mCoreThreadFrameEnded(struct mCoreThread* thread) {
|
||||
UNUSED(thread);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "util/common.h"
|
||||
|
||||
#include "core/log.h"
|
||||
#include "core/rewind.h"
|
||||
#include "core/sync.h"
|
||||
#include "util/threading.h"
|
||||
|
||||
|
@ -20,6 +21,8 @@ typedef void (*ThreadCallback)(struct mCoreThread* threadContext);
|
|||
enum mCoreThreadState {
|
||||
THREAD_INITIALIZED = -1,
|
||||
THREAD_RUNNING = 0,
|
||||
THREAD_REWINDING,
|
||||
THREAD_MAX_RUNNING = THREAD_REWINDING,
|
||||
THREAD_INTERRUPTED,
|
||||
THREAD_INTERRUPTING,
|
||||
THREAD_PAUSED,
|
||||
|
@ -61,6 +64,7 @@ struct mCoreThread {
|
|||
void (*run)(struct mCoreThread*);
|
||||
|
||||
struct mCoreSync sync;
|
||||
struct mCoreRewindContext rewind;
|
||||
};
|
||||
|
||||
bool mCoreThreadStart(struct mCoreThread* threadContext);
|
||||
|
@ -84,7 +88,13 @@ bool mCoreThreadIsPaused(struct mCoreThread* threadContext);
|
|||
void mCoreThreadTogglePause(struct mCoreThread* threadContext);
|
||||
void mCoreThreadPauseFromThread(struct mCoreThread* threadContext);
|
||||
|
||||
void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool);
|
||||
|
||||
struct mCoreThread* mCoreThreadGet(void);
|
||||
|
||||
void mCoreThreadFrameStarted(struct mCoreThread*);
|
||||
void mCoreThreadFrameEnded(struct mCoreThread*);
|
||||
|
||||
struct mLogger* mCoreThreadLogger(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -175,6 +175,8 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
|
|||
if (video->p->memory.mbcType == GB_MBC7 && video->p->memory.rotation && video->p->memory.rotation->sample) {
|
||||
video->p->memory.rotation->sample(video->p->memory.rotation);
|
||||
}
|
||||
struct mCoreThread* thread = mCoreThreadGet();
|
||||
mCoreThreadFrameStarted(thread);
|
||||
break;
|
||||
case 2:
|
||||
_cleanOAM(video, video->ly);
|
||||
|
@ -204,9 +206,7 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
|
|||
if (video->p->cpu->executionState == LR35902_CORE_FETCH) {
|
||||
GBFrameEnded(video->p);
|
||||
struct mCoreThread* thread = mCoreThreadGet();
|
||||
if (thread && thread->frameCallback) {
|
||||
thread->frameCallback(thread);
|
||||
}
|
||||
mCoreThreadFrameEnded(thread);
|
||||
video->nextFrame = GB_VIDEO_TOTAL_LENGTH;
|
||||
} else {
|
||||
video->nextFrame = 4 - ((video->p->cpu->executionState + 1) & 3);
|
||||
|
|
|
@ -800,7 +800,8 @@ void GBABreakpoint(struct ARMCore* cpu, int immediate) {
|
|||
void GBAFrameStarted(struct GBA* gba) {
|
||||
UNUSED(gba);
|
||||
|
||||
// TODO: Put back rewind
|
||||
struct mCoreThread* thread = mCoreThreadGet();
|
||||
mCoreThreadFrameStarted(thread);
|
||||
}
|
||||
|
||||
void GBAFrameEnded(struct GBA* gba) {
|
||||
|
@ -831,13 +832,7 @@ void GBAFrameEnded(struct GBA* gba) {
|
|||
}
|
||||
|
||||
struct mCoreThread* thread = mCoreThreadGet();
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread->frameCallback) {
|
||||
thread->frameCallback(thread);
|
||||
}
|
||||
mCoreThreadFrameEnded(thread);
|
||||
|
||||
// TODO: Put back RR
|
||||
}
|
||||
|
|
|
@ -225,5 +225,3 @@ struct GBASerializedState* GBAAllocateState(void) {
|
|||
void GBADeallocateState(struct GBASerializedState* state) {
|
||||
mappedMemoryFree(state, sizeof(struct GBASerializedState));
|
||||
}
|
||||
|
||||
// TODO: Put back rewind
|
||||
|
|
|
@ -112,8 +112,7 @@ ConfigController::ConfigController(QObject* parent)
|
|||
m_opts.volume = 0x100;
|
||||
m_opts.logLevel = mLOG_WARN | mLOG_ERROR | mLOG_FATAL;
|
||||
m_opts.rewindEnable = false;
|
||||
m_opts.rewindBufferInterval = 0;
|
||||
m_opts.rewindBufferCapacity = 0;
|
||||
m_opts.rewindBufferCapacity = 60;
|
||||
m_opts.useBios = true;
|
||||
m_opts.suspendScreensaver = true;
|
||||
mCoreConfigLoad(&m_config);
|
||||
|
|
|
@ -234,13 +234,6 @@ GameController::GameController(QObject* parent)
|
|||
|
||||
m_threadContext.userData = this;
|
||||
|
||||
connect(&m_rewindTimer, &QTimer::timeout, [this]() {
|
||||
// TODO: Put rewind back
|
||||
emit frameAvailable(m_drawContext);
|
||||
emit rewound(&m_threadContext);
|
||||
});
|
||||
m_rewindTimer.setInterval(100);
|
||||
|
||||
m_audioThread->setObjectName("Audio Thread");
|
||||
m_audioThread->start(QThread::TimeCriticalPriority);
|
||||
m_audioProcessor->moveToThread(m_audioThread);
|
||||
|
@ -529,7 +522,6 @@ void GameController::closeGame() {
|
|||
}
|
||||
m_gameOpen = false;
|
||||
|
||||
m_rewindTimer.stop();
|
||||
if (mCoreThreadIsPaused(&m_threadContext)) {
|
||||
mCoreThreadUnpause(&m_threadContext);
|
||||
}
|
||||
|
@ -578,7 +570,7 @@ QSize GameController::screenDimensions() const {
|
|||
}
|
||||
|
||||
void GameController::setPaused(bool paused) {
|
||||
if (!isLoaded() || m_rewindTimer.isActive() || paused == mCoreThreadIsPaused(&m_threadContext)) {
|
||||
if (!isLoaded() || paused == mCoreThreadIsPaused(&m_threadContext)) {
|
||||
return;
|
||||
}
|
||||
if (paused) {
|
||||
|
@ -617,15 +609,12 @@ void GameController::threadContinue() {
|
|||
}
|
||||
|
||||
void GameController::frameAdvance() {
|
||||
if (m_rewindTimer.isActive()) {
|
||||
return;
|
||||
}
|
||||
if (m_pauseAfterFrame.testAndSetRelaxed(false, true)) {
|
||||
setPaused(false);
|
||||
}
|
||||
}
|
||||
|
||||
void GameController::setRewind(bool enable, int capacity, int interval) {
|
||||
void GameController::setRewind(bool enable, int capacity) {
|
||||
if (m_gameOpen) {
|
||||
threadInterrupt();
|
||||
// TODO: Put back rewind
|
||||
|
@ -638,9 +627,12 @@ void GameController::setRewind(bool enable, int capacity, int interval) {
|
|||
void GameController::rewind(int states) {
|
||||
threadInterrupt();
|
||||
if (!states) {
|
||||
// TODO: Put back rewind
|
||||
} else {
|
||||
// TODO: Put back rewind
|
||||
states = INT_MAX;
|
||||
}
|
||||
for (int i = 0; i < states; ++i) {
|
||||
if (!mCoreRewindRestore(&m_threadContext.rewind, m_threadContext.core)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
threadContinue();
|
||||
emit frameAvailable(m_drawContext);
|
||||
|
@ -648,24 +640,21 @@ void GameController::rewind(int states) {
|
|||
}
|
||||
|
||||
void GameController::startRewinding() {
|
||||
if (!m_gameOpen || m_rewindTimer.isActive()) {
|
||||
if (!m_gameOpen) {
|
||||
return;
|
||||
}
|
||||
if (m_multiplayer && m_multiplayer->attached() > 1) {
|
||||
return;
|
||||
}
|
||||
m_wasPaused = isPaused();
|
||||
if (!mCoreThreadIsPaused(&m_threadContext)) {
|
||||
mCoreThreadPause(&m_threadContext);
|
||||
m_wasPaused = mCoreThreadIsPaused(&m_threadContext);
|
||||
if (m_wasPaused) {
|
||||
mCoreThreadUnpause(&m_threadContext);
|
||||
}
|
||||
m_rewindTimer.start();
|
||||
mCoreThreadSetRewinding(&m_threadContext, true);
|
||||
}
|
||||
|
||||
void GameController::stopRewinding() {
|
||||
if (!m_rewindTimer.isActive()) {
|
||||
return;
|
||||
}
|
||||
m_rewindTimer.stop();
|
||||
mCoreThreadSetRewinding(&m_threadContext, false);
|
||||
bool signalsBlocked = blockSignals(true);
|
||||
setPaused(m_wasPaused);
|
||||
blockSignals(signalsBlocked);
|
||||
|
|
|
@ -116,7 +116,7 @@ public slots:
|
|||
void setPaused(bool paused);
|
||||
void reset();
|
||||
void frameAdvance();
|
||||
void setRewind(bool enable, int capacity, int interval);
|
||||
void setRewind(bool enable, int capacity);
|
||||
void rewind(int states = 0);
|
||||
void startRewinding();
|
||||
void stopRewinding();
|
||||
|
@ -202,7 +202,6 @@ private:
|
|||
bool m_turbo;
|
||||
bool m_turboForced;
|
||||
float m_turboSpeed;
|
||||
QTimer m_rewindTimer;
|
||||
bool m_wasPaused;
|
||||
|
||||
bool m_audioChannels[6];
|
||||
|
|
|
@ -165,14 +165,6 @@ void SettingsView::selectBios() {
|
|||
}
|
||||
}
|
||||
|
||||
void SettingsView::recalculateRewind() {
|
||||
int interval = m_ui.rewindInterval->value();
|
||||
int capacity = m_ui.rewindCapacity->value();
|
||||
double duration = m_ui.fpsTarget->value();
|
||||
m_ui.rewindDuration->setValue(interval * capacity / duration);
|
||||
|
||||
}
|
||||
|
||||
void SettingsView::updateConfig() {
|
||||
saveSetting("bios", m_ui.bios);
|
||||
saveSetting("useBios", m_ui.useBios);
|
||||
|
@ -187,7 +179,6 @@ void SettingsView::updateConfig() {
|
|||
saveSetting("volume", m_ui.volume);
|
||||
saveSetting("mute", m_ui.mute);
|
||||
saveSetting("rewindEnable", m_ui.rewind);
|
||||
saveSetting("rewindBufferInterval", m_ui.rewindInterval);
|
||||
saveSetting("rewindBufferCapacity", m_ui.rewindCapacity);
|
||||
saveSetting("resampleVideo", m_ui.resampleVideo);
|
||||
saveSetting("allowOpposingDirections", m_ui.allowOpposingDirections);
|
||||
|
@ -262,7 +253,6 @@ void SettingsView::reloadConfig() {
|
|||
loadSetting("volume", m_ui.volume);
|
||||
loadSetting("mute", m_ui.mute);
|
||||
loadSetting("rewindEnable", m_ui.rewind);
|
||||
loadSetting("rewindBufferInterval", m_ui.rewindInterval);
|
||||
loadSetting("rewindBufferCapacity", m_ui.rewindCapacity);
|
||||
loadSetting("resampleVideo", m_ui.resampleVideo);
|
||||
loadSetting("allowOpposingDirections", m_ui.allowOpposingDirections);
|
||||
|
@ -283,10 +273,6 @@ void SettingsView::reloadConfig() {
|
|||
m_ui.fastForwardRatio->setValue(fastForwardRatio);
|
||||
}
|
||||
|
||||
connect(m_ui.rewindInterval, SIGNAL(valueChanged(int)), this, SLOT(recalculateRewind()));
|
||||
connect(m_ui.rewindCapacity, SIGNAL(valueChanged(int)), this, SLOT(recalculateRewind()));
|
||||
connect(m_ui.fpsTarget, SIGNAL(valueChanged(double)), this, SLOT(recalculateRewind()));
|
||||
|
||||
QString idleOptimization = loadSetting("idleOptimization");
|
||||
if (idleOptimization == "ignore") {
|
||||
m_ui.idleOptimization->setCurrentIndex(0);
|
||||
|
|
|
@ -30,7 +30,6 @@ signals:
|
|||
|
||||
private slots:
|
||||
void selectBios();
|
||||
void recalculateRewind();
|
||||
void updateConfig();
|
||||
void reloadConfig();
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>544</width>
|
||||
<height>425</height>
|
||||
<width>548</width>
|
||||
<height>431</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -72,7 +72,7 @@
|
|||
<item row="1" column="1">
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>2</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="stackedWidgetPage1">
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
|
@ -110,7 +110,7 @@
|
|||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="currentText" stdset="0">
|
||||
<property name="currentText">
|
||||
<string>1536</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
|
@ -176,7 +176,7 @@
|
|||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="currentText" stdset="0">
|
||||
<property name="currentText">
|
||||
<string>44100</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
|
@ -487,13 +487,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="allowOpposingDirections">
|
||||
<property name="text">
|
||||
<string>Allow opposing input directions</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QCheckBox" name="suspendScreensaver">
|
||||
<property name="text">
|
||||
|
@ -537,6 +530,13 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="allowOpposingDirections">
|
||||
<property name="text">
|
||||
<string>Allow opposing input directions</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_2">
|
||||
|
@ -634,70 +634,25 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Create rewind state:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Every</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="rewindInterval"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>frames</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Rewind history:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<item row="10" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_13">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="rewindCapacity"/>
|
||||
<widget class="QSpinBox" name="rewindCapacity">
|
||||
<property name="maximum">
|
||||
<number>3600</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>states</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="rewindDuration">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>999.990000000000009</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_26">
|
||||
<property name="text">
|
||||
<string>seconds</string>
|
||||
<string>frames</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -1375,17 +1375,12 @@ void Window::setupMenu(QMenuBar* menubar) {
|
|||
|
||||
ConfigOption* rewindEnable = m_config->addOption("rewindEnable");
|
||||
rewindEnable->connect([this](const QVariant& value) {
|
||||
m_controller->setRewind(value.toBool(), m_config->getOption("rewindBufferCapacity").toInt(), m_config->getOption("rewindBufferInterval").toInt());
|
||||
m_controller->setRewind(value.toBool(), m_config->getOption("rewindBufferCapacity").toInt());
|
||||
}, this);
|
||||
|
||||
ConfigOption* rewindBufferCapacity = m_config->addOption("rewindBufferCapacity");
|
||||
rewindBufferCapacity->connect([this](const QVariant& value) {
|
||||
m_controller->setRewind(m_config->getOption("rewindEnable").toInt(), value.toInt(), m_config->getOption("rewindBufferInterval").toInt());
|
||||
}, this);
|
||||
|
||||
ConfigOption* rewindBufferInterval = m_config->addOption("rewindBufferInterval");
|
||||
rewindBufferInterval->connect([this](const QVariant& value) {
|
||||
m_controller->setRewind(m_config->getOption("rewindEnable").toInt(), m_config->getOption("rewindBufferCapacity").toInt(), value.toInt());
|
||||
m_controller->setRewind(m_config->getOption("rewindEnable").toInt(), value.toInt());
|
||||
}, this);
|
||||
|
||||
ConfigOption* allowOpposingDirections = m_config->addOption("allowOpposingDirections");
|
||||
|
|
|
@ -51,6 +51,7 @@ int main(int argc, char** argv) {
|
|||
struct mCoreOptions opts = {
|
||||
.useBios = true,
|
||||
.rewindEnable = true,
|
||||
.rewindBufferCapacity = 600,
|
||||
.audioBuffers = 512,
|
||||
.videoSync = false,
|
||||
.audioSync = true,
|
||||
|
|
|
@ -406,6 +406,9 @@ static void _mSDLHandleKeypress(struct mCoreThread* context, struct mSDLPlayer*
|
|||
context->sync.audioWait = event->type != SDL_KEYDOWN;
|
||||
return;
|
||||
}
|
||||
if (event->keysym.sym == SDLK_BACKQUOTE) {
|
||||
mCoreThreadSetRewinding(context, event->type == SDL_KEYDOWN);
|
||||
}
|
||||
if (event->type == SDL_KEYDOWN) {
|
||||
switch (event->keysym.sym) {
|
||||
case SDLK_F11:
|
||||
|
@ -423,9 +426,6 @@ static void _mSDLHandleKeypress(struct mCoreThread* context, struct mSDLPlayer*
|
|||
context->frameCallback = _pauseAfterFrame;
|
||||
mCoreThreadUnpause(context);
|
||||
return;
|
||||
case SDLK_BACKQUOTE:
|
||||
// TODO: Put back rewind
|
||||
return;
|
||||
#ifdef BUILD_PANDORA
|
||||
case SDLK_ESCAPE:
|
||||
mCoreThreadEnd(context);
|
||||
|
|
Loading…
Reference in New Issue