From 7dc9eb4d5641d5980a2cc0eb8f1e459b4bfdfb4a Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 11 Apr 2017 21:29:24 -0700 Subject: [PATCH 1/7] Feature: Make -l option explicit --- CHANGES | 1 + src/feature/commandline.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index da5eea6cc..8739f213a 100644 --- a/CHANGES +++ b/CHANGES @@ -87,6 +87,7 @@ Misc: - Qt: Make "Mute" able to be bound to a key - Core: Restore sleep callback - Qt: Add .gb/.gbc files to the extension list in Info.plist + - Feature: Make -l option explicit 0.5.2: (2016-12-31) Bugfixes: diff --git a/src/feature/commandline.c b/src/feature/commandline.c index ae9f72c18..9e9158208 100644 --- a/src/feature/commandline.c +++ b/src/feature/commandline.c @@ -38,6 +38,7 @@ static const struct option _options[] = { { "gdb", no_argument, 0, 'g' }, #endif { "help", no_argument, 0, 'h' }, + { "log-level", required_argument, 0, 'l' }, { "movie", required_argument, 0, 'v' }, { "patch", required_argument, 0, 'p' }, { "version", no_argument, 0, '\0' }, @@ -217,6 +218,7 @@ void usage(const char* arg0, const char* extraOptions) { #ifdef USE_GDB_STUB puts(" -g, --gdb Start GDB session (default port 2345)"); #endif + puts(" -l, --log-level N Log level mask"); puts(" -v, --movie FILE Play back a movie of recorded input"); puts(" -p, --patch FILE Apply a specified patch file when running"); puts(" -s, --frameskip N Skip every N frames"); From bf716b947a113056d315ee75802e40c6a5df3d65 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 11 Apr 2017 21:41:53 -0700 Subject: [PATCH 2/7] Util: Move StringList to string.c --- include/mgba-util/vector.h | 2 ++ include/mgba/core/cheats.h | 1 - src/core/cheats.c | 1 - src/util/string.c | 4 ++++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/mgba-util/vector.h b/include/mgba-util/vector.h index 664221b7d..ae542d41b 100644 --- a/include/mgba-util/vector.h +++ b/include/mgba-util/vector.h @@ -92,6 +92,8 @@ CXX_GUARD_START dest->size = src->size; \ } \ +DECLARE_VECTOR(StringList, char*); + CXX_GUARD_END #endif diff --git a/include/mgba/core/cheats.h b/include/mgba/core/cheats.h index 7960ae58b..25ad3bbe1 100644 --- a/include/mgba/core/cheats.h +++ b/include/mgba/core/cheats.h @@ -48,7 +48,6 @@ struct mCheat { mLOG_DECLARE_CATEGORY(CHEATS); DECLARE_VECTOR(mCheatList, struct mCheat); -DECLARE_VECTOR(StringList, char*); struct mCheatDevice; struct mCheatSet { diff --git a/src/core/cheats.c b/src/core/cheats.c index 83bdde0b8..5085a3d67 100644 --- a/src/core/cheats.c +++ b/src/core/cheats.c @@ -17,7 +17,6 @@ mLOG_DEFINE_CATEGORY(CHEATS, "Cheats", "core.cheats"); DEFINE_VECTOR(mCheatList, struct mCheat); DEFINE_VECTOR(mCheatSets, struct mCheatSet*); -DEFINE_VECTOR(StringList, char*); static int32_t _readMem(struct mCore* core, uint32_t address, int width) { switch (width) { diff --git a/src/util/string.c b/src/util/string.c index a776bc16d..cef28e5cd 100644 --- a/src/util/string.c +++ b/src/util/string.c @@ -5,8 +5,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include + #include +DEFINE_VECTOR(StringList, char*); + #ifndef HAVE_STRNDUP char* strndup(const char* start, size_t len) { // This is suboptimal, but anything recent should have strndup From d16df6979010a1864a9f4ef518edfd4387d2e6d2 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 11 Apr 2017 22:20:37 -0700 Subject: [PATCH 3/7] Feature: Command line ability to override configuration values --- CHANGES | 1 + src/feature/commandline.c | 45 ++++++++++++++++++++++++++++++--------- src/feature/commandline.h | 4 ++++ 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index 8739f213a..e48baefc3 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,7 @@ Features: - Add option for whether rewinding restores save games - Qt: German translation (by Lothar Serra Mari) - Savestates now contain any RTC override data + - Command line ability to override configuration values Bugfixes: - LR35902: Fix core never exiting with certain event patterns - GB Timer: Improve DIV reset behavior diff --git a/src/feature/commandline.c b/src/feature/commandline.c index 9e9158208..07da69760 100644 --- a/src/feature/commandline.c +++ b/src/feature/commandline.c @@ -48,10 +48,27 @@ static const struct option _options[] = { static bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg); static void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config); +static void _tableInsert(struct Table* table, const char* pair) { + char* eq = strchr(pair, '='); + if (eq) { + char option[128] = ""; + strncpy(option, pair, eq - pair); + option[sizeof(option) - 1] = '\0'; + HashTableInsert(table, option, strdup(&eq[1])); + } else { + HashTableInsert(table, pair, strdup("1")); + } +} + +static void _tableApply(const char* key, void* value, void* user) { + struct mCoreConfig* config = user; + mCoreConfigSetOverrideValue(config, key, value); +} + bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct mSubParser* subparser) { int ch; char options[64] = - "b:c:hl:p:s:v:" + "b:c:C:hl:p:s:v:" #ifdef USE_EDITLINE "d" #endif @@ -62,6 +79,7 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct memset(args, 0, sizeof(*args)); args->frameskip = -1; args->logLevel = INT_MIN; + HashTableInit(&args->configOverrides, 0, free); if (subparser && subparser->extraOptions) { // TODO: modularize options to subparsers strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1); @@ -83,6 +101,9 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct case 'c': args->cheatsFile = strdup(optarg); break; + case 'C': + _tableInsert(&args->configOverrides, optarg); + break; #ifdef USE_EDITLINE case 'd': if (args->debuggerType != DEBUGGER_NONE) { @@ -145,6 +166,7 @@ void applyArguments(const struct mArguments* args, struct mSubParser* subparser, if (args->bios) { mCoreConfigSetOverrideValue(config, "bios", args->bios); } + HashTableEnumerate(&args->configOverrides, _tableApply, config); if (subparser) { subparser->apply(subparser, config); } @@ -165,6 +187,8 @@ void freeArguments(struct mArguments* args) { free(args->bios); args->bios = 0; + + HashTableDeinit(&args->configOverrides); } void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts) { @@ -210,19 +234,20 @@ void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config) { void usage(const char* arg0, const char* extraOptions) { printf("usage: %s [option ...] file\n", arg0); puts("\nGeneric options:"); - puts(" -b, --bios FILE GBA BIOS file to use"); - puts(" -c, --cheats FILE Apply cheat codes from a file"); + puts(" -b, --bios FILE GBA BIOS file to use"); + puts(" -c, --cheats FILE Apply cheat codes from a file"); + puts(" -C, --config OPTION=VALUE Override config value"); #ifdef USE_EDITLINE - puts(" -d, --debug Use command-line debugger"); + puts(" -d, --debug Use command-line debugger"); #endif #ifdef USE_GDB_STUB - puts(" -g, --gdb Start GDB session (default port 2345)"); + puts(" -g, --gdb Start GDB session (default port 2345)"); #endif - puts(" -l, --log-level N Log level mask"); - puts(" -v, --movie FILE Play back a movie of recorded input"); - puts(" -p, --patch FILE Apply a specified patch file when running"); - puts(" -s, --frameskip N Skip every N frames"); - puts(" --version Print version and exit"); + puts(" -l, --log-level N Log level mask"); + puts(" -v, --movie FILE Play back a movie of recorded input"); + puts(" -p, --patch FILE Apply a specified patch file when running"); + puts(" -s, --frameskip N Skip every N frames"); + puts(" --version Print version and exit"); if (extraOptions) { puts(extraOptions); } diff --git a/src/feature/commandline.h b/src/feature/commandline.h index 322c8e87b..b47442c21 100644 --- a/src/feature/commandline.h +++ b/src/feature/commandline.h @@ -10,6 +10,8 @@ CXX_GUARD_START +#include + #include struct mArguments { @@ -21,6 +23,8 @@ struct mArguments { int logLevel; int frameskip; + struct Table configOverrides; + enum mDebuggerType debuggerType; bool debugAtStart; bool showHelp; From 9ced6724c15fa79a44a33a9aa6f50009f569157f Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 12 Apr 2017 13:23:10 -0700 Subject: [PATCH 4/7] Qt: Attempt to fix #622 --- src/platform/qt/ConfigController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/qt/ConfigController.cpp b/src/platform/qt/ConfigController.cpp index 520b6d9f2..862cb3d06 100644 --- a/src/platform/qt/ConfigController.cpp +++ b/src/platform/qt/ConfigController.cpp @@ -92,7 +92,7 @@ QString ConfigController::s_configDir; ConfigController::ConfigController(QObject* parent) : QObject(parent) - , m_opts() + , m_opts{} { QString fileName = configDir(); fileName.append(QDir::separator()); From 58c9bcf67aa4ab64bc28bc96741508570a47caa4 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 12 Apr 2017 13:28:21 -0700 Subject: [PATCH 5/7] Core: Ability to enumerate and modify video and audio channels --- CHANGES | 1 + include/mgba/core/core.h | 5 ++ include/mgba/core/interface.h | 7 ++ src/gb/core.c | 48 ++++++++++++++ src/gba/core.c | 69 +++++++++++++++++++ src/platform/qt/GameController.cpp | 103 ++++++----------------------- src/platform/qt/GameController.h | 4 +- 7 files changed, 153 insertions(+), 84 deletions(-) diff --git a/CHANGES b/CHANGES index e48baefc3..55d3c0e9b 100644 --- a/CHANGES +++ b/CHANGES @@ -89,6 +89,7 @@ Misc: - Core: Restore sleep callback - Qt: Add .gb/.gbc files to the extension list in Info.plist - Feature: Make -l option explicit + - Core: Ability to enumerate and modify video and audio channels 0.5.2: (2016-12-31) Bugfixes: diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h index e382a7beb..b83c4aca0 100644 --- a/include/mgba/core/core.h +++ b/include/mgba/core/core.h @@ -140,6 +140,11 @@ struct mCore { size_t (*savedataClone)(struct mCore*, void** sram); bool (*savedataRestore)(struct mCore*, const void* sram, size_t size, bool writeback); + + size_t (*listVideoLayers)(const struct mCore*, const struct mCoreChannelInfo**); + size_t (*listAudioChannels)(const struct mCore*, const struct mCoreChannelInfo**); + void (*enableVideoLayer)(struct mCore*, size_t id, bool enable); + void (*enableAudioChannel)(struct mCore*, size_t id, bool enable); }; #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 diff --git a/include/mgba/core/interface.h b/include/mgba/core/interface.h index acaa930cd..7f0515a60 100644 --- a/include/mgba/core/interface.h +++ b/include/mgba/core/interface.h @@ -105,6 +105,13 @@ struct mRumble { void (*setRumble)(struct mRumble*, int enable); }; +struct mCoreChannelInfo { + size_t id; + const char* internalName; + const char* visibleName; + const char* visibleType; +}; + CXX_GUARD_END #endif diff --git a/src/gb/core.c b/src/gb/core.c index c3eb1b22a..48d178719 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -20,6 +20,19 @@ #include #include +const static struct mCoreChannelInfo _GBVideoLayers[] = { + { 0, "bg", "Background", NULL }, + { 1, "obj", "Objects", NULL }, + { 2, "win", "Window", NULL }, +}; + +const static struct mCoreChannelInfo _GBAudioChannels[] = { + { 0, "ch0", "Channel 0", "Square/Sweep" }, + { 1, "ch1", "Channel 1", "Square" }, + { 2, "ch2", "Channel 2", "PCM" }, + { 3, "ch3", "Channel 3", "Noise" }, +}; + struct GBCore { struct mCore d; struct GBVideoSoftwareRenderer renderer; @@ -579,6 +592,37 @@ static bool _GBCoreSavedataRestore(struct mCore* core, const void* sram, size_t return true; } +static size_t _GBCoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) { + UNUSED(core); + *info = _GBVideoLayers; + return sizeof(_GBVideoLayers) / sizeof(*_GBVideoLayers); +} + +static size_t _GBCoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) { + UNUSED(core); + *info = _GBAudioChannels; + return sizeof(_GBAudioChannels) / sizeof(*_GBAudioChannels); +} + +static void _GBCoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) { + struct GB* gb = core->board; + // TODO +} + +static void _GBCoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) { + struct GB* gb = core->board; + switch (id) { + case 0: + case 1: + case 2: + case 3: + gb->audio.forceDisableCh[id] = !enable; + break; + default: + break; + } +} + struct mCore* GBCoreCreate(void) { struct GBCore* gbcore = malloc(sizeof(*gbcore)); struct mCore* core = &gbcore->d; @@ -647,5 +691,9 @@ struct mCore* GBCoreCreate(void) { core->cheatDevice = _GBCoreCheatDevice; core->savedataClone = _GBCoreSavedataClone; core->savedataRestore = _GBCoreSavedataRestore; + core->listVideoLayers = _GBCoreListVideoLayers; + core->listAudioChannels = _GBCoreListAudioChannels; + core->enableVideoLayer = _GBCoreEnableVideoLayer; + core->enableAudioChannel = _GBCoreEnableAudioChannel; return core; } diff --git a/src/gba/core.c b/src/gba/core.c index 4f7963cea..8636489f2 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -22,6 +22,23 @@ #include #include +const static struct mCoreChannelInfo _GBAVideoLayers[] = { + { 0, "bg0", "Background 0", NULL }, + { 1, "bg1", "Background 1", NULL }, + { 2, "bg2", "Background 2", NULL }, + { 3, "bg3", "Background 3", NULL }, + { 4, "obj", "Objects", NULL }, +}; + +const static struct mCoreChannelInfo _GBAAudioChannels[] = { + { 0, "ch0", "PSG Channel 0", "Square/Sweep" }, + { 1, "ch1", "PSG Channel 1", "Square" }, + { 2, "ch2", "PSG Channel 2", "PCM" }, + { 3, "ch3", "PSG Channel 3", "Noise" }, + { 4, "chA", "FIFO Channel A", NULL }, + { 5, "chB", "FIFO Channel B", NULL }, +}; + struct GBACore { struct mCore d; struct GBAVideoSoftwareRenderer renderer; @@ -581,6 +598,54 @@ static bool _GBACoreSavedataRestore(struct mCore* core, const void* sram, size_t return success; } +static size_t _GBACoreListVideoLayers(const struct mCore* core, const struct mCoreChannelInfo** info) { + UNUSED(core); + *info = _GBAVideoLayers; + return sizeof(_GBAVideoLayers) / sizeof(*_GBAVideoLayers); +} + +static size_t _GBACoreListAudioChannels(const struct mCore* core, const struct mCoreChannelInfo** info) { + UNUSED(core); + *info = _GBAAudioChannels; + return sizeof(_GBAAudioChannels) / sizeof(*_GBAAudioChannels); +} + +static void _GBACoreEnableVideoLayer(struct mCore* core, size_t id, bool enable) { + struct GBA* gba = core->board; + switch (id) { + case 0: + case 1: + case 2: + case 3: + gba->video.renderer->disableBG[id] = !enable; + break; + case 4: + gba->video.renderer->disableOBJ = !enable; + break; + default: + break; + } +} + +static void _GBACoreEnableAudioChannel(struct mCore* core, size_t id, bool enable) { + struct GBA* gba = core->board; + switch (id) { + case 0: + case 1: + case 2: + case 3: + gba->audio.psg.forceDisableCh[id] = !enable; + break; + case 4: + gba->audio.forceDisableChA = !enable; + case 5: + gba->audio.forceDisableChB = !enable; + break; + default: + break; + } +} + struct mCore* GBACoreCreate(void) { struct GBACore* gbacore = malloc(sizeof(*gbacore)); struct mCore* core = &gbacore->d; @@ -649,5 +714,9 @@ struct mCore* GBACoreCreate(void) { core->cheatDevice = _GBACoreCheatDevice; core->savedataClone = _GBACoreSavedataClone; core->savedataRestore = _GBACoreSavedataRestore; + core->listVideoLayers = _GBACoreListVideoLayers; + core->listAudioChannels = _GBACoreListAudioChannels; + core->enableVideoLayer = _GBACoreEnableVideoLayer; + core->enableAudioChannel = _GBACoreEnableAudioChannel; return core; } diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index 28efaa8ea..0eb922b0e 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -57,8 +57,8 @@ GameController::GameController(QObject* parent) , m_turboForced(false) , m_turboSpeed(-1) , m_wasPaused(false) - , m_audioChannels{ true, true, true, true, true, true } - , m_videoLayers{ true, true, true, true, true } + , m_audioChannels() + , m_videoLayers() , m_autofire{} , m_autofireStatus{} , m_inputController(nullptr) @@ -90,35 +90,17 @@ GameController::GameController(QObject* parent) context->core->setPeripheral(context->core, mPERIPH_ROTATION, controller->m_inputController->rotationSource()); context->core->setPeripheral(context->core, mPERIPH_RUMBLE, controller->m_inputController->rumble()); -#ifdef M_CORE_GBA - GBA* gba = static_cast(context->core->board); -#endif -#ifdef M_CORE_GB - GB* gb = static_cast(context->core->board); -#endif + for (size_t i = 0; i < controller->m_audioChannels.size(); ++i) { + context->core->enableAudioChannel(context->core, i, controller->m_audioChannels[i]); + } + for (size_t i = 0; i < controller->m_videoLayers.size(); ++i) { + context->core->enableVideoLayer(context->core, i, controller->m_videoLayers[i]); + } + switch (context->core->platform(context->core)) { #ifdef M_CORE_GBA case PLATFORM_GBA: context->core->setPeripheral(context->core, mPERIPH_GBA_LUMINANCE, &controller->m_lux); - gba->audio.psg.forceDisableCh[0] = !controller->m_audioChannels[0]; - gba->audio.psg.forceDisableCh[1] = !controller->m_audioChannels[1]; - gba->audio.psg.forceDisableCh[2] = !controller->m_audioChannels[2]; - gba->audio.psg.forceDisableCh[3] = !controller->m_audioChannels[3]; - gba->audio.forceDisableChA = !controller->m_audioChannels[4]; - gba->audio.forceDisableChB = !controller->m_audioChannels[5]; - gba->video.renderer->disableBG[0] = !controller->m_videoLayers[0]; - gba->video.renderer->disableBG[1] = !controller->m_videoLayers[1]; - gba->video.renderer->disableBG[2] = !controller->m_videoLayers[2]; - gba->video.renderer->disableBG[3] = !controller->m_videoLayers[3]; - gba->video.renderer->disableOBJ = !controller->m_videoLayers[4]; - break; -#endif -#ifdef M_CORE_GB - case PLATFORM_GB: - gb->audio.forceDisableCh[0] = !controller->m_audioChannels[0]; - gb->audio.forceDisableCh[1] = !controller->m_audioChannels[1]; - gb->audio.forceDisableCh[2] = !controller->m_audioChannels[2]; - gb->audio.forceDisableCh[3] = !controller->m_audioChannels[3]; break; #endif default: @@ -866,47 +848,13 @@ void GameController::setAudioChannelEnabled(int channel, bool enable) { if (channel > 5 || channel < 0) { return; } -#ifdef M_CORE_GBA - GBA* gba = static_cast(m_threadContext.core->board); -#endif -#ifdef M_CORE_GB - GB* gb = static_cast(m_threadContext.core->board); -#endif + m_audioChannels.reserve(channel + 1); + while (m_audioChannels.size() <= channel) { + m_audioChannels.append(true); + } m_audioChannels[channel] = enable; if (isLoaded()) { - switch (channel) { - case 0: - case 1: - case 2: - case 3: - switch (m_threadContext.core->platform(m_threadContext.core)) { -#ifdef M_CORE_GBA - case PLATFORM_GBA: - gba->audio.psg.forceDisableCh[channel] = !enable; - break; -#endif -#ifdef M_CORE_GB - case PLATFORM_GB: - gb->audio.forceDisableCh[channel] = !enable; - break; -#endif - default: - break; - } - break; -#ifdef M_CORE_GBA - case 4: - if (m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) { - gba->audio.forceDisableChA = !enable; - } - break; - case 5: - if (m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) { - gba->audio.forceDisableChB = !enable; - } - break; -#endif - } + m_threadContext.core->enableAudioChannel(m_threadContext.core, channel, enable); } } @@ -925,23 +873,14 @@ void GameController::setVideoLayerEnabled(int layer, bool enable) { if (layer > 4 || layer < 0) { return; } - m_videoLayers[layer] = enable; -#ifdef M_CORE_GBA - if (isLoaded() && m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) { - GBA* gba = static_cast(m_threadContext.core->board); - switch (layer) { - case 0: - case 1: - case 2: - case 3: - gba->video.renderer->disableBG[layer] = !enable; - break; - case 4: - gba->video.renderer->disableOBJ = !enable; - break; - } + m_videoLayers.reserve(layer + 1); + while (m_videoLayers.size() <= layer) { + m_videoLayers.append(true); + } + m_videoLayers[layer] = enable; + if (isLoaded()) { + m_threadContext.core->enableVideoLayer(m_threadContext.core, layer, enable); } -#endif } void GameController::setFPSTarget(float fps) { diff --git a/src/platform/qt/GameController.h b/src/platform/qt/GameController.h index 75b9a1137..d8137908d 100644 --- a/src/platform/qt/GameController.h +++ b/src/platform/qt/GameController.h @@ -222,8 +222,8 @@ private: std::shared_ptr m_tileCache; - bool m_audioChannels[6]; - bool m_videoLayers[5]; + QList m_audioChannels; + QList m_videoLayers; bool m_autofire[GBA_KEY_MAX]; int m_autofireStatus[GBA_KEY_MAX]; From 959f66a1a0faff37607a53c4da1ea7b508d6a43a Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 13 Apr 2017 00:28:28 -0700 Subject: [PATCH 6/7] Core: Add option to allow preloading the entire ROM before running --- CHANGES | 1 + include/mgba/core/core.h | 3 +++ src/core/core.c | 29 +++++++++++++++++++++++++++++ src/platform/qt/GameController.cpp | 22 ++++++++++++++++++---- src/platform/qt/GameController.h | 3 +++ src/platform/qt/SettingsView.cpp | 2 ++ src/platform/qt/SettingsView.ui | 27 +++++++++++++++++---------- src/platform/qt/Window.cpp | 6 ++++++ 8 files changed, 79 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index 55d3c0e9b..4b31d0426 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,7 @@ Features: - Qt: German translation (by Lothar Serra Mari) - Savestates now contain any RTC override data - Command line ability to override configuration values + - Add option to allow preloading the entire ROM before running Bugfixes: - LR35902: Fix core never exiting with certain event patterns - GB Timer: Improve DIV reset behavior diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h index b83c4aca0..2c226c577 100644 --- a/include/mgba/core/core.h +++ b/include/mgba/core/core.h @@ -151,6 +151,9 @@ struct mCore { struct mCore* mCoreFind(const char* path); bool mCoreLoadFile(struct mCore* core, const char* path); +bool mCorePreloadVF(struct mCore* core, struct VFile* vf); +bool mCorePreloadFile(struct mCore* core, const char* path); + bool mCoreAutoloadSave(struct mCore* core); bool mCoreAutoloadPatch(struct mCore* core); diff --git a/src/core/core.c b/src/core/core.c index 7eacdcfc8..439f89c3e 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -115,6 +115,35 @@ bool mCoreLoadFile(struct mCore* core, const char* path) { return ret; } +bool mCorePreloadVF(struct mCore* core, struct VFile* vf) { + struct VFile* vfm = VFileMemChunk(NULL, vf->size(vf)); + uint8_t buffer[2048]; + ssize_t read; + vf->seek(vf, 0, SEEK_SET); + while ((read = vf->read(vf, buffer, sizeof(buffer))) > 0) { + vfm->write(vfm, buffer, read); + } + vf->close(vf); + bool ret = core->loadROM(core, vfm); + if (!ret) { + vfm->close(vfm); + } + return ret; +} + +bool mCorePreloadFile(struct mCore* core, const char* path) { + struct VFile* rom = mDirectorySetOpenPath(&core->dirs, path, core->isROM); + if (!rom) { + return false; + } + + bool ret = mCorePreloadVF(core, rom); + if (!ret) { + rom->close(rom); + } + return ret; +} + bool mCoreAutoloadSave(struct mCore* core) { return core->loadSave(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.save, ".sav", O_CREAT | O_RDWR)); } diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index 0eb922b0e..53ecf3ed9 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -69,6 +69,7 @@ GameController::GameController(QObject* parent) , m_backupSaveState(nullptr) , m_saveStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS | SAVESTATE_RTC) , m_loadStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_RTC) + , m_preload(false) , m_override(nullptr) { #ifdef M_CORE_GBA @@ -458,11 +459,20 @@ void GameController::openGame(bool biosOnly) { QByteArray bytes; if (!biosOnly) { bytes = m_fname.toUtf8(); - if (m_vf) { - m_threadContext.core->loadROM(m_threadContext.core, m_vf); + if (m_preload) { + if (m_vf) { + mCorePreloadVF(m_threadContext.core, m_vf); + } else { + mCorePreloadFile(m_threadContext.core, bytes.constData()); + mDirectorySetDetachBase(&m_threadContext.core->dirs); + } } else { - mCoreLoadFile(m_threadContext.core, bytes.constData()); - mDirectorySetDetachBase(&m_threadContext.core->dirs); + if (m_vf) { + m_threadContext.core->loadROM(m_threadContext.core, m_vf); + } else { + mCoreLoadFile(m_threadContext.core, bytes.constData()); + mDirectorySetDetachBase(&m_threadContext.core->dirs); + } } } else { bytes = m_bios.toUtf8(); @@ -1107,6 +1117,10 @@ void GameController::setLoadStateExtdata(int flags) { m_loadStateFlags = flags; } +void GameController::setPreload(bool preload) { + m_preload = preload; +} + void GameController::setLuminanceValue(uint8_t value) { m_luxValue = value; value = std::max(value - 0x16, 0); diff --git a/src/platform/qt/GameController.h b/src/platform/qt/GameController.h index d8137908d..acd09f258 100644 --- a/src/platform/qt/GameController.h +++ b/src/platform/qt/GameController.h @@ -154,6 +154,7 @@ public slots: void reloadAudioDriver(); void setSaveStateExtdata(int flags); void setLoadStateExtdata(int flags); + void setPreload(bool); #ifdef USE_PNG void screenshot(); @@ -234,6 +235,8 @@ private: int m_saveStateFlags; int m_loadStateFlags; + bool m_preload; + InputController* m_inputController; MultiplayerController* m_multiplayer; diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index 15d13b4a1..510885501 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -204,6 +204,7 @@ void SettingsView::updateConfig() { saveSetting("screenshotPath", m_ui.screenshotPath); saveSetting("patchPath", m_ui.patchPath); saveSetting("showLibrary", m_ui.showLibrary); + saveSetting("preload", m_ui.preload); if (m_ui.fastForwardUnbounded->isChecked()) { saveSetting("fastForwardRatio", "-1"); @@ -283,6 +284,7 @@ void SettingsView::reloadConfig() { loadSetting("screenshotPath", m_ui.screenshotPath); loadSetting("patchPath", m_ui.patchPath); loadSetting("showLibrary", m_ui.showLibrary); + loadSetting("preload", m_ui.preload); double fastForwardRatio = loadSetting("fastForwardRatio").toDouble(); if (fastForwardRatio <= 0) { diff --git a/src/platform/qt/SettingsView.ui b/src/platform/qt/SettingsView.ui index ad59bc5bd..967c17cb1 100644 --- a/src/platform/qt/SettingsView.ui +++ b/src/platform/qt/SettingsView.ui @@ -568,21 +568,21 @@ - + Qt::Horizontal - + Savestate extra data: - + Screenshot @@ -592,7 +592,7 @@ - + Save data @@ -602,7 +602,7 @@ - + Cheat codes @@ -612,14 +612,14 @@ - + Load extra data: - + Screenshot @@ -629,21 +629,21 @@ - + Save data - + Cheat codes - + Qt::Horizontal @@ -660,6 +660,13 @@ + + + + Preload entire ROM into memory + + + diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index b3b15f909..7be87c484 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -1476,6 +1476,12 @@ void Window::setupMenu(QMenuBar* menubar) { m_controller->setLoadStateExtdata(value.toInt()); }, this); + ConfigOption* preload = m_config->addOption("preload"); + preload->connect([this](const QVariant& value) { + m_controller->setPreload(value.toBool()); + }, this); + m_config->updateOption("preload"); + QAction* exitFullScreen = new QAction(tr("Exit fullscreen"), frameMenu); connect(exitFullScreen, SIGNAL(triggered()), this, SLOT(exitFullScreen())); exitFullScreen->setShortcut(QKeySequence("Esc")); From 0c917138ea39b94d17c092b92a43986ac9c7f790 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 13 Apr 2017 00:28:41 -0700 Subject: [PATCH 7/7] Qt: Code cleanup --- src/platform/qt/Window.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 7be87c484..a679054cf 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -302,19 +302,6 @@ void Window::reloadConfig() { m_log.setLevels(opts->logLevel); - QString saveStateExtdata = m_config->getOption("saveStateExtdata"); - bool ok; - int flags = saveStateExtdata.toInt(&ok); - if (ok) { - m_controller->setSaveStateExtdata(flags); - } - - QString loadStateExtdata = m_config->getOption("loadStateExtdata"); - flags = loadStateExtdata.toInt(&ok); - if (ok) { - m_controller->setLoadStateExtdata(flags); - } - m_controller->setConfig(m_config->config()); m_display->lockAspectRatio(opts->lockAspectRatio); m_display->filter(opts->resampleVideo); @@ -1470,11 +1457,13 @@ void Window::setupMenu(QMenuBar* menubar) { saveStateExtdata->connect([this](const QVariant& value) { m_controller->setSaveStateExtdata(value.toInt()); }, this); + m_config->updateOption("saveStateExtdata"); ConfigOption* loadStateExtdata = m_config->addOption("loadStateExtdata"); loadStateExtdata->connect([this](const QVariant& value) { m_controller->setLoadStateExtdata(value.toInt()); }, this); + m_config->updateOption("loadStateExtdata"); ConfigOption* preload = m_config->addOption("preload"); preload->connect([this](const QVariant& value) {