From e9446fa9dc3ba64c22f8e5bb611ad394b5729eda Mon Sep 17 00:00:00 2001 From: Jakly <102590697+Jaklyy@users.noreply.github.com> Date: Sun, 29 Sep 2024 03:30:13 -0400 Subject: [PATCH 01/47] implement 3 configurable and toggleable framerate targets (#2159) This pr allows for configuring the framerate target and adds support for two other framerate targets, a "fastforward" and "slowmo" target which can be enabled via either a toggle or holding a button. this allows for supporting a more accurate framerate target and allows for users to slow down the speed of gameplay if they so desire --- src/frontend/qt_sdl/Config.cpp | 48 +++- src/frontend/qt_sdl/Config.h | 4 + src/frontend/qt_sdl/EmuInstance.cpp | 26 +- src/frontend/qt_sdl/EmuInstance.h | 12 +- src/frontend/qt_sdl/EmuInstanceInput.cpp | 7 +- src/frontend/qt_sdl/EmuThread.cpp | 43 ++-- .../qt_sdl/InputConfig/InputConfigDialog.h | 6 + .../qt_sdl/InterfaceSettingsDialog.cpp | 52 +++- src/frontend/qt_sdl/InterfaceSettingsDialog.h | 10 + .../qt_sdl/InterfaceSettingsDialog.ui | 236 +++++++++++++++--- src/frontend/qt_sdl/Window.cpp | 5 +- 11 files changed, 394 insertions(+), 55 deletions(-) diff --git a/src/frontend/qt_sdl/Config.cpp b/src/frontend/qt_sdl/Config.cpp index 580af72e..0a161b6f 100644 --- a/src/frontend/qt_sdl/Config.cpp +++ b/src/frontend/qt_sdl/Config.cpp @@ -55,7 +55,6 @@ DefaultList DefaultInts = {"Screen.VSyncInterval", 1}, {"3D.Renderer", renderer3D_Software}, {"3D.GL.ScaleFactor", 1}, - {"MaxFPS", 1000}, #ifdef JIT_ENABLED {"JIT.MaxBlockSize", 32}, #endif @@ -120,6 +119,13 @@ DefaultList DefaultStrings = {"Instance*.Firmware.Username", "melonDS"} }; +DefaultList DefaultDoubles = +{ + {"TargetFPS", 60.0}, + {"FastForwardFPS", 1000.0}, + {"SlowmoFPS", 30.0}, +}; + LegacyEntry LegacyFile[] = { {"Key_A", 0, "Keyboard.A", true}, @@ -153,7 +159,7 @@ LegacyEntry LegacyFile[] = {"HKKey_Pause", 0, "Keyboard.HK_Pause", true}, {"HKKey_Reset", 0, "Keyboard.HK_Reset", true}, {"HKKey_FastForward", 0, "Keyboard.HK_FastForward", true}, - {"HKKey_FastForwardToggle", 0, "Keyboard.HK_FastForwardToggle", true}, + {"HKKey_FastForwardToggle", 0, "Keyboard.HK_FrameLimitToggle", true}, {"HKKey_FullscreenToggle", 0, "Keyboard.HK_FullscreenToggle", true}, {"HKKey_SwapScreens", 0, "Keyboard.HK_SwapScreens", true}, {"HKKey_SwapScreenEmphasis", 0, "Keyboard.HK_SwapScreenEmphasis", true}, @@ -169,7 +175,7 @@ LegacyEntry LegacyFile[] = {"HKJoy_Pause", 0, "Joystick.HK_Pause", true}, {"HKJoy_Reset", 0, "Joystick.HK_Reset", true}, {"HKJoy_FastForward", 0, "Joystick.HK_FastForward", true}, - {"HKJoy_FastForwardToggle", 0, "Joystick.HK_FastForwardToggle", true}, + {"HKJoy_FastForwardToggle", 0, "Joystick.HK_FrameLimitToggle", true}, {"HKJoy_FullscreenToggle", 0, "Joystick.HK_FullscreenToggle", true}, {"HKJoy_SwapScreens", 0, "Joystick.HK_SwapScreens", true}, {"HKJoy_SwapScreenEmphasis", 0, "Joystick.HK_SwapScreenEmphasis", true}, @@ -434,6 +440,18 @@ std::string Array::GetString(const int id) return tval.as_string(); } +double Array::GetDouble(const int id) +{ + while (Data.size() < id+1) + Data.push_back(0.0); + + toml::value& tval = Data[id]; + if (!tval.is_floating()) + tval = 0.0; + + return tval.as_floating(); +} + void Array::SetInt(const int id, int val) { while (Data.size() < id+1) @@ -470,6 +488,15 @@ void Array::SetString(const int id, const std::string& val) tval = val; } +void Array::SetDouble(const int id, double val) +{ + while (Data.size() < id+1) + Data.push_back(0.0); + + toml::value& tval = Data[id]; + tval = val; +} + /*Table::Table()// : Data(toml::value()) { @@ -562,6 +589,15 @@ std::string Table::GetString(const std::string& path) return tval.as_string(); } +double Table::GetDouble(const std::string& path) +{ + toml::value& tval = ResolvePath(path); + if (!tval.is_floating()) + tval = FindDefault(path, 0.0, DefaultDoubles); + + return tval.as_floating(); +} + void Table::SetInt(const std::string& path, int val) { std::string rngkey = GetDefaultKey(PathPrefix+path); @@ -593,6 +629,12 @@ void Table::SetString(const std::string& path, const std::string& val) tval = val; } +void Table::SetDouble(const std::string& path, double val) +{ + toml::value& tval = ResolvePath(path); + tval = val; +} + toml::value& Table::ResolvePath(const std::string& path) { toml::value* ret = &Data; diff --git a/src/frontend/qt_sdl/Config.h b/src/frontend/qt_sdl/Config.h index 4ca88b46..9e6d3ea4 100644 --- a/src/frontend/qt_sdl/Config.h +++ b/src/frontend/qt_sdl/Config.h @@ -61,11 +61,13 @@ public: int64_t GetInt64(const int id); bool GetBool(const int id); std::string GetString(const int id); + double GetDouble(const int id); void SetInt(const int id, int val); void SetInt64(const int id, int64_t val); void SetBool(const int id, bool val); void SetString(const int id, const std::string& val); + void SetDouble(const int id, double val); // convenience @@ -99,11 +101,13 @@ public: int64_t GetInt64(const std::string& path); bool GetBool(const std::string& path); std::string GetString(const std::string& path); + double GetDouble(const std::string& path); void SetInt(const std::string& path, int val); void SetInt64(const std::string& path, int64_t val); void SetBool(const std::string& path, bool val); void SetString(const std::string& path, const std::string& val); + void SetDouble(const std::string& path, double val); // convenience diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index e48f29a2..54bae531 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -88,7 +88,31 @@ EmuInstance::EmuInstance(int inst) : deleting(false), cheatsOn = localCfg.GetBool("EnableCheats"); doLimitFPS = globalCfg.GetBool("LimitFPS"); - maxFPS = globalCfg.GetInt("MaxFPS"); + + double val = globalCfg.GetDouble("TargetFPS"); + if (val == 0.0) + { + Platform::Log(Platform::LogLevel::Error, "Target FPS in config invalid\n"); + targetFPS = 1.0 / 60.0; + } + else targetFPS = 1.0 / val; + + val = globalCfg.GetDouble("FastForwardFPS"); + if (val == 0.0) + { + Platform::Log(Platform::LogLevel::Error, "Fast-Forward FPS in config invalid\n"); + fastForwardFPS = 1.0 / 60.0; + } + else fastForwardFPS = 1.0 / val; + + val = globalCfg.GetDouble("SlowmoFPS"); + if (val == 0.0) + { + Platform::Log(Platform::LogLevel::Error, "Slow-Mo FPS in config invalid\n"); + slowmoFPS = 1.0 / 60.0; + } + else slowmoFPS = 1.0 / val; + doAudioSync = globalCfg.GetBool("AudioSync"); mpAudioMode = globalCfg.GetInt("MP.AudioMode"); diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index 39c187c2..04290f56 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -36,7 +36,7 @@ enum HK_Pause, HK_Reset, HK_FastForward, - HK_FastForwardToggle, + HK_FrameLimitToggle, HK_FullscreenToggle, HK_SwapScreens, HK_SwapScreenEmphasis, @@ -46,6 +46,9 @@ enum HK_PowerButton, HK_VolumeUp, HK_VolumeDown, + HK_SlowMo, + HK_FastForwardToggle, + HK_SlowMoToggle, HK_MAX }; @@ -252,7 +255,12 @@ public: std::unique_ptr firmwareSave; bool doLimitFPS; - int maxFPS; + double curFPS; + double targetFPS; + double fastForwardFPS; + double slowmoFPS; + bool fastForwardToggled; + bool slowmoToggled; bool doAudioSync; private: diff --git a/src/frontend/qt_sdl/EmuInstanceInput.cpp b/src/frontend/qt_sdl/EmuInstanceInput.cpp index ddaca8f0..bb06c242 100644 --- a/src/frontend/qt_sdl/EmuInstanceInput.cpp +++ b/src/frontend/qt_sdl/EmuInstanceInput.cpp @@ -47,7 +47,7 @@ const char* EmuInstance::hotkeyNames[HK_MAX] = "HK_Pause", "HK_Reset", "HK_FastForward", - "HK_FastForwardToggle", + "HK_FrameLimitToggle", "HK_FullscreenToggle", "HK_SwapScreens", "HK_SwapScreenEmphasis", @@ -56,7 +56,10 @@ const char* EmuInstance::hotkeyNames[HK_MAX] = "HK_FrameStep", "HK_PowerButton", "HK_VolumeUp", - "HK_VolumeDown" + "HK_VolumeDown", + "HK_SlowMo", + "HK_FastForwardToggle", + "HK_SlowMoToggle" }; diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index ae66e1ba..4ce4efda 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -149,12 +149,17 @@ void EmuThread::run() char melontitle[100]; + bool fastforward = false; + bool slowmo = false; + emuInstance->fastForwardToggled = false; + emuInstance->slowmoToggled = false; + while (emuStatus != emuStatus_Exit) { MPInterface::Get().Process(); emuInstance->inputProcess(); - if (emuInstance->hotkeyPressed(HK_FastForwardToggle)) emit windowLimitFPSChange(); + if (emuInstance->hotkeyPressed(HK_FrameLimitToggle)) emit windowLimitFPSChange(); if (emuInstance->hotkeyPressed(HK_Pause)) emuTogglePause(); if (emuInstance->hotkeyPressed(HK_Reset)) emuReset(); @@ -332,22 +337,34 @@ void EmuThread::run() emit windowUpdate(); winUpdateCount = 0; } + + if (emuInstance->hotkeyPressed(HK_FastForwardToggle)) emuInstance->fastForwardToggled = !emuInstance->fastForwardToggled; + if (emuInstance->hotkeyPressed(HK_SlowMoToggle)) emuInstance->slowmoToggled = !emuInstance->slowmoToggled; - bool fastforward = emuInstance->hotkeyDown(HK_FastForward); + bool enablefastforward = emuInstance->hotkeyDown(HK_FastForward) | emuInstance->fastForwardToggled; + bool enableslowmo = emuInstance->hotkeyDown(HK_SlowMo) | emuInstance->slowmoToggled; if (useOpenGL) { - // when using OpenGL: when toggling fast-forward, change the vsync interval - if (emuInstance->hotkeyPressed(HK_FastForward)) + // when using OpenGL: when toggling fast-forward or slowmo, change the vsync interval + if ((enablefastforward || enableslowmo) && !(fastforward || slowmo)) { emuInstance->setVSyncGL(false); } - else if (emuInstance->hotkeyReleased(HK_FastForward)) + else if (!(enablefastforward || enableslowmo) && (fastforward || slowmo)) { emuInstance->setVSyncGL(true); } } + fastforward = enablefastforward; + slowmo = enableslowmo; + + if (slowmo) emuInstance->curFPS = emuInstance->slowmoFPS; + else if (fastforward) emuInstance->curFPS = emuInstance->fastForwardFPS; + else if (!emuInstance->doLimitFPS) emuInstance->curFPS = 1.0 / 1000.0; + else emuInstance->curFPS = emuInstance->targetFPS; + if (emuInstance->audioDSiVolumeSync && emuInstance->nds->ConsoleType == 1) { DSi* dsi = static_cast(emuInstance->nds); @@ -361,23 +378,19 @@ void EmuThread::run() emuInstance->audioVolume = volumeLevel * (256.0 / 31.0); } - if (emuInstance->doAudioSync && !fastforward) + if (emuInstance->doAudioSync && !(fastforward || slowmo)) emuInstance->audioSync(); double frametimeStep = nlines / (60.0 * 263.0); { - bool limitfps = emuInstance->doLimitFPS && !fastforward; - - double practicalFramelimit = limitfps ? frametimeStep : 1.0 / emuInstance->maxFPS; - double curtime = SDL_GetPerformanceCounter() * perfCountsSec; - frameLimitError += practicalFramelimit - (curtime - lastTime); - if (frameLimitError < -practicalFramelimit) - frameLimitError = -practicalFramelimit; - if (frameLimitError > practicalFramelimit) - frameLimitError = practicalFramelimit; + frameLimitError += emuInstance->curFPS - (curtime - lastTime); + if (frameLimitError < -emuInstance->curFPS) + frameLimitError = -emuInstance->curFPS; + if (frameLimitError > emuInstance->curFPS) + frameLimitError = emuInstance->curFPS; if (round(frameLimitError * 1000.0) > 0.0) { diff --git a/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h b/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h index 64986d62..3337228f 100644 --- a/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h +++ b/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h @@ -49,6 +49,9 @@ static constexpr std::initializer_list hk_general = HK_FrameStep, HK_FastForward, HK_FastForwardToggle, + HK_SlowMo, + HK_SlowMoToggle, + HK_FrameLimitToggle, HK_FullscreenToggle, HK_Lid, HK_Mic, @@ -65,6 +68,9 @@ static constexpr std::initializer_list hk_general_labels = "Reset", "Frame step", "Fast forward", + "Toggle fast forward", + "Slow mo", + "Toggle slow mo", "Toggle FPS limit", "Toggle fullscreen", "Close/open lid", diff --git a/src/frontend/qt_sdl/InterfaceSettingsDialog.cpp b/src/frontend/qt_sdl/InterfaceSettingsDialog.cpp index dfe30d12..2e7e75c9 100644 --- a/src/frontend/qt_sdl/InterfaceSettingsDialog.cpp +++ b/src/frontend/qt_sdl/InterfaceSettingsDialog.cpp @@ -39,7 +39,9 @@ InterfaceSettingsDialog::InterfaceSettingsDialog(QWidget* parent) : QDialog(pare ui->spinMouseHideSeconds->setEnabled(ui->cbMouseHide->isChecked()); ui->spinMouseHideSeconds->setValue(cfg.GetInt("MouseHideSeconds")); ui->cbPauseLostFocus->setChecked(cfg.GetBool("PauseLostFocus")); - ui->spinMaxFPS->setValue(cfg.GetInt("MaxFPS")); + ui->spinTargetFPS->setValue(cfg.GetDouble("TargetFPS")); + ui->spinFFW->setValue(cfg.GetDouble("FastForwardFPS")); + ui->spinSlow->setValue(cfg.GetDouble("SlowmoFPS")); const QList themeKeys = QStyleFactory::keys(); const QString currentTheme = qApp->style()->objectName(); @@ -65,6 +67,41 @@ void InterfaceSettingsDialog::on_cbMouseHide_clicked() ui->spinMouseHideSeconds->setEnabled(ui->cbMouseHide->isChecked()); } +void InterfaceSettingsDialog::on_pbClean_clicked() +{ + ui->spinTargetFPS->setValue(60.0000); +} + +void InterfaceSettingsDialog::on_pbAccurate_clicked() +{ + ui->spinTargetFPS->setValue(59.8261); +} + +void InterfaceSettingsDialog::on_pb2x_clicked() +{ + ui->spinFFW->setValue(ui->spinTargetFPS->value() * 2.0); +} + +void InterfaceSettingsDialog::on_pb3x_clicked() +{ + ui->spinFFW->setValue(ui->spinTargetFPS->value() * 3.0); +} + +void InterfaceSettingsDialog::on_pbMAX_clicked() +{ + ui->spinFFW->setValue(1000.0); +} + +void InterfaceSettingsDialog::on_pbHalf_clicked() +{ + ui->spinSlow->setValue(ui->spinTargetFPS->value() / 2.0); +} + +void InterfaceSettingsDialog::on_pbQuarter_clicked() +{ + ui->spinSlow->setValue(ui->spinTargetFPS->value() / 4.0); +} + void InterfaceSettingsDialog::done(int r) { if (r == QDialog::Accepted) @@ -74,7 +111,18 @@ void InterfaceSettingsDialog::done(int r) cfg.SetBool("MouseHide", ui->cbMouseHide->isChecked()); cfg.SetInt("MouseHideSeconds", ui->spinMouseHideSeconds->value()); cfg.SetBool("PauseLostFocus", ui->cbPauseLostFocus->isChecked()); - cfg.SetInt("MaxFPS", ui->spinMaxFPS->value()); + + double val = ui->spinTargetFPS->value(); + if (val == 0.0) cfg.SetDouble("TargetFPS", 0.0001); + else cfg.SetDouble("TargetFPS", val); + + val = ui->spinFFW->value(); + if (val == 0.0) cfg.SetDouble("FastForwardFPS", 0.0001); + else cfg.SetDouble("FastForwardFPS", val); + + val = ui->spinSlow->value(); + if (val == 0.0) cfg.SetDouble("SlowmoFPS", 0.0001); + else cfg.SetDouble("SlowmoFPS", val); QString themeName = ui->cbxUITheme->currentData().toString(); cfg.SetQString("UITheme", themeName); diff --git a/src/frontend/qt_sdl/InterfaceSettingsDialog.h b/src/frontend/qt_sdl/InterfaceSettingsDialog.h index bbc62df9..c960e560 100644 --- a/src/frontend/qt_sdl/InterfaceSettingsDialog.h +++ b/src/frontend/qt_sdl/InterfaceSettingsDialog.h @@ -60,6 +60,16 @@ private slots: void on_cbMouseHide_clicked(); + void on_pbClean_clicked(); + void on_pbAccurate_clicked(); + + void on_pb2x_clicked(); + void on_pb3x_clicked(); + void on_pbMAX_clicked(); + + void on_pbHalf_clicked(); + void on_pbQuarter_clicked(); + private: Ui::InterfaceSettingsDialog* ui; diff --git a/src/frontend/qt_sdl/InterfaceSettingsDialog.ui b/src/frontend/qt_sdl/InterfaceSettingsDialog.ui index 21d8434e..460a6e99 100644 --- a/src/frontend/qt_sdl/InterfaceSettingsDialog.ui +++ b/src/frontend/qt_sdl/InterfaceSettingsDialog.ui @@ -6,12 +6,12 @@ 0 0 - 337 - 275 + 389 + 356 - + 0 0 @@ -20,6 +20,9 @@ Interface settings - melonDS + + QLayout::SizeConstraint::SetFixedSize + @@ -95,32 +98,209 @@ Framerate - + - - - Fast-forward limit + + + 6 - - spinMaxFPS + + 2 - - - - - - FPS - - - 60 - - - 1000 - - - 1000 - - + + + + Target FPS + + + + + + + Fast-Forward + + + spinFFW + + + + + + + FPS + + + 4 + + + 0.000100000000000 + + + 1000.000000000000000 + + + 59.826099999999997 + + + + + + + 2 + + + + + + 63 + 16777215 + + + + 1/4 + + + + + + + + 62 + 16777215 + + + + 1/2 + + + + + + + + + FPS + + + 4 + + + 0.000100000000000 + + + 1000.000000000000000 + + + 29.913000000000000 + + + + + + + FPS + + + 4 + + + 0.000100000000000 + + + 1000.000000000000000 + + + 1000.000000000000000 + + + + + + + Slow-Mo + + + + + + + 2 + + + + + + 63 + 16777215 + + + + Accurate + + + + + + + + 62 + 16777215 + + + + Clean + + + + + + + + + 2 + + + + + + 41 + 16777215 + + + + 2x + + + + + + + + 41 + 16777215 + + + + 3x + + + + + + + + 41 + 16777215 + + + + MAX + + + + + + @@ -128,10 +308,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index d40a062e..3020defd 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -1946,8 +1946,9 @@ void MainWindow::onOpenInterfaceSettings() void MainWindow::onUpdateInterfaceSettings() { pauseOnLostFocus = globalCfg.GetBool("PauseLostFocus"); - emuInstance->maxFPS = globalCfg.GetInt("MaxFPS"); - + emuInstance->targetFPS = 1.0 / globalCfg.GetDouble("TargetFPS"); + emuInstance->fastForwardFPS = 1.0 / globalCfg.GetDouble("FastForwardFPS"); + emuInstance->slowmoFPS = 1.0 / globalCfg.GetDouble("SlowmoFPS"); panel->setMouseHide(globalCfg.GetBool("MouseHide"), globalCfg.GetInt("MouseHideSeconds")*1000); } From f13c70d028beac130278b857ca84493841fcc7a1 Mon Sep 17 00:00:00 2001 From: RSDuck Date: Tue, 1 Oct 2024 19:52:10 +0200 Subject: [PATCH 02/47] fix blow noise input (microphone input takes signed values) --- src/frontend/qt_sdl/EmuInstanceAudio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/qt_sdl/EmuInstanceAudio.cpp b/src/frontend/qt_sdl/EmuInstanceAudio.cpp index 21b112ea..a9bf1fb7 100644 --- a/src/frontend/qt_sdl/EmuInstanceAudio.cpp +++ b/src/frontend/qt_sdl/EmuInstanceAudio.cpp @@ -321,7 +321,7 @@ void EmuInstance::micProcess() for (int i = 0; i < 735; i++) { - tmp[i] = mic_blow[sample_pos]; + tmp[i] = mic_blow[sample_pos] ^ 0x8000; sample_pos++; if (sample_pos >= sample_len) sample_pos = 0; } From aa443c8846a16f502a6508786f44f2d66c31101b Mon Sep 17 00:00:00 2001 From: RSDuck Date: Sun, 6 Oct 2024 17:33:03 +0200 Subject: [PATCH 03/47] fix #2083 and minor cleanup --- src/frontend/qt_sdl/CLI.cpp | 4 ++-- src/frontend/qt_sdl/CLI.h | 2 -- src/frontend/qt_sdl/main.cpp | 3 +++ 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/frontend/qt_sdl/CLI.cpp b/src/frontend/qt_sdl/CLI.cpp index 299ce65b..5e352cae 100644 --- a/src/frontend/qt_sdl/CLI.cpp +++ b/src/frontend/qt_sdl/CLI.cpp @@ -96,7 +96,7 @@ CommandLineOptions* ManageArgs(QApplication& melon) } else { - options->errorsToDisplay += "Option -a/--archive-file given, but no archive specified!"; + Log(LogLevel::Error, "Option -a/--archive-file given, but no archive specified!"); } } @@ -108,7 +108,7 @@ CommandLineOptions* ManageArgs(QApplication& melon) } else { - options->errorsToDisplay += "Option -A/--archive-file-gba given, but no archive specified!"; + Log(LogLevel::Error, "Option -A/--archive-file-gba given, but no archive specified!"); } } #endif diff --git a/src/frontend/qt_sdl/CLI.h b/src/frontend/qt_sdl/CLI.h index 4997e6a7..beb120bf 100644 --- a/src/frontend/qt_sdl/CLI.h +++ b/src/frontend/qt_sdl/CLI.h @@ -28,8 +28,6 @@ namespace CLI { struct CommandLineOptions { - QStringList errorsToDisplay = {}; - std::optional dsRomPath; std::optional dsRomArchivePath; std::optional gbaRomPath; diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 9a9c93cb..2643104d 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -364,6 +364,9 @@ int main(int argc, char** argv) if (memberSyntaxUsed) printf("Warning: use the a.zip|b.nds format at your own risk!\n"); win->preloadROMs(dsfile, gbafile, options->boot); + + if (options->fullscreen) + ToggleFullscreen(win); } int ret = melon.exec(); From 30441fed24c1f04cb6a7a162e58c3187c7e5cee0 Mon Sep 17 00:00:00 2001 From: RSDuck Date: Sun, 6 Oct 2024 18:59:19 +0200 Subject: [PATCH 04/47] do not restore fullscreen state from saved geometry --- src/frontend/qt_sdl/Window.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 3020defd..0e4f1b06 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -81,6 +81,7 @@ #include "EmuInstance.h" #include "ArchiveUtil.h" #include "CameraManager.h" +#include "Window.h" using namespace melonDS; @@ -666,6 +667,8 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : QByteArray dec = QByteArray::fromBase64(raw, QByteArray::Base64Encoding | QByteArray::AbortOnBase64DecodingErrors); if (!dec.isEmpty()) restoreGeometry(dec); + // if the window was closed in fullscreen do not restore this + setWindowState(windowState() & ~Qt::WindowFullScreen); } show(); From 216b8e045daffa3582978e81c12fdbe74873e246 Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Mon, 7 Oct 2024 11:28:58 +0200 Subject: [PATCH 05/47] fix audio interpolation setting range --- src/frontend/qt_sdl/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/qt_sdl/Config.cpp b/src/frontend/qt_sdl/Config.cpp index 0a161b6f..3f570302 100644 --- a/src/frontend/qt_sdl/Config.cpp +++ b/src/frontend/qt_sdl/Config.cpp @@ -80,7 +80,7 @@ RangeList IntRanges = {"3D.Renderer", {0, renderer3D_Max-1}}, {"Screen.VSyncInterval", {1, 20}}, {"3D.GL.ScaleFactor", {1, 16}}, - {"Audio.Interpolation", {0, 3}}, + {"Audio.Interpolation", {0, 4}}, {"Instance*.Audio.Volume", {0, 256}}, {"Mic.InputType", {0, micInputType_MAX-1}}, {"Instance*.Window*.ScreenRotation", {0, screenRot_MAX-1}}, From fbf753257b74072d2c95c10b2f40c0534959cf8d Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Sat, 19 Oct 2024 18:29:05 +0200 Subject: [PATCH 06/47] cmake: Add easy sanitizers option Set -DSANITIZE to a comma-separated list of options to pass to -fsanitize=, like -DSANITIZE=address,undefined --- CMakeLists.txt | 1 + cmake/Sanitizers.cmake | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 cmake/Sanitizers.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 40583949..55bf825f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ include(CMakeDependentOption) include(CheckIPOSupported) include(SetupCCache) +include(Sanitizers) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") diff --git a/cmake/Sanitizers.cmake b/cmake/Sanitizers.cmake new file mode 100644 index 00000000..9c09da28 --- /dev/null +++ b/cmake/Sanitizers.cmake @@ -0,0 +1,8 @@ +set(SANITIZE "" CACHE STRING "Sanitizers to enable.") + +string(REGEX MATCHALL "[^,]+" ENABLED_SANITIZERS "${SANITIZE}") + +foreach(SANITIZER ${ENABLED_SANITIZERS}) + add_compile_options("-fsanitize=${SANITIZER}") + add_link_options("-fsanitize=${SANITIZER}") +endforeach() \ No newline at end of file From e5501e555f9d1fb6c4b56354e57cbf908a3ff0e7 Mon Sep 17 00:00:00 2001 From: kaitou <52998298+kaitouctr@users.noreply.github.com> Date: Wed, 23 Oct 2024 05:13:55 +1100 Subject: [PATCH 07/47] fix: set default mode to 24 hours (#2166) --- src/RTC.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RTC.cpp b/src/RTC.cpp index fe262644..24e00de7 100644 --- a/src/RTC.cpp +++ b/src/RTC.cpp @@ -40,7 +40,7 @@ RTC::RTC(melonDS::NDS& nds) : NDS(nds) // indicate the power was off // this will be changed if a previously saved RTC state is loaded - State.StatusReg1 = 0x80; + State.StatusReg1 = 0x80 | (1<<1); } RTC::~RTC() @@ -943,4 +943,4 @@ void RTC::Write(u16 val, bool byte) IO = (IO & 0x0001) | (val & 0xFFFE); } -} \ No newline at end of file +} From b993ec10cd5a3b50f48e8be0e98c4d439f00a597 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 23 Oct 2024 11:57:37 +0200 Subject: [PATCH 08/47] remove "Test" menu item --- src/frontend/qt_sdl/Window.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 0e4f1b06..0280e761 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -623,13 +623,6 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : } } - if (parentWidget() != nullptr) // TEST - { - QMenu* menu = menubar->addMenu("Test"); - - menu->addAction("Test"); - } - actScreenFiltering = menu->addAction("Screen filtering"); actScreenFiltering->setCheckable(true); connect(actScreenFiltering, &QAction::triggered, this, &MainWindow::onChangeScreenFiltering); From d68b58f37e08f16660cdac4c563e404642d0355e Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 23 Oct 2024 14:55:02 +0200 Subject: [PATCH 09/47] fix DSi wifi hang --- src/DSi_NWifi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DSi_NWifi.cpp b/src/DSi_NWifi.cpp index 792bf12d..9827bdbe 100644 --- a/src/DSi_NWifi.cpp +++ b/src/DSi_NWifi.cpp @@ -1445,7 +1445,6 @@ void DSi_NWifi::CheckRX() int rxlen = Platform::Net_RecvPacket(LANBuffer, DSi.UserData); while (rxlen > 0) { - //printf("WMI packet recv %04X %04X %04X\n", *(u16*)&LANBuffer[0], *(u16*)&LANBuffer[2], *(u16*)&LANBuffer[4]); // check destination MAC if (*(u32*)&LANBuffer[0] != 0xFFFFFFFF || *(u16*)&LANBuffer[4] != 0xFFFF) { @@ -1508,6 +1507,7 @@ void DSi_NWifi::CheckRX() Mailbox[8].Write(LANBuffer[14+i]); DrainRXBuffer(); + return; } } From 1428bfb2cfd34dd775b2b04791ee47910484fffe Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 23 Oct 2024 20:33:31 +0200 Subject: [PATCH 10/47] fix one of the cursed bugs --- src/frontend/qt_sdl/EmuInstance.cpp | 19 +++++++++---------- src/frontend/qt_sdl/EmuThread.cpp | 1 - src/frontend/qt_sdl/EmuThread.h | 1 + 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index 54bae531..edb6c559 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -1116,6 +1116,9 @@ void EmuInstance::setDateTime() bool EmuInstance::updateConsole(UpdateConsoleNDSArgs&& _ndsargs, UpdateConsoleGBAArgs&& _gbaargs) noexcept { + // update the console type + consoleType = globalCfg.GetInt("Emu.ConsoleType"); + // Let's get the cart we want to use; // if we wnat to keep the cart, we'll eject it from the existing console first. std::unique_ptr nextndscart; @@ -1149,8 +1152,6 @@ bool EmuInstance::updateConsole(UpdateConsoleNDSArgs&& _ndsargs, UpdateConsoleGB } - int consoletype = globalCfg.GetInt("Emu.ConsoleType"); - auto arm9bios = loadARM9BIOS(); if (!arm9bios) return false; @@ -1159,7 +1160,7 @@ bool EmuInstance::updateConsole(UpdateConsoleNDSArgs&& _ndsargs, UpdateConsoleGB if (!arm7bios) return false; - auto firmware = loadFirmware(consoletype); + auto firmware = loadFirmware(consoleType); if (!firmware) return false; @@ -1203,7 +1204,7 @@ bool EmuInstance::updateConsole(UpdateConsoleNDSArgs&& _ndsargs, UpdateConsoleGB NDSArgs* args = &ndsargs; std::optional dsiargs = std::nullopt; - if (consoletype == 1) + if (consoleType == 1) { ndsargs.GBAROM = nullptr; @@ -1234,19 +1235,19 @@ bool EmuInstance::updateConsole(UpdateConsoleNDSArgs&& _ndsargs, UpdateConsoleGB args = &(*dsiargs); } - - if ((!nds) || (consoletype != nds->ConsoleType)) + if ((!nds) || (consoleType != nds->ConsoleType)) { NDS::Current = nullptr; if (nds) delete nds; - if (consoletype == 1) + if (consoleType == 1) nds = new DSi(std::move(dsiargs.value()), this); else nds = new NDS(std::move(ndsargs), this); NDS::Current = nds; nds->Reset(); + //emuThread->updateVideoRenderer(); // not actually needed? } else { @@ -1260,7 +1261,7 @@ bool EmuInstance::updateConsole(UpdateConsoleNDSArgs&& _ndsargs, UpdateConsoleGB nds->SPU.SetInterpolation(args->Interpolation); nds->SPU.SetDegrade10Bit(args->BitDepth); - if (consoletype == 1) + if (consoleType == 1) { DSi* dsi = (DSi*)nds; DSiArgs& _dsiargs = *dsiargs; @@ -1282,8 +1283,6 @@ bool EmuInstance::updateConsole(UpdateConsoleNDSArgs&& _ndsargs, UpdateConsoleGB void EmuInstance::reset() { - consoleType = globalCfg.GetInt("Emu.ConsoleType"); - updateConsole(Keep {}, Keep {}); if (consoleType == 1) ejectGBACart(); diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 4ce4efda..c6ac80d7 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -664,7 +664,6 @@ void EmuThread::updateRenderer() { if (videoRenderer != lastVideoRenderer) { - printf("creating renderer %d\n", videoRenderer); switch (videoRenderer) { case renderer3D_Software: diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h index cd36eb4c..f728788b 100644 --- a/src/frontend/qt_sdl/EmuThread.h +++ b/src/frontend/qt_sdl/EmuThread.h @@ -106,6 +106,7 @@ public: void initContext(); void deinitContext(); void updateVideoSettings() { videoSettingsDirty = true; } + void updateVideoRenderer() { videoSettingsDirty = true; lastVideoRenderer = -1; } int FrontBuffer = 0; QMutex FrontBufferLock; From 82f38f0b7a3f4214d89c4cd877bbe49d1a6d3485 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 24 Oct 2024 00:27:05 +0200 Subject: [PATCH 11/47] start moving ROM/firmware loading to the emuthread to avoid cursed bugs --- src/frontend/qt_sdl/EmuThread.cpp | 51 +++++++++++++++++++++++++++++-- src/frontend/qt_sdl/EmuThread.h | 13 +++++--- src/frontend/qt_sdl/Window.cpp | 47 +++------------------------- 3 files changed, 63 insertions(+), 48 deletions(-) diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index c6ac80d7..9a7ea6cb 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -541,7 +541,8 @@ void EmuThread::handleMessages() break; case msg_EmuStop: - if (msg.stopExternal) emuInstance->nds->Stop(); + if (msg.param.value()) + emuInstance->nds->Stop(); emuStatus = emuStatus_Paused; emuActive = false; @@ -574,6 +575,26 @@ void EmuThread::handleMessages() emuInstance->deinitOpenGL(); useOpenGL = false; break; + + case msg_BootROM: + bootResult = 0; + if (!emuInstance->loadROM(msg.param.value(), true)) + break; + + assert(emuInstance->nds != nullptr); + emuInstance->nds->Start(); + bootResult = 1; + break; + + case msg_BootFirmware: + bootResult = 0; + if (!emuInstance->bootToMenu()) + break; + + assert(emuInstance->nds != nullptr); + emuInstance->nds->Start(); + bootResult = 1; + break; } msgSemaphore.release(); @@ -626,7 +647,7 @@ void EmuThread::emuTogglePause() void EmuThread::emuStop(bool external) { - sendMessage({.type = msg_EmuStop, .stopExternal = external}); + sendMessage({.type = msg_EmuStop, .param = external}); waitMessage(); } @@ -660,6 +681,32 @@ bool EmuThread::emuIsActive() return emuActive; } +int EmuThread::bootROM(QStringList filename) +{ + sendMessage(msg_EmuPause); + sendMessage({.type = msg_BootROM, .param = filename}); + waitMessage(2); + if (!bootResult) + return bootResult; + + sendMessage(msg_EmuRun); + waitMessage(); + return bootResult; +} + +int EmuThread::bootFirmware() +{ + sendMessage(msg_EmuPause); + sendMessage(msg_BootFirmware); + waitMessage(2); + if (!bootResult) + return bootResult; + + sendMessage(msg_EmuRun); + waitMessage(); + return bootResult; +} + void EmuThread::updateRenderer() { if (videoRenderer != lastVideoRenderer) diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h index f728788b..612f7920 100644 --- a/src/frontend/qt_sdl/EmuThread.h +++ b/src/frontend/qt_sdl/EmuThread.h @@ -68,15 +68,15 @@ public: msg_InitGL, msg_DeInitGL, + + msg_BootROM, + msg_BootFirmware, }; struct Message { MessageType type; - union - { - bool stopExternal; - }; + QVariant param; }; void sendMessage(Message msg); @@ -100,6 +100,9 @@ public: void emuFrameStep(); void emuReset(); + int bootROM(QStringList filename); + int bootFirmware(); + bool emuIsRunning(); bool emuIsActive(); @@ -153,6 +156,8 @@ private: constexpr static int emuPauseStackPauseThreshold = 1; int emuPauseStack; + int bootResult = 0; + QMutex msgMutex; QSemaphore msgSemaphore; QQueue msgQueue; diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 0280e761..6f2f86a9 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -1211,24 +1211,15 @@ void MainWindow::updateCartInserted(bool gba) void MainWindow::onOpenFile() { - emuThread->emuPause(); - if (!verifySetup()) - { - emuThread->emuUnpause(); return; - } QStringList file = pickROM(false); if (file.isEmpty()) - { - emuThread->emuUnpause(); return; - } - - if (!emuInstance->loadROM(file, true)) + + if (!emuThread->bootROM(file)) { - emuThread->emuUnpause(); return; } @@ -1237,10 +1228,6 @@ void MainWindow::onOpenFile() recentFileList.prepend(filename); updateRecentFilesMenu(); - assert(emuInstance->nds != nullptr); - emuInstance->nds->Start(); - emuThread->emuRun(); - updateCartInserted(false); } @@ -1310,24 +1297,15 @@ void MainWindow::onClickRecentFile() QAction *act = (QAction *)sender(); QString filename = act->data().toString(); - emuThread->emuPause(); - if (!verifySetup()) - { - emuThread->emuUnpause(); return; - } const QStringList file = splitArchivePath(filename, true); if (file.isEmpty()) - { - emuThread->emuUnpause(); return; - } - - if (!emuInstance->loadROM(file, true)) + + if (!emuThread->bootROM(file)) { - emuThread->emuUnpause(); return; } @@ -1335,34 +1313,19 @@ void MainWindow::onClickRecentFile() recentFileList.prepend(filename); updateRecentFilesMenu(); - assert(emuInstance->nds != nullptr); - emuInstance->nds->Start(); - emuThread->emuRun(); - updateCartInserted(false); } void MainWindow::onBootFirmware() { - emuThread->emuPause(); - if (!verifySetup()) - { - emuThread->emuUnpause(); return; - } - if (!emuInstance->bootToMenu()) + if (!emuThread->bootFirmware()) { - // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "This firmware is not bootable."); - emuThread->emuUnpause(); return; } - - assert(emuInstance->nds != nullptr); - emuInstance->nds->Start(); - emuThread->emuRun(); } void MainWindow::onInsertCart() From 079341f102f1ded4211196c148df420a5a56344c Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 24 Oct 2024 11:44:21 +0200 Subject: [PATCH 12/47] take this a bit further --- src/frontend/qt_sdl/EmuThread.cpp | 60 ++++++++++++++++++++++++++++--- src/frontend/qt_sdl/EmuThread.h | 10 +++++- src/frontend/qt_sdl/Window.cpp | 49 +++++-------------------- 3 files changed, 73 insertions(+), 46 deletions(-) diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 9a7ea6cb..7c3e1a91 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -595,6 +595,36 @@ void EmuThread::handleMessages() emuInstance->nds->Start(); bootResult = 1; break; + + case msg_InsertCart: + bootResult = 0; + if (!emuInstance->loadROM(msg.param.value(), false)) + break; + + bootResult = 1; + break; + + case msg_EjectCart: + emuInstance->ejectCart(); + break; + + case msg_InsertGBACart: + bootResult = 0; + if (!emuInstance->loadGBAROM(msg.param.value())) + break; + + bootResult = 1; + break; + + case msg_InsertGBAAddon: + bootResult = 0; + emuInstance->loadGBAAddon(msg.param.value()); + bootResult = 1; + break; + + case msg_EjectGBACart: + emuInstance->ejectCart(); + break; } msgSemaphore.release(); @@ -681,11 +711,10 @@ bool EmuThread::emuIsActive() return emuActive; } -int EmuThread::bootROM(QStringList filename) +int EmuThread::bootROM(const QStringList& filename) { - sendMessage(msg_EmuPause); sendMessage({.type = msg_BootROM, .param = filename}); - waitMessage(2); + waitMessage(); if (!bootResult) return bootResult; @@ -696,9 +725,8 @@ int EmuThread::bootROM(QStringList filename) int EmuThread::bootFirmware() { - sendMessage(msg_EmuPause); sendMessage(msg_BootFirmware); - waitMessage(2); + waitMessage(); if (!bootResult) return bootResult; @@ -707,6 +735,28 @@ int EmuThread::bootFirmware() return bootResult; } +int EmuThread::insertCart(const QStringList& filename, bool gba) +{ + MessageType msgtype = gba ? msg_InsertGBACart : msg_InsertCart; + + sendMessage({.type = msgtype, .param = filename}); + waitMessage(); + return bootResult; +} + +void EmuThread::ejectCart(bool gba) +{ + sendMessage(gba ? msg_EjectGBACart : msg_EjectCart); + waitMessage(); +} + +int EmuThread::insertGBAAddon(int type) +{ + sendMessage({.type = msg_InsertGBAAddon, .param = type}); + waitMessage(); + return bootResult; +} + void EmuThread::updateRenderer() { if (videoRenderer != lastVideoRenderer) diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h index 612f7920..a21cc511 100644 --- a/src/frontend/qt_sdl/EmuThread.h +++ b/src/frontend/qt_sdl/EmuThread.h @@ -71,6 +71,11 @@ public: msg_BootROM, msg_BootFirmware, + msg_InsertCart, + msg_EjectCart, + msg_InsertGBACart, + msg_InsertGBAAddon, + msg_EjectGBACart, }; struct Message @@ -100,8 +105,11 @@ public: void emuFrameStep(); void emuReset(); - int bootROM(QStringList filename); + int bootROM(const QStringList& filename); int bootFirmware(); + int insertCart(const QStringList& filename, bool gba); + void ejectCart(bool gba); + int insertGBAAddon(int type); bool emuIsRunning(); bool emuIsActive(); diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 6f2f86a9..c267eb85 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -1330,56 +1330,35 @@ void MainWindow::onBootFirmware() void MainWindow::onInsertCart() { - emuThread->emuPause(); - QStringList file = pickROM(false); if (file.isEmpty()) + return; + + if (!emuThread->insertCart(file, false)) { - emuThread->emuUnpause(); return; } - if (!emuInstance->loadROM(file, false)) - { - emuThread->emuUnpause(); - return; - } - - emuThread->emuUnpause(); - updateCartInserted(false); } void MainWindow::onEjectCart() { - emuThread->emuPause(); - - emuInstance->ejectCart(); - - emuThread->emuUnpause(); - + emuThread->ejectCart(false); updateCartInserted(false); } void MainWindow::onInsertGBACart() { - emuThread->emuPause(); - QStringList file = pickROM(true); if (file.isEmpty()) + return; + + if (!emuThread->insertCart(file, true)) { - emuThread->emuUnpause(); return; } - if (!emuInstance->loadGBAROM(file)) - { - emuThread->emuUnpause(); - return; - } - - emuThread->emuUnpause(); - updateCartInserted(true); } @@ -1388,23 +1367,13 @@ void MainWindow::onInsertGBAAddon() QAction* act = (QAction*)sender(); int type = act->data().toInt(); - emuThread->emuPause(); - - emuInstance->loadGBAAddon(type); - - emuThread->emuUnpause(); - + emuThread->insertGBAAddon(type); updateCartInserted(true); } void MainWindow::onEjectGBACart() { - emuThread->emuPause(); - - emuInstance->ejectGBACart(); - - emuThread->emuUnpause(); - + emuThread->ejectCart(true); updateCartInserted(true); } From 6d3ea6a485930c027488ea0f376a12e77aead4bd Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 24 Oct 2024 13:49:43 +0200 Subject: [PATCH 13/47] fix bug with the GBA addon menu (and make it a proper list so we don't have to hardcode the length all over) --- src/frontend/qt_sdl/Window.cpp | 27 +++++++++++++++------------ src/frontend/qt_sdl/Window.h | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index c267eb85..ecf7f771 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -311,14 +311,17 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : { QMenu* submenu = menu->addMenu("Insert add-on cart"); + QAction* act; - actInsertGBAAddon[0] = submenu->addAction("Memory expansion"); - actInsertGBAAddon[0]->setData(QVariant(GBAAddon_RAMExpansion)); - connect(actInsertGBAAddon[0], &QAction::triggered, this, &MainWindow::onInsertGBAAddon); + act = submenu->addAction("Memory expansion"); + act->setData(QVariant(GBAAddon_RAMExpansion)); + connect(act, &QAction::triggered, this, &MainWindow::onInsertGBAAddon); + actInsertGBAAddon.append(act); - actInsertGBAAddon[1] = submenu->addAction("Rumble Pak"); - actInsertGBAAddon[1]->setData(QVariant(GBAAddon_RumblePak)); - connect(actInsertGBAAddon[1], &QAction::triggered, this, &MainWindow::onInsertGBAAddon); + act = submenu->addAction("Rumble Pak"); + act->setData(QVariant(GBAAddon_RumblePak)); + connect(act, &QAction::triggered, this, &MainWindow::onInsertGBAAddon); + actInsertGBAAddon.append(act); } actEjectGBACart = menu->addAction("Eject cart"); @@ -673,8 +676,8 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : if (globalCfg.GetInt("Emu.ConsoleType") == 1) { actInsertGBACart->setEnabled(false); - for (int i = 0; i < 1; i++) - actInsertGBAAddon[i]->setEnabled(false); + for (auto act : actInsertGBAAddon) + act->setEnabled(false); } for (int i = 0; i < 9; i++) @@ -1700,15 +1703,15 @@ void MainWindow::onEmuSettingsDialogFinished(int res) if (globalCfg.GetInt("Emu.ConsoleType") == 1) { actInsertGBACart->setEnabled(false); - for (int i = 0; i < 1; i++) - actInsertGBAAddon[i]->setEnabled(false); + for (auto act : actInsertGBAAddon) + act->setEnabled(false); actEjectGBACart->setEnabled(false); } else { actInsertGBACart->setEnabled(true); - for (int i = 0; i < 1; i++) - actInsertGBAAddon[i]->setEnabled(true); + for (auto act : actInsertGBAAddon) + act->setEnabled(true); actEjectGBACart->setEnabled(emuInstance->gbaCartInserted()); } diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h index 30d97b17..9125f76a 100644 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -269,7 +269,7 @@ public: QAction* actEjectCart; QAction* actCurrentGBACart; QAction* actInsertGBACart; - QAction* actInsertGBAAddon[2]; + QList actInsertGBAAddon; QAction* actEjectGBACart; QAction* actImportSavefile; QAction* actSaveState[9]; From 1666049531c5ebd806ee0c865bd6b3442d8caf58 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 24 Oct 2024 14:00:11 +0200 Subject: [PATCH 14/47] fix shit --- src/frontend/qt_sdl/EmuInstance.cpp | 35 +++++++++++++++++++---------- src/frontend/qt_sdl/EmuInstance.h | 1 + src/frontend/qt_sdl/EmuThread.cpp | 2 +- src/frontend/qt_sdl/Window.cpp | 18 +++++++-------- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index edb6c559..c4c003fb 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -1972,25 +1972,36 @@ bool EmuInstance::gbaCartInserted() return gbaCartType != -1; } +QString EmuInstance::gbaAddonName(int addon) +{ + switch (addon) + { + case GBAAddon_RumblePak: + return "Rumble Pak"; + case GBAAddon_RAMExpansion: + return "Memory expansion"; + } + + return "???"; +} + QString EmuInstance::gbaCartLabel() { if (consoleType == 1) return "none (DSi)"; - switch (gbaCartType) + if (gbaCartType == 0) { - case 0: - { - QString ret = QString::fromStdString(baseGBAROMName); + QString ret = QString::fromStdString(baseGBAROMName); - int maxlen = 32; - if (ret.length() > maxlen) - ret = ret.left(maxlen-6) + "..." + ret.right(3); + int maxlen = 32; + if (ret.length() > maxlen) + ret = ret.left(maxlen-6) + "..." + ret.right(3); - return ret; - } - - case GBAAddon_RAMExpansion: - return "Memory expansion"; + return ret; + } + else if (gbaCartType != -1) + { + return gbaAddonName(gbaCartType); } return "(none)"; diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index 04290f56..9e0659e0 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -186,6 +186,7 @@ private: void loadGBAAddon(int type); void ejectGBACart(); bool gbaCartInserted(); + QString gbaAddonName(int addon); QString gbaCartLabel(); void audioInit(); diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 7c3e1a91..c3668fe3 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -623,7 +623,7 @@ void EmuThread::handleMessages() break; case msg_EjectGBACart: - emuInstance->ejectCart(); + emuInstance->ejectGBACart(); break; } diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index ecf7f771..ce900cbb 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -313,15 +313,15 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : QMenu* submenu = menu->addMenu("Insert add-on cart"); QAction* act; - act = submenu->addAction("Memory expansion"); - act->setData(QVariant(GBAAddon_RAMExpansion)); - connect(act, &QAction::triggered, this, &MainWindow::onInsertGBAAddon); - actInsertGBAAddon.append(act); - - act = submenu->addAction("Rumble Pak"); - act->setData(QVariant(GBAAddon_RumblePak)); - connect(act, &QAction::triggered, this, &MainWindow::onInsertGBAAddon); - actInsertGBAAddon.append(act); + int addons[] = {GBAAddon_RAMExpansion, GBAAddon_RumblePak, -1}; + for (int i = 0; addons[i] != -1; i++) + { + int addon = addons[i]; + act = submenu->addAction(emuInstance->gbaAddonName(addon)); + act->setData(QVariant(addon)); + connect(act, &QAction::triggered, this, &MainWindow::onInsertGBAAddon); + actInsertGBAAddon.append(act); + } } actEjectGBACart = menu->addAction("Eject cart"); From 13b4cea171f38461fa798b818ce2d1457c1a5c20 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 24 Oct 2024 16:08:04 +0200 Subject: [PATCH 15/47] move screen layout/etc options to new View menu --- src/frontend/qt_sdl/Window.cpp | 95 +++++++++++++++++----------------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index ce900cbb..f88c1dc7 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -458,53 +458,7 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : } } { - QMenu* menu = menubar->addMenu("Config"); - - actEmuSettings = menu->addAction("Emu settings"); - connect(actEmuSettings, &QAction::triggered, this, &MainWindow::onOpenEmuSettings); - -#ifdef __APPLE__ - actPreferences = menu->addAction("Preferences..."); - connect(actPreferences, &QAction::triggered, this, &MainWindow::onOpenEmuSettings); - actPreferences->setMenuRole(QAction::PreferencesRole); -#endif - - actInputConfig = menu->addAction("Input and hotkeys"); - connect(actInputConfig, &QAction::triggered, this, &MainWindow::onOpenInputConfig); - - actVideoSettings = menu->addAction("Video settings"); - connect(actVideoSettings, &QAction::triggered, this, &MainWindow::onOpenVideoSettings); - - actCameraSettings = menu->addAction("Camera settings"); - connect(actCameraSettings, &QAction::triggered, this, &MainWindow::onOpenCameraSettings); - - actAudioSettings = menu->addAction("Audio settings"); - connect(actAudioSettings, &QAction::triggered, this, &MainWindow::onOpenAudioSettings); - - actMPSettings = menu->addAction("Multiplayer settings"); - connect(actMPSettings, &QAction::triggered, this, &MainWindow::onOpenMPSettings); - - actWifiSettings = menu->addAction("Wifi settings"); - connect(actWifiSettings, &QAction::triggered, this, &MainWindow::onOpenWifiSettings); - - actFirmwareSettings = menu->addAction("Firmware settings"); - connect(actFirmwareSettings, &QAction::triggered, this, &MainWindow::onOpenFirmwareSettings); - - actInterfaceSettings = menu->addAction("Interface settings"); - connect(actInterfaceSettings, &QAction::triggered, this, &MainWindow::onOpenInterfaceSettings); - - actPathSettings = menu->addAction("Path settings"); - connect(actPathSettings, &QAction::triggered, this, &MainWindow::onOpenPathSettings); - - { - QMenu* submenu = menu->addMenu("Savestate settings"); - - actSavestateSRAMReloc = submenu->addAction("Separate savefiles"); - actSavestateSRAMReloc->setCheckable(true); - connect(actSavestateSRAMReloc, &QAction::triggered, this, &MainWindow::onChangeSavestateSRAMReloc); - } - - menu->addSeparator(); + QMenu *menu = menubar->addMenu("View"); { QMenu* submenu = menu->addMenu("Screen size"); @@ -633,6 +587,53 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : actShowOSD = menu->addAction("Show OSD"); actShowOSD->setCheckable(true); connect(actShowOSD, &QAction::triggered, this, &MainWindow::onChangeShowOSD); + } + { + QMenu* menu = menubar->addMenu("Config"); + + actEmuSettings = menu->addAction("Emu settings"); + connect(actEmuSettings, &QAction::triggered, this, &MainWindow::onOpenEmuSettings); + +#ifdef __APPLE__ + actPreferences = menu->addAction("Preferences..."); + connect(actPreferences, &QAction::triggered, this, &MainWindow::onOpenEmuSettings); + actPreferences->setMenuRole(QAction::PreferencesRole); +#endif + + actInputConfig = menu->addAction("Input and hotkeys"); + connect(actInputConfig, &QAction::triggered, this, &MainWindow::onOpenInputConfig); + + actVideoSettings = menu->addAction("Video settings"); + connect(actVideoSettings, &QAction::triggered, this, &MainWindow::onOpenVideoSettings); + + actCameraSettings = menu->addAction("Camera settings"); + connect(actCameraSettings, &QAction::triggered, this, &MainWindow::onOpenCameraSettings); + + actAudioSettings = menu->addAction("Audio settings"); + connect(actAudioSettings, &QAction::triggered, this, &MainWindow::onOpenAudioSettings); + + actMPSettings = menu->addAction("Multiplayer settings"); + connect(actMPSettings, &QAction::triggered, this, &MainWindow::onOpenMPSettings); + + actWifiSettings = menu->addAction("Wifi settings"); + connect(actWifiSettings, &QAction::triggered, this, &MainWindow::onOpenWifiSettings); + + actFirmwareSettings = menu->addAction("Firmware settings"); + connect(actFirmwareSettings, &QAction::triggered, this, &MainWindow::onOpenFirmwareSettings); + + actInterfaceSettings = menu->addAction("Interface settings"); + connect(actInterfaceSettings, &QAction::triggered, this, &MainWindow::onOpenInterfaceSettings); + + actPathSettings = menu->addAction("Path settings"); + connect(actPathSettings, &QAction::triggered, this, &MainWindow::onOpenPathSettings); + + { + QMenu* submenu = menu->addMenu("Savestate settings"); + + actSavestateSRAMReloc = submenu->addAction("Separate savefiles"); + actSavestateSRAMReloc->setCheckable(true); + connect(actSavestateSRAMReloc, &QAction::triggered, this, &MainWindow::onChangeSavestateSRAMReloc); + } menu->addSeparator(); From 1787235e09d78732204172f68648d84d50bb807d Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 24 Oct 2024 17:20:14 +0200 Subject: [PATCH 16/47] fix more shit now it doesn't shit itself on startup if the BIOS paths are wrong --- src/frontend/qt_sdl/EmuInstance.cpp | 38 +++++++++++++- src/frontend/qt_sdl/EmuInstance.h | 5 +- src/frontend/qt_sdl/EmuThread.cpp | 28 ++-------- src/frontend/qt_sdl/Screen.cpp | 81 +++++++++++++++-------------- src/frontend/qt_sdl/Window.cpp | 3 ++ 5 files changed, 89 insertions(+), 66 deletions(-) diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index c4c003fb..402af56b 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -154,6 +154,13 @@ EmuInstance::~EmuInstance() audioDeInit(); inputDeInit(); + + NDS::Current = nullptr; + if (nds) + { + saveRTCData(); + delete nds; + } } @@ -1105,6 +1112,30 @@ void EmuInstance::setBatteryLevels() } } +void EmuInstance::loadRTCData() +{ + auto file = Platform::OpenLocalFile("rtc.bin", Platform::FileMode::Read); + if (file) + { + RTC::StateData state; + Platform::FileRead(&state, sizeof(state), 1, file); + Platform::CloseFile(file); + nds->RTC.SetState(state); + } +} + +void EmuInstance::saveRTCData() +{ + auto file = Platform::OpenLocalFile("rtc.bin", Platform::FileMode::Write); + if (file) + { + RTC::StateData state; + nds->RTC.GetState(state); + Platform::FileWrite(&state, sizeof(state), 1, file); + Platform::CloseFile(file); + } +} + void EmuInstance::setDateTime() { QDateTime hosttime = QDateTime::currentDateTime(); @@ -1238,7 +1269,11 @@ bool EmuInstance::updateConsole(UpdateConsoleNDSArgs&& _ndsargs, UpdateConsoleGB if ((!nds) || (consoleType != nds->ConsoleType)) { NDS::Current = nullptr; - if (nds) delete nds; + if (nds) + { + saveRTCData(); + delete nds; + } if (consoleType == 1) nds = new DSi(std::move(dsiargs.value()), this); @@ -1247,6 +1282,7 @@ bool EmuInstance::updateConsole(UpdateConsoleNDSArgs&& _ndsargs, UpdateConsoleGB NDS::Current = nds; nds->Reset(); + loadRTCData(); //emuThread->updateVideoRenderer(); // not actually needed? } else diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index 9e0659e0..742bebba 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -168,7 +168,6 @@ private: std::optional getSDCardArgs(const std::string& key) noexcept; std::optional loadSDCard(const std::string& key) noexcept; void setBatteryLevels(); - void setDateTime(); void reset(); bool bootToMenu(); melonDS::u32 decompressROM(const melonDS::u8* inContent, const melonDS::u32 inSize, std::unique_ptr& outContent); @@ -223,6 +222,10 @@ private: bool hotkeyPressed(int id) { return hotkeyPress & (1<getGlobalConfig(); u32 mainScreenPos[3]; - Platform::FileHandle* file; - emuInstance->updateConsole(nullptr, nullptr); + //emuInstance->updateConsole(nullptr, nullptr); // No carts are inserted when melonDS first boots mainScreenPos[0] = 0; @@ -112,7 +111,7 @@ void EmuThread::run() mainScreenPos[2] = 0; autoScreenSizing = 0; - videoSettingsDirty = false; + //videoSettingsDirty = false; if (emuInstance->usesOpenGL()) { @@ -127,7 +126,8 @@ void EmuThread::run() videoRenderer = 0; } - updateRenderer(); + //updateRenderer(); + videoSettingsDirty = true; u32 nframes = 0; double perfCountsSec = 1.0 / SDL_GetPerformanceFrequency(); @@ -138,15 +138,6 @@ void EmuThread::run() u32 winUpdateCount = 0, winUpdateFreq = 1; u8 dsiVolumeLevel = 0x1F; - file = Platform::OpenLocalFile("rtc.bin", Platform::FileMode::Read); - if (file) - { - RTC::StateData state; - Platform::FileRead(&state, sizeof(state), 1, file); - Platform::CloseFile(file); - emuInstance->nds->RTC.SetState(state); - } - char melontitle[100]; bool fastforward = false; @@ -453,17 +444,6 @@ void EmuThread::run() handleMessages(); } - - file = Platform::OpenLocalFile("rtc.bin", Platform::FileMode::Write); - if (file) - { - RTC::StateData state; - emuInstance->nds->RTC.GetState(state); - Platform::FileWrite(&state, sizeof(state), 1, file); - Platform::CloseFile(file); - } - - NDS::Current = nullptr; } void EmuThread::sendMessage(Message msg) diff --git a/src/frontend/qt_sdl/Screen.cpp b/src/frontend/qt_sdl/Screen.cpp index 425d99b5..3780de55 100644 --- a/src/frontend/qt_sdl/Screen.cpp +++ b/src/frontend/qt_sdl/Screen.cpp @@ -947,9 +947,6 @@ void ScreenPanelGL::drawScreenGL() { if (!glContext) return; - auto nds = emuInstance->getNDS(); - if (!nds) return; - auto emuThread = emuInstance->getEmuThread(); glContext->MakeCurrent(); @@ -968,50 +965,54 @@ void ScreenPanelGL::drawScreenGL() glViewport(0, 0, w, h); - glUseProgram(screenShaderProgram); - glUniform2f(screenShaderScreenSizeULoc, w / factor, h / factor); + if (emuThread->emuIsActive()) + { + auto nds = emuInstance->getNDS(); - int frontbuf = emuThread->FrontBuffer; - glActiveTexture(GL_TEXTURE0); + glUseProgram(screenShaderProgram); + glUniform2f(screenShaderScreenSizeULoc, w / factor, h / factor); + + int frontbuf = emuThread->FrontBuffer; + glActiveTexture(GL_TEXTURE0); #ifdef OGLRENDERER_ENABLED - if (nds->GPU.GetRenderer3D().Accelerated) - { - // hardware-accelerated render - nds->GPU.GetRenderer3D().BindOutputTexture(frontbuf); - } - else -#endif - { - // regular render - glBindTexture(GL_TEXTURE_2D, screenTexture); - - if (nds->GPU.Framebuffer[frontbuf][0] && nds->GPU.Framebuffer[frontbuf][1]) + if (nds->GPU.GetRenderer3D().Accelerated) { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA, - GL_UNSIGNED_BYTE, nds->GPU.Framebuffer[frontbuf][0].get()); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA, - GL_UNSIGNED_BYTE, nds->GPU.Framebuffer[frontbuf][1].get()); + // hardware-accelerated render + nds->GPU.GetRenderer3D().BindOutputTexture(frontbuf); + } else +#endif + { + // regular render + glBindTexture(GL_TEXTURE_2D, screenTexture); + + if (nds->GPU.Framebuffer[frontbuf][0] && nds->GPU.Framebuffer[frontbuf][1]) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA, + GL_UNSIGNED_BYTE, nds->GPU.Framebuffer[frontbuf][0].get()); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192 + 2, 256, 192, GL_RGBA, + GL_UNSIGNED_BYTE, nds->GPU.Framebuffer[frontbuf][1].get()); + } } + + screenSettingsLock.lock(); + + GLint filter = this->filter ? GL_LINEAR : GL_NEAREST; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + + glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer); + glBindVertexArray(screenVertexArray); + + for (int i = 0; i < numScreens; i++) + { + glUniformMatrix2x3fv(screenShaderTransformULoc, 1, GL_TRUE, screenMatrix[i]); + glDrawArrays(GL_TRIANGLES, screenKind[i] == 0 ? 0 : 2 * 3, 2 * 3); + } + + screenSettingsLock.unlock(); } - screenSettingsLock.lock(); - - GLint filter = this->filter ? GL_LINEAR : GL_NEAREST; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); - - glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer); - glBindVertexArray(screenVertexArray); - - for (int i = 0; i < numScreens; i++) - { - glUniformMatrix2x3fv(screenShaderTransformULoc, 1, GL_TRUE, screenMatrix[i]); - glDrawArrays(GL_TRIANGLES, screenKind[i] == 0 ? 0 : 2*3, 2*3); - } - - screenSettingsLock.unlock(); - osdUpdate(); if (osdEnabled) { diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index f88c1dc7..a19b29ed 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -1009,6 +1009,9 @@ bool MainWindow::verifySetup() bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot) { + if (file.isEmpty() && gbafile.isEmpty()) + return false; + if (!verifySetup()) { return false; From 3fc065d72d03112ba26b617033537e398e3fbcb2 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 24 Oct 2024 17:48:34 +0200 Subject: [PATCH 17/47] fix ROM preloading to also go through EmuThread --- src/frontend/qt_sdl/Window.cpp | 31 +++++++++++++++---------------- src/frontend/qt_sdl/main.cpp | 4 +--- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index a19b29ed..65e85f1c 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -1020,7 +1020,8 @@ bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot) bool gbaloaded = false; if (!gbafile.isEmpty()) { - if (!emuInstance->loadGBAROM(gbafile)) return false; + if (!emuThread->insertCart(gbafile, true)) + return false; gbaloaded = true; } @@ -1028,33 +1029,31 @@ bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot) bool ndsloaded = false; if (!file.isEmpty()) { - if (!emuInstance->loadROM(file, true)) return false; + if (boot) + { + if (!emuThread->bootROM(file)) + return false; + } + else + { + if (!emuThread->insertCart(file, false)) + return false; + } recentFileList.removeAll(file.join("|")); recentFileList.prepend(file.join("|")); updateRecentFilesMenu(); ndsloaded = true; } - - if (boot) + else if (boot) { - if (ndsloaded) - { - emuInstance->nds->Start(); - emuThread->emuRun(); - } - else - { - onBootFirmware(); - } + if (!emuThread->bootFirmware()) + return false; } updateCartInserted(false); - if (gbaloaded) - { updateCartInserted(true); - } return true; } diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 2643104d..6d18adaf 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -250,10 +250,8 @@ bool MelonApplication::event(QEvent *event) MainWindow* win = inst->getMainWindow(); QFileOpenEvent *openEvent = static_cast(event); - inst->getEmuThread()->emuPause(); const QStringList file = win->splitArchivePath(openEvent->file(), true); - if (!win->preloadROMs(file, {}, true)) - inst->getEmuThread()->emuUnpause(); + win->preloadROMs(file, {}, true); } return QApplication::event(event); From 75e6856af479b81f7066abc97e20d83f781a64c4 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 24 Oct 2024 19:27:45 +0200 Subject: [PATCH 18/47] route savestate stuff through EmuThread --- src/frontend/qt_sdl/EmuThread.cpp | 70 +++++++++++++++++++++++-------- src/frontend/qt_sdl/EmuThread.h | 10 ++++- src/frontend/qt_sdl/Window.cpp | 45 ++++++-------------- 3 files changed, 73 insertions(+), 52 deletions(-) diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 590d10f5..d73cd6ea 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -557,31 +557,31 @@ void EmuThread::handleMessages() break; case msg_BootROM: - bootResult = 0; + msgResult = 0; if (!emuInstance->loadROM(msg.param.value(), true)) break; assert(emuInstance->nds != nullptr); emuInstance->nds->Start(); - bootResult = 1; + msgResult = 1; break; case msg_BootFirmware: - bootResult = 0; + msgResult = 0; if (!emuInstance->bootToMenu()) break; assert(emuInstance->nds != nullptr); emuInstance->nds->Start(); - bootResult = 1; + msgResult = 1; break; case msg_InsertCart: - bootResult = 0; + msgResult = 0; if (!emuInstance->loadROM(msg.param.value(), false)) break; - bootResult = 1; + msgResult = 1; break; case msg_EjectCart: @@ -589,22 +589,35 @@ void EmuThread::handleMessages() break; case msg_InsertGBACart: - bootResult = 0; + msgResult = 0; if (!emuInstance->loadGBAROM(msg.param.value())) break; - bootResult = 1; + msgResult = 1; break; case msg_InsertGBAAddon: - bootResult = 0; + msgResult = 0; emuInstance->loadGBAAddon(msg.param.value()); - bootResult = 1; + msgResult = 1; break; case msg_EjectGBACart: emuInstance->ejectGBACart(); break; + + case msg_SaveState: + msgResult = emuInstance->saveState(msg.param.value().toStdString()); + break; + + case msg_LoadState: + msgResult = emuInstance->loadState(msg.param.value().toStdString()); + break; + + case msg_UndoStateLoad: + emuInstance->undoStateLoad(); + msgResult = 1; + break; } msgSemaphore.release(); @@ -695,24 +708,24 @@ int EmuThread::bootROM(const QStringList& filename) { sendMessage({.type = msg_BootROM, .param = filename}); waitMessage(); - if (!bootResult) - return bootResult; + if (!msgResult) + return msgResult; sendMessage(msg_EmuRun); waitMessage(); - return bootResult; + return msgResult; } int EmuThread::bootFirmware() { sendMessage(msg_BootFirmware); waitMessage(); - if (!bootResult) - return bootResult; + if (!msgResult) + return msgResult; sendMessage(msg_EmuRun); waitMessage(); - return bootResult; + return msgResult; } int EmuThread::insertCart(const QStringList& filename, bool gba) @@ -721,7 +734,7 @@ int EmuThread::insertCart(const QStringList& filename, bool gba) sendMessage({.type = msgtype, .param = filename}); waitMessage(); - return bootResult; + return msgResult; } void EmuThread::ejectCart(bool gba) @@ -734,7 +747,28 @@ int EmuThread::insertGBAAddon(int type) { sendMessage({.type = msg_InsertGBAAddon, .param = type}); waitMessage(); - return bootResult; + return msgResult; +} + +int EmuThread::saveState(const QString& filename) +{ + sendMessage({.type = msg_SaveState, .param = filename}); + waitMessage(); + return msgResult; +} + +int EmuThread::loadState(const QString& filename) +{ + sendMessage({.type = msg_LoadState, .param = filename}); + waitMessage(); + return msgResult; +} + +int EmuThread::undoStateLoad() +{ + sendMessage(msg_UndoStateLoad); + waitMessage(); + return msgResult; } void EmuThread::updateRenderer() diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h index a21cc511..52648520 100644 --- a/src/frontend/qt_sdl/EmuThread.h +++ b/src/frontend/qt_sdl/EmuThread.h @@ -76,6 +76,10 @@ public: msg_InsertGBACart, msg_InsertGBAAddon, msg_EjectGBACart, + + msg_LoadState, + msg_SaveState, + msg_UndoStateLoad, }; struct Message @@ -111,6 +115,10 @@ public: void ejectCart(bool gba); int insertGBAAddon(int type); + int saveState(const QString& filename); + int loadState(const QString& filename); + int undoStateLoad(); + bool emuIsRunning(); bool emuIsActive(); @@ -164,7 +172,7 @@ private: constexpr static int emuPauseStackPauseThreshold = 1; int emuPauseStack; - int bootResult = 0; + int msgResult = 0; QMutex msgMutex; QSemaphore msgSemaphore; diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 65e85f1c..cf65fe2c 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -1387,30 +1387,23 @@ void MainWindow::onSaveState() { int slot = ((QAction*)sender())->data().toInt(); - emuThread->emuPause(); - - std::string filename; + QString filename; if (slot > 0) { - filename = emuInstance->getSavestateName(slot); + filename = QString::fromStdString(emuInstance->getSavestateName(slot)); } else { // TODO: specific 'last directory' for savestate files? - QString qfilename = QFileDialog::getSaveFileName(this, + filename = QFileDialog::getSaveFileName(this, "Save state", globalCfg.GetQString("LastROMFolder"), "melonDS savestates (*.mln);;Any file (*.*)"); - if (qfilename.isEmpty()) - { - emuThread->emuUnpause(); + if (filename.isEmpty()) return; - } - - filename = qfilename.toStdString(); } - if (emuInstance->saveState(filename)) + if (emuThread->saveState(filename)) { if (slot > 0) emuInstance->osdAddMessage(0, "State saved to slot %d", slot); else emuInstance->osdAddMessage(0, "State saved to file"); @@ -1421,47 +1414,37 @@ void MainWindow::onSaveState() { emuInstance->osdAddMessage(0xFFA0A0, "State save failed"); } - - emuThread->emuUnpause(); } void MainWindow::onLoadState() { int slot = ((QAction*)sender())->data().toInt(); - emuThread->emuPause(); - - std::string filename; + QString filename; if (slot > 0) { - filename = emuInstance->getSavestateName(slot); + filename = QString::fromStdString(emuInstance->getSavestateName(slot)); } else { // TODO: specific 'last directory' for savestate files? - QString qfilename = QFileDialog::getOpenFileName(this, + filename = QFileDialog::getOpenFileName(this, "Load state", globalCfg.GetQString("LastROMFolder"), "melonDS savestates (*.ml*);;Any file (*.*)"); - if (qfilename.isEmpty()) - { - emuThread->emuUnpause(); + if (filename.isEmpty()) return; - } - - filename = qfilename.toStdString(); } - if (!Platform::FileExists(filename)) + if (!Platform::FileExists(filename.toStdString())) { if (slot > 0) emuInstance->osdAddMessage(0xFFA0A0, "State slot %d is empty", slot); else emuInstance->osdAddMessage(0xFFA0A0, "State file does not exist"); - emuThread->emuUnpause(); return; } - if (emuInstance->loadState(filename)) + if (emuThread->loadState(filename)) { if (slot > 0) emuInstance->osdAddMessage(0, "State loaded from slot %d", slot); else emuInstance->osdAddMessage(0, "State loaded from file"); @@ -1472,15 +1455,11 @@ void MainWindow::onLoadState() { emuInstance->osdAddMessage(0xFFA0A0, "State load failed"); } - - emuThread->emuUnpause(); } void MainWindow::onUndoStateLoad() { - emuThread->emuPause(); - emuInstance->undoStateLoad(); - emuThread->emuUnpause(); + emuThread->undoStateLoad(); emuInstance->osdAddMessage(0, "State load undone"); } From 9ebc96d1215260dc10670323bfba82340e86cd90 Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Thu, 24 Oct 2024 19:55:41 +0200 Subject: [PATCH 19/47] vcpkg 2024.10.21 --- .github/workflows/build-macos.yml | 2 +- .github/workflows/build-windows.yml | 2 +- cmake/ConfigureVcpkg.cmake | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index b2dda12d..47e0f685 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -28,7 +28,7 @@ jobs: - name: Set up vcpkg uses: lukka/run-vcpkg@v11 with: - vcpkgGitCommitId: 3508985146f1b1d248c67ead13f8f54be5b4f5da + vcpkgGitCommitId: 10b7a178346f3f0abef60cecd5130e295afd8da4 - name: Build uses: lukka/run-cmake@v10 with: diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 30dbd2a8..c1cb1856 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -27,7 +27,7 @@ jobs: - name: Set up vcpkg uses: lukka/run-vcpkg@v11 with: - vcpkgGitCommitId: 3508985146f1b1d248c67ead13f8f54be5b4f5da + vcpkgGitCommitId: 10b7a178346f3f0abef60cecd5130e295afd8da4 - name: Configure run: cmake --preset=release-mingw-x86_64 - name: Build diff --git a/cmake/ConfigureVcpkg.cmake b/cmake/ConfigureVcpkg.cmake index f8c33fd4..c1eb522d 100644 --- a/cmake/ConfigureVcpkg.cmake +++ b/cmake/ConfigureVcpkg.cmake @@ -9,7 +9,7 @@ if (VCPKG_ROOT STREQUAL "${_DEFAULT_VCPKG_ROOT}") endif() FetchContent_Declare(vcpkg GIT_REPOSITORY "https://github.com/Microsoft/vcpkg.git" - GIT_TAG 2024.08.23 + GIT_TAG 2024.10.21 SOURCE_DIR "${CMAKE_SOURCE_DIR}/vcpkg") FetchContent_MakeAvailable(vcpkg) endif() From a97463b0ac54d6f5cfd10824aa63a3af9c4b9d72 Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Thu, 24 Oct 2024 21:02:41 +0200 Subject: [PATCH 20/47] nix: update inputs --- flake.lock | 12 ++++++------ flake.nix | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 9f0fe239..be75f57f 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1725432240, - "narHash": "sha256-+yj+xgsfZaErbfYM3T+QvEE2hU7UuE+Jf0fJCJ8uPS0=", + "lastModified": 1729665710, + "narHash": "sha256-AlcmCXJZPIlO5dmFzV3V2XF6x/OpNWUV8Y/FMPGd8Z4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ad416d066ca1222956472ab7d0555a6946746a80", + "rev": "2768c7d042a37de65bb1b5b3268fc987e534c49d", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 8236ccd3..4b5cd397 100644 --- a/flake.nix +++ b/flake.nix @@ -16,7 +16,7 @@ then sourceInfo.dirtyShortRev else sourceInfo.shortRev; - melonDS = pkgs.stdenv.mkDerivation { + melonDS = pkgs.qt6.qtbase.stdenv.mkDerivation { pname = "melonDS"; version = "0.9.5-${versionSuffix}"; src = ./.; From 287f6642fc78ca84f0e37e70c8c736a662d4884f Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Thu, 24 Oct 2024 22:05:30 +0200 Subject: [PATCH 21/47] Add an About dialog with build info (#2138) add About dialog --- .github/workflows/build-macos.yml | 6 + .github/workflows/build-ubuntu.yml | 10 +- .github/workflows/build-windows.yml | 7 +- flake.nix | 12 +- src/CMakeLists.txt | 11 + src/frontend/qt_sdl/AboutDialog.cpp | 58 ++++++ src/frontend/qt_sdl/AboutDialog.h | 50 +++++ src/frontend/qt_sdl/AboutDialog.ui | 300 ++++++++++++++++++++++++++++ src/frontend/qt_sdl/CMakeLists.txt | 3 + src/frontend/qt_sdl/Window.cpp | 10 + src/frontend/qt_sdl/Window.h | 2 + src/version.h.in | 6 + 12 files changed, 470 insertions(+), 5 deletions(-) create mode 100644 src/frontend/qt_sdl/AboutDialog.cpp create mode 100644 src/frontend/qt_sdl/AboutDialog.h create mode 100644 src/frontend/qt_sdl/AboutDialog.ui diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 47e0f685..f47b3a4a 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -9,6 +9,11 @@ on: branches: - master +env: + MELONDS_GIT_BRANCH: ${{ github.ref }} + MELONDS_GIT_HASH: ${{ github.sha }} + MELONDS_BUILD_PROVIDER: GitHub Actions + jobs: build-macos: strategy: @@ -34,6 +39,7 @@ jobs: with: configurePreset: release-mac-${{ matrix.arch }} buildPreset: release-mac-${{ matrix.arch }} + configurePresetAdditionalArgs: "['-DMELONDS_EMBED_BUILD_INFO=ON']" - name: Compress app bundle shell: bash run: | diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index 1bcf2f66..044d01ee 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -8,6 +8,11 @@ on: branches: - master +env: + MELONDS_GIT_BRANCH: ${{ github.ref }} + MELONDS_GIT_HASH: ${{ github.sha }} + MELONDS_BUILD_PROVIDER: GitHub Actions + jobs: build-x86_64: name: x86_64 @@ -23,7 +28,7 @@ jobs: sudo apt install --allow-downgrades cmake ninja-build extra-cmake-modules libpcap0.8-dev libsdl2-dev libenet-dev \ qt6-{base,base-private,multimedia}-dev libqt6svg6-dev libarchive-dev libzstd-dev libfuse2 - name: Configure - run: cmake -B build -G Ninja -DUSE_QT6=ON -DCMAKE_INSTALL_PREFIX=/usr + run: cmake -B build -G Ninja -DUSE_QT6=ON -DCMAKE_INSTALL_PREFIX=/usr -DMELONDS_EMBED_BUILD_INFO=ON - name: Build run: | cmake --build build @@ -74,7 +79,8 @@ jobs: -DPKG_CONFIG_EXECUTABLE=/usr/bin/aarch64-linux-gnu-pkg-config \ -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc-12 \ -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++-12 \ - -DUSE_QT6=ON + -DUSE_QT6=ON \ + -DMELONDS_EMBED_BUILD_INFO=ON - name: Build shell: bash run: | diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index c1cb1856..c3350b4d 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -9,6 +9,11 @@ on: branches: - master +env: + MELONDS_GIT_BRANCH: ${{ github.ref }} + MELONDS_GIT_HASH: ${{ github.sha }} + MELONDS_BUILD_PROVIDER: GitHub Actions + jobs: build: runs-on: windows-latest @@ -29,7 +34,7 @@ jobs: with: vcpkgGitCommitId: 10b7a178346f3f0abef60cecd5130e295afd8da4 - name: Configure - run: cmake --preset=release-mingw-x86_64 + run: cmake --preset=release-mingw-x86_64 -DMELONDS_EMBED_BUILD_INFO=ON - name: Build run: cmake --build --preset=release-mingw-x86_64 - uses: actions/upload-artifact@v4 diff --git a/flake.nix b/flake.nix index 4b5cd397..e898674a 100644 --- a/flake.nix +++ b/flake.nix @@ -12,13 +12,16 @@ inherit (pkgs.lib) cmakeBool optionals makeLibraryPath; inherit (pkgs.stdenv) isLinux isDarwin; - versionSuffix = with self; if sourceInfo?dirtyShortRev + revision = with self; if sourceInfo?dirtyRev + then sourceInfo.dirtyRev + else sourceInfo.rev; + shortRevision = with self; if sourceInfo?dirtyShortRev then sourceInfo.dirtyShortRev else sourceInfo.shortRev; melonDS = pkgs.qt6.qtbase.stdenv.mkDerivation { pname = "melonDS"; - version = "0.9.5-${versionSuffix}"; + version = "0.9.5-${shortRevision}"; src = ./.; nativeBuildInputs = with pkgs; [ @@ -46,8 +49,13 @@ cmakeFlags = [ (cmakeBool "USE_QT6" true) (cmakeBool "USE_SYSTEM_LIBSLIRP" true) + (cmakeBool "MELONDS_EMBED_BUILD_INFO" true) ]; + env.MELONDS_GIT_HASH = revision; + env.MELONDS_GIT_BRANCH = "(unknown)"; + env.MELONDS_BUILD_PROVIDER = "Nix"; + qtWrapperArgs = optionals isLinux [ "--prefix LD_LIBRARY_PATH : ${makeLibraryPath [ pkgs.libpcap pkgs.wayland ]}" ] ++ optionals isDarwin [ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e177835..1f947d11 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -128,6 +128,17 @@ if (ENABLE_JIT) endif() set(MELONDS_VERSION_SUFFIX "$ENV{MELONDS_VERSION_SUFFIX}" CACHE STRING "Suffix to add to displayed melonDS version") +option(MELONDS_EMBED_BUILD_INFO "Embed detailed build info into the binary" OFF) +set(MELONDS_GIT_BRANCH "$ENV{MELONDS_GIT_BRANCH}" CACHE STRING "The Git branch used for this build") +set(MELONDS_GIT_HASH "$ENV{MELONDS_GIT_HASH}" CACHE STRING "The hash of the Git commit") +set(MELONDS_BUILD_PROVIDER "$ENV{MELONDS_BUILD_PROVIDER}" CACHE STRING "The name of the provider of this build") + +if (MELONDS_EMBED_BUILD_INFO) + target_compile_definitions(core PUBLIC MELONDS_EMBED_BUILD_INFO) + if (NOT MELONDS_GIT_BRANCH OR NOT MELONDS_GIT_HASH OR NOT MELONDS_BUILD_PROVIDER) + message(FATAL_ERROR "When embedding build information, all fields must be filled out. See src/CMakeLists.txt.") + endif() +endif() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version.h.in" "${CMAKE_CURRENT_BINARY_DIR}/version.h") target_sources(core PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/version.h") diff --git a/src/frontend/qt_sdl/AboutDialog.cpp b/src/frontend/qt_sdl/AboutDialog.cpp new file mode 100644 index 00000000..ccf39eaa --- /dev/null +++ b/src/frontend/qt_sdl/AboutDialog.cpp @@ -0,0 +1,58 @@ +/* + Copyright 2016-2023 melonDS team + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include "AboutDialog.h" + +#include + +#include "ui_AboutDialog.h" + +#include "version.h" + +AboutDialog::AboutDialog(QWidget *parent) : + QDialog(parent), ui(new Ui::AboutDialog) +{ + ui->setupUi(this); + + ui->lblVersionInfo->setText("Version " MELONDS_VERSION); +#ifdef MELONDS_EMBED_BUILD_INFO + ui->lblBuildInfo->setText( + "Branch: " MELONDS_GIT_BRANCH "\n" + "Commit: " MELONDS_GIT_HASH "\n" + "Built by: " MELONDS_BUILD_PROVIDER + ); +#else + ui->lblBuildInfo->hide(); +#endif + adjustSize(); +} + +AboutDialog::~AboutDialog() +{ + delete ui; +} + +void AboutDialog::openWebsite() +{ + QDesktopServices::openUrl(QUrl(MELONDS_URL)); +} + +void AboutDialog::openGitHub() +{ + QDesktopServices::openUrl(QUrl("https://github.com/melonDS-emu/melonDS"));; +} diff --git a/src/frontend/qt_sdl/AboutDialog.h b/src/frontend/qt_sdl/AboutDialog.h new file mode 100644 index 00000000..eb328f5b --- /dev/null +++ b/src/frontend/qt_sdl/AboutDialog.h @@ -0,0 +1,50 @@ +/* + Copyright 2016-2023 melonDS team + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef MELONDS_ABOUTDIALOG_H +#define MELONDS_ABOUTDIALOG_H + +#include + + +QT_BEGIN_NAMESPACE +namespace Ui +{ + class AboutDialog; +} +QT_END_NAMESPACE + +class AboutDialog : public QDialog +{ +Q_OBJECT + +public: + explicit AboutDialog(QWidget *parent = nullptr); + + ~AboutDialog() override; + +private slots: + static void openWebsite(); + static void openGitHub(); + +private: + Ui::AboutDialog *ui; +}; + + +#endif //MELONDS_ABOUTDIALOG_H diff --git a/src/frontend/qt_sdl/AboutDialog.ui b/src/frontend/qt_sdl/AboutDialog.ui new file mode 100644 index 00000000..89ca7a36 --- /dev/null +++ b/src/frontend/qt_sdl/AboutDialog.ui @@ -0,0 +1,300 @@ + + + AboutDialog + + + + 0 + 0 + 600 + 304 + + + + + 0 + 0 + + + + + 600 + 0 + + + + About melonDS + + + false + + + + 0 + + + QLayout::SizeConstraint::SetFixedSize + + + 12 + + + + + 24 + + + QLayout::SizeConstraint::SetDefaultConstraint + + + + + true + + + + 0 + 0 + + + + + 128 + 128 + + + + + 128 + 128 + + + + + + + Qt::TextFormat::PlainText + + + :/melon-icon + + + true + + + Qt::AlignmentFlag::AlignCenter + + + 0 + + + 0 + + + + + + + 12 + + + + + true + + + + 32 + + + + melonDS + + + + + + + true + + + [VERSION INFO PLACEHOLDER] + + + Qt::TextFormat::MarkdownText + + + + + + + true + + + By Arisotura, the melonDS team <a href="https://github.com/melonDS-emu/melonDS/graphs/contributors">and contributors</a>. + + + + + + + true + + + [EMBEDDED BUILD INFO PLACEHOLDER] + + + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse + + + + + + + false + + + + 10 + + + + <html><head/><body><p>Licensed under the GNU General Public License v3 or any newer version.</p><p>melonDS is intended only for use with software that you own.</p><p>The Nintendo DS and Nintendo DSi systems are the property of Nintendo.<br />melonDS and the melonDS team are not affiliated with or endorsed by Nintendo.</p></body></html> + + + Qt::TextFormat::RichText + + + false + + + + + + + + + + + 12 + + + 12 + + + + + true + + + Qt::Orientation::Horizontal + + + + 40 + 0 + + + + + + + + true + + + Visit the &website + + + true + + + + + + + true + + + View on &GitHub + + + true + + + + + + + true + + + &Close + + + true + + + + + + + + + + + + + btnClose + clicked() + AboutDialog + accept() + + + 586 + 261 + + + 294 + 154 + + + + + btnOpenGitHub + clicked() + AboutDialog + openGitHub() + + + 449 + 243 + + + 299 + 139 + + + + + btnOpenWebsite + clicked() + AboutDialog + openWebsite() + + + 345 + 245 + + + 96 + 275 + + + + + + openWebsite() + openGitHub() + + diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt index 524fa13d..56f82d89 100644 --- a/src/frontend/qt_sdl/CMakeLists.txt +++ b/src/frontend/qt_sdl/CMakeLists.txt @@ -37,6 +37,9 @@ set(SOURCES_QT_SDL QPathInput.h SaveManager.cpp CameraManager.cpp + AboutDialog.cpp + AboutDialog.h + AboutDialog.ui ArchiveUtil.h ArchiveUtil.cpp diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index cf65fe2c..d87c049d 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -82,6 +82,7 @@ #include "ArchiveUtil.h" #include "CameraManager.h" #include "Window.h" +#include "AboutDialog.h" using namespace melonDS; @@ -645,6 +646,15 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : actAudioSync->setCheckable(true); connect(actAudioSync, &QAction::triggered, this, &MainWindow::onChangeAudioSync); } + { + QMenu* menu = menubar->addMenu("Help"); + actAbout = menu->addAction("About..."); + connect(actAbout, &QAction::triggered, this, [&]{ + auto dialog = AboutDialog(this); + dialog.exec(); + }); + } + setMenuBar(menubar); if (localCfg.GetString("Firmware.Username") == "Arisotura") diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h index 9125f76a..98298c0b 100644 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -329,6 +329,8 @@ public: QAction* actShowOSD; QAction* actLimitFramerate; QAction* actAudioSync; + + QAction* actAbout; }; void ToggleFullscreen(MainWindow* mainWindow); diff --git a/src/version.h.in b/src/version.h.in index 5aed0d49..9b4cd8ce 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -25,5 +25,11 @@ #define MELONDS_VERSION_SUFFIX "${MELONDS_VERSION_SUFFIX}" #define MELONDS_VERSION MELONDS_VERSION_BASE MELONDS_VERSION_SUFFIX +#ifdef MELONDS_EMBED_BUILD_INFO +#define MELONDS_GIT_BRANCH "${MELONDS_GIT_BRANCH}" +#define MELONDS_GIT_HASH "${MELONDS_GIT_HASH}" +#define MELONDS_BUILD_PROVIDER "${MELONDS_BUILD_PROVIDER}" +#endif + #endif // VERSION_H From 8b6628b07094d658b89a9734f959e4994fae85b2 Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Fri, 25 Oct 2024 01:15:59 +0200 Subject: [PATCH 22/47] Work around Qt windows11 theme menu bar padding --- src/frontend/qt_sdl/Window.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index d87c049d..2a694879 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -264,6 +264,13 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : setAcceptDrops(true); setFocusPolicy(Qt::ClickFocus); +#ifdef WIN32 + // The "windows11" theme has pretty massive padding around menubar items, this makes Config and Help not fit in a window at 1x screen sizing + // So let's reduce the padding a bit. + if (QApplication::style()->name() == "windows11") + setStyleSheet("QMenuBar::item { padding: 4px 8px; }"); +#endif + QMenuBar* menubar = new QMenuBar(); { QMenu* menu = menubar->addMenu("File"); From 979f1ed6159af0aae2768dc7c4c2711fa551f946 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Fri, 25 Oct 2024 10:52:47 +0200 Subject: [PATCH 23/47] same shit with Import Savefile --- src/frontend/qt_sdl/EmuThread.cpp | 28 ++++++++++++++++++++++++++++ src/frontend/qt_sdl/EmuThread.h | 4 ++++ src/frontend/qt_sdl/Window.cpp | 27 ++++++--------------------- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index d73cd6ea..589f11e2 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -618,6 +618,26 @@ void EmuThread::handleMessages() emuInstance->undoStateLoad(); msgResult = 1; break; + + case msg_ImportSavefile: + { + msgResult = 0; + auto f = Platform::OpenFile(msg.param.value().toStdString(), Platform::FileMode::Read); + if (!f) break; + + u32 len = FileLength(f); + + std::unique_ptr data = std::make_unique(len); + Platform::FileRewind(f); + Platform::FileRead(data.get(), len, 1, f); + + assert(emuInstance->nds != nullptr); + emuInstance->nds->SetNDSSave(data.get(), len); + + CloseFile(f); + msgResult = 1; + } + break; } msgSemaphore.release(); @@ -771,6 +791,14 @@ int EmuThread::undoStateLoad() return msgResult; } +int EmuThread::importSavefile(const QString& filename) +{ + sendMessage(msg_EmuReset); + sendMessage({.type = msg_ImportSavefile, .param = filename}); + waitMessage(2); + return msgResult; +} + void EmuThread::updateRenderer() { if (videoRenderer != lastVideoRenderer) diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h index 52648520..7a07c42c 100644 --- a/src/frontend/qt_sdl/EmuThread.h +++ b/src/frontend/qt_sdl/EmuThread.h @@ -80,6 +80,8 @@ public: msg_LoadState, msg_SaveState, msg_UndoStateLoad, + + msg_ImportSavefile, }; struct Message @@ -119,6 +121,8 @@ public: int loadState(const QString& filename); int undoStateLoad(); + int importSavefile(const QString& filename); + bool emuIsRunning(); bool emuIsActive(); diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 2a694879..08a9474b 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -1483,23 +1483,17 @@ void MainWindow::onUndoStateLoad() void MainWindow::onImportSavefile() { - emuThread->emuPause(); QString path = QFileDialog::getOpenFileName(this, "Select savefile", globalCfg.GetQString("LastROMFolder"), "Savefiles (*.sav *.bin *.dsv);;Any file (*.*)"); if (path.isEmpty()) - { - emuThread->emuUnpause(); return; - } - Platform::FileHandle* f = Platform::OpenFile(path.toStdString(), Platform::FileMode::Read); - if (!f) + if (!Platform::FileExists(path.toStdString())) { QMessageBox::critical(this, "melonDS", "Could not open the given savefile."); - emuThread->emuUnpause(); return; } @@ -1510,24 +1504,15 @@ void MainWindow::onImportSavefile() "The emulation will be reset and the current savefile overwritten.", QMessageBox::Ok, QMessageBox::Cancel) != QMessageBox::Ok) { - emuThread->emuUnpause(); return; } - - emuInstance->reset(); } - u32 len = FileLength(f); - - std::unique_ptr data = std::make_unique(len); - Platform::FileRewind(f); - Platform::FileRead(data.get(), len, 1, f); - - assert(emuInstance->nds != nullptr); - emuInstance->nds->SetNDSSave(data.get(), len); - - CloseFile(f); - emuThread->emuUnpause(); + if (!emuThread->importSavefile(path)) + { + QMessageBox::critical(this, "melonDS", "Could not import the given savefile."); + return; + } } void MainWindow::onQuit() From fc3c7440d1524409700c775baade73be1d6c0fe0 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Fri, 25 Oct 2024 12:33:04 +0200 Subject: [PATCH 24/47] fix that crash --- src/frontend/qt_sdl/Window.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 08a9474b..47113993 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -1800,6 +1800,7 @@ void MainWindow::onUpdateAudioVolume(int vol, int dsisync) void MainWindow::onUpdateAudioSettings() { + if (!emuThread->emuIsActive()) return; assert(emuInstance->nds != nullptr); int interp = globalCfg.GetInt("Audio.Interpolation"); From 1d284f6f1e0afc61431c639b7fafc892d4fffc64 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Fri, 25 Oct 2024 16:16:23 +0200 Subject: [PATCH 25/47] as promised, reroute dropEvent() through EmuThread --- src/frontend/qt_sdl/Window.cpp | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 47113993..7c6c0c4c 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -920,20 +920,12 @@ void MainWindow::dropEvent(QDropEvent* event) QList urls = event->mimeData()->urls(); if (urls.count() > 1) return; // not handling more than one file at once - emuThread->emuPause(); - if (!verifySetup()) - { - emuThread->emuUnpause(); return; - } const QStringList file = splitArchivePath(urls.at(0).toLocalFile(), false); if (file.isEmpty()) - { - emuThread->emuUnpause(); return; - } const QString filename = file.last(); const bool romInsideArchive = file.size() > 1; @@ -947,9 +939,8 @@ void MainWindow::dropEvent(QDropEvent* event) if (isNdsRom) { - if (!emuInstance->loadROM(file, true)) + if (!emuThread->bootROM(file)) { - emuThread->emuUnpause(); return; } @@ -958,28 +949,20 @@ void MainWindow::dropEvent(QDropEvent* event) recentFileList.prepend(barredFilename); updateRecentFilesMenu(); - assert(emuInstance->nds != nullptr); - emuInstance->nds->Start(); - emuThread->emuRun(); - updateCartInserted(false); } else if (isGbaRom) { - if (!emuInstance->loadGBAROM(file)) + if (!emuThread->insertCart(file, true)) { - emuThread->emuUnpause(); return; } - emuThread->emuUnpause(); - updateCartInserted(true); } else { QMessageBox::critical(this, "melonDS", "The file could not be recognized as a DS or GBA ROM."); - emuThread->emuUnpause(); return; } } From f375099613e73c69b169d2ef504705c1fbb3c023 Mon Sep 17 00:00:00 2001 From: Citrodata <39993466+Citrodata@users.noreply.github.com> Date: Sat, 26 Oct 2024 23:03:36 +0200 Subject: [PATCH 26/47] Update EmuThread.h (#2171) * Update EmuThread.h Add missing include QVariant. This fixes and error when building on Arch. * Update AboutDialog.cpp --- src/frontend/qt_sdl/AboutDialog.cpp | 1 + src/frontend/qt_sdl/EmuThread.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/frontend/qt_sdl/AboutDialog.cpp b/src/frontend/qt_sdl/AboutDialog.cpp index ccf39eaa..22022de9 100644 --- a/src/frontend/qt_sdl/AboutDialog.cpp +++ b/src/frontend/qt_sdl/AboutDialog.cpp @@ -19,6 +19,7 @@ #include "AboutDialog.h" #include +#include #include "ui_AboutDialog.h" diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h index 7a07c42c..c53740c8 100644 --- a/src/frontend/qt_sdl/EmuThread.h +++ b/src/frontend/qt_sdl/EmuThread.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include From 881a740cabbbc5b3e877572de474df03d9dc4dd5 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 01:14:29 +0200 Subject: [PATCH 27/47] start actually implementing multi-window feature, still rough around the edges fix crash when closing main window if sub windows are involved fix OpenGL context handling, still need to fix when changing display type --- src/frontend/qt_sdl/EmuInstance.cpp | 35 +++++++++++++---------------- src/frontend/qt_sdl/EmuInstance.h | 4 ++-- src/frontend/qt_sdl/EmuThread.cpp | 14 ++++++------ src/frontend/qt_sdl/EmuThread.h | 4 ++-- src/frontend/qt_sdl/Screen.cpp | 6 +++++ src/frontend/qt_sdl/Screen.h | 1 + src/frontend/qt_sdl/Window.cpp | 16 +++++++++++-- src/frontend/qt_sdl/Window.h | 2 ++ 8 files changed, 49 insertions(+), 33 deletions(-) diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index 402af56b..09f6a2bc 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -199,6 +199,10 @@ void EmuInstance::createWindow() numWindows++; emuThread->attachWindow(win); + + // if creating a secondary window, we may need to initialize its OpenGL context here + if (win->hasOpenGL() && (win != topWindow)) + emuThread->initContext(id); } void EmuInstance::deleteWindow(int id, bool close) @@ -208,12 +212,8 @@ void EmuInstance::deleteWindow(int id, bool close) MainWindow* win = windowList[id]; if (!win) return; - if (win->hasOpenGL() && win == mainWindow) - { - // we intentionally don't unpause here - emuThread->emuPause(); - emuThread->deinitContext(); - } + if (win->hasOpenGL()) + emuThread->deinitContext(id); emuThread->detachWindow(win); @@ -226,9 +226,10 @@ void EmuInstance::deleteWindow(int id, bool close) if (close) win->close(); - if ((!mainWindow) && (!deleting)) + if (numWindows == 0) { - // if we closed this instance's main window, delete the instance + // if we closed the last window, delete the instance + // if the main window is closed, Qt will take care of closing any secondary windows deleteEmuInstance(instanceID); } } @@ -292,24 +293,18 @@ bool EmuInstance::usesOpenGL() (globalCfg.GetInt("3D.Renderer") != renderer3D_Software); } -void EmuInstance::initOpenGL() +void EmuInstance::initOpenGL(int win) { - for (int i = 0; i < kMaxWindows; i++) - { - if (windowList[i]) - windowList[i]->initOpenGL(); - } + if (windowList[win]) + windowList[win]->initOpenGL(); setVSyncGL(true); } -void EmuInstance::deinitOpenGL() +void EmuInstance::deinitOpenGL(int win) { - for (int i = 0; i < kMaxWindows; i++) - { - if (windowList[i]) - windowList[i]->deinitOpenGL(); - } + if (windowList[win]) + windowList[win]->deinitOpenGL(); } void EmuInstance::setVSyncGL(bool vsync) diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index 742bebba..8022867a 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -103,8 +103,8 @@ public: void emuStop(melonDS::Platform::StopReason reason); bool usesOpenGL(); - void initOpenGL(); - void deinitOpenGL(); + void initOpenGL(int win); + void deinitOpenGL(int win); void setVSyncGL(bool vsync); void makeCurrentGL(); void drawScreenGL(); diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 589f11e2..da28365c 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -115,7 +115,7 @@ void EmuThread::run() if (emuInstance->usesOpenGL()) { - emuInstance->initOpenGL(); + emuInstance->initOpenGL(0); useOpenGL = true; videoRenderer = globalCfg.GetInt("3D.Renderer"); @@ -547,12 +547,12 @@ void EmuThread::handleMessages() break; case msg_InitGL: - emuInstance->initOpenGL(); + emuInstance->initOpenGL(msg.param.value()); useOpenGL = true; break; case msg_DeInitGL: - emuInstance->deinitOpenGL(); + emuInstance->deinitOpenGL(msg.param.value()); useOpenGL = false; break; @@ -650,15 +650,15 @@ void EmuThread::changeWindowTitle(char* title) emit windowTitleChange(QString(title)); } -void EmuThread::initContext() +void EmuThread::initContext(int win) { - sendMessage(msg_InitGL); + sendMessage({.type = msg_InitGL, .param = win}); waitMessage(); } -void EmuThread::deinitContext() +void EmuThread::deinitContext(int win) { - sendMessage(msg_DeInitGL); + sendMessage({.type = msg_DeInitGL, .param = win}); waitMessage(); } diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h index c53740c8..57f389af 100644 --- a/src/frontend/qt_sdl/EmuThread.h +++ b/src/frontend/qt_sdl/EmuThread.h @@ -127,8 +127,8 @@ public: bool emuIsRunning(); bool emuIsActive(); - void initContext(); - void deinitContext(); + void initContext(int win); + void deinitContext(int win); void updateVideoSettings() { videoSettingsDirty = true; } void updateVideoRenderer() { videoSettingsDirty = true; lastVideoRenderer = -1; } diff --git a/src/frontend/qt_sdl/Screen.cpp b/src/frontend/qt_sdl/Screen.cpp index 3780de55..11a6150a 100644 --- a/src/frontend/qt_sdl/Screen.cpp +++ b/src/frontend/qt_sdl/Screen.cpp @@ -736,6 +736,8 @@ ScreenPanelGL::ScreenPanelGL(QWidget* parent) : ScreenPanel(parent) setAttribute(Qt::WA_KeyCompression, false); setFocusPolicy(Qt::StrongFocus); setMinimumSize(screenGetMinSize()); + + glInited = false; } ScreenPanelGL::~ScreenPanelGL() @@ -781,6 +783,7 @@ void ScreenPanelGL::setSwapInterval(int intv) void ScreenPanelGL::initOpenGL() { if (!glContext) return; + if (glInited) return; glContext->MakeCurrent(); @@ -877,11 +880,13 @@ void ScreenPanelGL::initOpenGL() glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0)); transferLayout(); + glInited = true; } void ScreenPanelGL::deinitOpenGL() { if (!glContext) return; + if (!glInited) return; glDeleteTextures(1, &screenTexture); @@ -906,6 +911,7 @@ void ScreenPanelGL::deinitOpenGL() glContext->DoneCurrent(); lastScreenWidth = lastScreenHeight = -1; + glInited = false; } void ScreenPanelGL::makeCurrentGL() diff --git a/src/frontend/qt_sdl/Screen.h b/src/frontend/qt_sdl/Screen.h index f3662d8d..c17626bd 100644 --- a/src/frontend/qt_sdl/Screen.h +++ b/src/frontend/qt_sdl/Screen.h @@ -197,6 +197,7 @@ private: void setupScreenLayout() override; std::unique_ptr glContext; + bool glInited; GLuint screenVertexBuffer, screenVertexArray; GLuint screenTexture; diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 7c6c0c4c..19c59673 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -588,6 +588,13 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : } } + menu->addSeparator(); + + actNewWindow = menu->addAction("Open new window"); + connect(actNewWindow, &QAction::triggered, this, &MainWindow::onOpenNewWindow); + + menu->addSeparator(); + actScreenFiltering = menu->addAction("Screen filtering"); actScreenFiltering->setCheckable(true); connect(actScreenFiltering, &QAction::triggered, this, &MainWindow::onChangeScreenFiltering); @@ -1950,6 +1957,11 @@ void MainWindow::onChangeIntegerScaling(bool checked) emit screenLayoutChange(); } +void MainWindow::onOpenNewWindow() +{ + emuInstance->createWindow(); +} + void MainWindow::onChangeScreenFiltering(bool checked) { windowCfg.SetBool("ScreenFilter", checked); @@ -2077,7 +2089,7 @@ void MainWindow::onUpdateVideoSettings(bool glchange) if (glchange) { emuThread->emuPause(); - if (hasOGL) emuThread->deinitContext(); + if (hasOGL) emuThread->deinitContext(windowID); delete panel; createScreenPanel(); @@ -2088,7 +2100,7 @@ void MainWindow::onUpdateVideoSettings(bool glchange) if (glchange) { - if (hasOGL) emuThread->initContext(); + if (hasOGL) emuThread->initContext(windowID); emuThread->emuUnpause(); } } diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h index 98298c0b..b1391911 100644 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -208,6 +208,7 @@ private slots: void onChangeScreenSizing(QAction* act); void onChangeScreenAspect(QAction* act); void onChangeIntegerScaling(bool checked); + void onOpenNewWindow(); void onChangeScreenFiltering(bool checked); void onChangeShowOSD(bool checked); void onChangeLimitFramerate(bool checked); @@ -325,6 +326,7 @@ public: QAction** actScreenAspectTop; QActionGroup* grpScreenAspectBot; QAction** actScreenAspectBot; + QAction* actNewWindow; QAction* actScreenFiltering; QAction* actShowOSD; QAction* actLimitFramerate; From b2ae4c7dc5490d0e8e2be589b781704487855e77 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 02:07:33 +0200 Subject: [PATCH 28/47] lay base for a window with no menubar --- src/frontend/qt_sdl/EmuThread.cpp | 16 +- src/frontend/qt_sdl/Window.cpp | 889 +++++++++++++++--------------- src/frontend/qt_sdl/Window.h | 8 +- src/frontend/qt_sdl/main.cpp | 2 +- 4 files changed, 478 insertions(+), 437 deletions(-) diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index da28365c..07e03e0f 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -76,11 +76,15 @@ void EmuThread::attachWindow(MainWindow* window) connect(this, SIGNAL(windowEmuStop()), window, SLOT(onEmuStop())); connect(this, SIGNAL(windowEmuPause(bool)), window, SLOT(onEmuPause(bool))); connect(this, SIGNAL(windowEmuReset()), window, SLOT(onEmuReset())); - connect(this, SIGNAL(windowLimitFPSChange()), window->actLimitFramerate, SLOT(trigger())); connect(this, SIGNAL(autoScreenSizingChange(int)), window->panel, SLOT(onAutoScreenSizingChanged(int))); connect(this, SIGNAL(windowFullscreenToggle()), window, SLOT(onFullscreenToggled())); - connect(this, SIGNAL(swapScreensToggle()), window->actScreenSwap, SLOT(trigger())); connect(this, SIGNAL(screenEmphasisToggle()), window, SLOT(onScreenEmphasisToggled())); + + if (window->winHasMenu()) + { + connect(this, SIGNAL(windowLimitFPSChange()), window->actLimitFramerate, SLOT(trigger())); + connect(this, SIGNAL(swapScreensToggle()), window->actScreenSwap, SLOT(trigger())); + } } void EmuThread::detachWindow(MainWindow* window) @@ -91,11 +95,15 @@ void EmuThread::detachWindow(MainWindow* window) disconnect(this, SIGNAL(windowEmuStop()), window, SLOT(onEmuStop())); disconnect(this, SIGNAL(windowEmuPause(bool)), window, SLOT(onEmuPause(bool))); disconnect(this, SIGNAL(windowEmuReset()), window, SLOT(onEmuReset())); - disconnect(this, SIGNAL(windowLimitFPSChange()), window->actLimitFramerate, SLOT(trigger())); disconnect(this, SIGNAL(autoScreenSizingChange(int)), window->panel, SLOT(onAutoScreenSizingChanged(int))); disconnect(this, SIGNAL(windowFullscreenToggle()), window, SLOT(onFullscreenToggled())); - disconnect(this, SIGNAL(swapScreensToggle()), window->actScreenSwap, SLOT(trigger())); disconnect(this, SIGNAL(screenEmphasisToggle()), window, SLOT(onScreenEmphasisToggled())); + + if (window->winHasMenu()) + { + disconnect(this, SIGNAL(windowLimitFPSChange()), window->actLimitFramerate, SLOT(trigger())); + disconnect(this, SIGNAL(swapScreensToggle()), window->actScreenSwap, SLOT(trigger())); + } } void EmuThread::run() diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 19c59673..4a5fa439 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -271,408 +271,416 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : setStyleSheet("QMenuBar::item { padding: 4px 8px; }"); #endif - QMenuBar* menubar = new QMenuBar(); + hasMenu = (!parent); + + if (hasMenu) { - QMenu* menu = menubar->addMenu("File"); - - actOpenROM = menu->addAction("Open ROM..."); - connect(actOpenROM, &QAction::triggered, this, &MainWindow::onOpenFile); - actOpenROM->setShortcut(QKeySequence(QKeySequence::StandardKey::Open)); - - /*actOpenROMArchive = menu->addAction("Open ROM inside archive..."); - connect(actOpenROMArchive, &QAction::triggered, this, &MainWindow::onOpenFileArchive); - actOpenROMArchive->setShortcut(QKeySequence(Qt::Key_O | Qt::CTRL | Qt::SHIFT));*/ - - recentMenu = menu->addMenu("Open recent"); - Config::Array recentROMs = globalCfg.GetArray("RecentROM"); - int numrecent = std::min(kMaxRecentROMs, (int)recentROMs.Size()); - for (int i = 0; i < numrecent; ++i) + QMenuBar * menubar = new QMenuBar(); { - std::string item = recentROMs.GetString(i); - if (!item.empty()) - recentFileList.push_back(QString::fromStdString(item)); - } - updateRecentFilesMenu(); + QMenu * menu = menubar->addMenu("File"); - //actBootFirmware = menu->addAction("Launch DS menu"); - actBootFirmware = menu->addAction("Boot firmware"); - connect(actBootFirmware, &QAction::triggered, this, &MainWindow::onBootFirmware); + actOpenROM = menu->addAction("Open ROM..."); + connect(actOpenROM, &QAction::triggered, this, &MainWindow::onOpenFile); + actOpenROM->setShortcut(QKeySequence(QKeySequence::StandardKey::Open)); - menu->addSeparator(); + /*actOpenROMArchive = menu->addAction("Open ROM inside archive..."); + connect(actOpenROMArchive, &QAction::triggered, this, &MainWindow::onOpenFileArchive); + actOpenROMArchive->setShortcut(QKeySequence(Qt::Key_O | Qt::CTRL | Qt::SHIFT));*/ - actCurrentCart = menu->addAction("DS slot: " + emuInstance->cartLabel()); - actCurrentCart->setEnabled(false); - - actInsertCart = menu->addAction("Insert cart..."); - connect(actInsertCart, &QAction::triggered, this, &MainWindow::onInsertCart); - - actEjectCart = menu->addAction("Eject cart"); - connect(actEjectCart, &QAction::triggered, this, &MainWindow::onEjectCart); - - menu->addSeparator(); - - actCurrentGBACart = menu->addAction("GBA slot: " + emuInstance->gbaCartLabel()); - actCurrentGBACart->setEnabled(false); - - actInsertGBACart = menu->addAction("Insert ROM cart..."); - connect(actInsertGBACart, &QAction::triggered, this, &MainWindow::onInsertGBACart); - - { - QMenu* submenu = menu->addMenu("Insert add-on cart"); - QAction* act; - - int addons[] = {GBAAddon_RAMExpansion, GBAAddon_RumblePak, -1}; - for (int i = 0; addons[i] != -1; i++) + recentMenu = menu->addMenu("Open recent"); + Config::Array recentROMs = globalCfg.GetArray("RecentROM"); + int numrecent = std::min(kMaxRecentROMs, (int) recentROMs.Size()); + for (int i = 0; i < numrecent; ++i) { - int addon = addons[i]; - act = submenu->addAction(emuInstance->gbaAddonName(addon)); - act->setData(QVariant(addon)); - connect(act, &QAction::triggered, this, &MainWindow::onInsertGBAAddon); - actInsertGBAAddon.append(act); + std::string item = recentROMs.GetString(i); + if (!item.empty()) + recentFileList.push_back(QString::fromStdString(item)); } - } + updateRecentFilesMenu(); - actEjectGBACart = menu->addAction("Eject cart"); - connect(actEjectGBACart, &QAction::triggered, this, &MainWindow::onEjectGBACart); - - menu->addSeparator(); - - actImportSavefile = menu->addAction("Import savefile"); - connect(actImportSavefile, &QAction::triggered, this, &MainWindow::onImportSavefile); - - menu->addSeparator(); - - { - QMenu* submenu = menu->addMenu("Save state"); - - for (int i = 1; i < 9; i++) - { - actSaveState[i] = submenu->addAction(QString("%1").arg(i)); - actSaveState[i]->setShortcut(QKeySequence(Qt::ShiftModifier | (Qt::Key_F1+i-1))); - actSaveState[i]->setData(QVariant(i)); - connect(actSaveState[i], &QAction::triggered, this, &MainWindow::onSaveState); - } - - actSaveState[0] = submenu->addAction("File..."); - actSaveState[0]->setShortcut(QKeySequence(Qt::ShiftModifier | Qt::Key_F9)); - actSaveState[0]->setData(QVariant(0)); - connect(actSaveState[0], &QAction::triggered, this, &MainWindow::onSaveState); - } - { - QMenu* submenu = menu->addMenu("Load state"); - - for (int i = 1; i < 9; i++) - { - actLoadState[i] = submenu->addAction(QString("%1").arg(i)); - actLoadState[i]->setShortcut(QKeySequence(Qt::Key_F1+i-1)); - actLoadState[i]->setData(QVariant(i)); - connect(actLoadState[i], &QAction::triggered, this, &MainWindow::onLoadState); - } - - actLoadState[0] = submenu->addAction("File..."); - actLoadState[0]->setShortcut(QKeySequence(Qt::Key_F9)); - actLoadState[0]->setData(QVariant(0)); - connect(actLoadState[0], &QAction::triggered, this, &MainWindow::onLoadState); - } - - actUndoStateLoad = menu->addAction("Undo state load"); - actUndoStateLoad->setShortcut(QKeySequence(Qt::Key_F12)); - connect(actUndoStateLoad, &QAction::triggered, this, &MainWindow::onUndoStateLoad); - - menu->addSeparator(); - actOpenConfig = menu->addAction("Open melonDS directory"); - connect(actOpenConfig, &QAction::triggered, this, [&]() { - QDesktopServices::openUrl(QUrl::fromLocalFile(emuDirectory)); - }); - - menu->addSeparator(); - - actQuit = menu->addAction("Quit"); - connect(actQuit, &QAction::triggered, this, &MainWindow::onQuit); - actQuit->setShortcut(QKeySequence(QKeySequence::StandardKey::Quit)); - } - { - QMenu* menu = menubar->addMenu("System"); - - actPause = menu->addAction("Pause"); - actPause->setCheckable(true); - connect(actPause, &QAction::triggered, this, &MainWindow::onPause); - - actReset = menu->addAction("Reset"); - connect(actReset, &QAction::triggered, this, &MainWindow::onReset); - - actStop = menu->addAction("Stop"); - connect(actStop, &QAction::triggered, this, &MainWindow::onStop); - - actFrameStep = menu->addAction("Frame step"); - connect(actFrameStep, &QAction::triggered, this, &MainWindow::onFrameStep); - - menu->addSeparator(); - - actPowerManagement = menu->addAction("Power management"); - connect(actPowerManagement, &QAction::triggered, this, &MainWindow::onOpenPowerManagement); - - actDateTime = menu->addAction("Date and time"); - connect(actDateTime, &QAction::triggered, this, &MainWindow::onOpenDateTime); - - menu->addSeparator(); - - actEnableCheats = menu->addAction("Enable cheats"); - actEnableCheats->setCheckable(true); - connect(actEnableCheats, &QAction::triggered, this, &MainWindow::onEnableCheats); - - //if (inst == 0) - { - actSetupCheats = menu->addAction("Setup cheat codes"); - actSetupCheats->setMenuRole(QAction::NoRole); - connect(actSetupCheats, &QAction::triggered, this, &MainWindow::onSetupCheats); + //actBootFirmware = menu->addAction("Launch DS menu"); + actBootFirmware = menu->addAction("Boot firmware"); + connect(actBootFirmware, &QAction::triggered, this, &MainWindow::onBootFirmware); menu->addSeparator(); - actROMInfo = menu->addAction("ROM info"); - connect(actROMInfo, &QAction::triggered, this, &MainWindow::onROMInfo); - actRAMInfo = menu->addAction("RAM search"); - connect(actRAMInfo, &QAction::triggered, this, &MainWindow::onRAMInfo); + actCurrentCart = menu->addAction("DS slot: " + emuInstance->cartLabel()); + actCurrentCart->setEnabled(false); - actTitleManager = menu->addAction("Manage DSi titles"); - connect(actTitleManager, &QAction::triggered, this, &MainWindow::onOpenTitleManager); - } + actInsertCart = menu->addAction("Insert cart..."); + connect(actInsertCart, &QAction::triggered, this, &MainWindow::onInsertCart); + + actEjectCart = menu->addAction("Eject cart"); + connect(actEjectCart, &QAction::triggered, this, &MainWindow::onEjectCart); - { menu->addSeparator(); - QMenu* submenu = menu->addMenu("Multiplayer"); - actMPNewInstance = submenu->addAction("Launch new instance"); - connect(actMPNewInstance, &QAction::triggered, this, &MainWindow::onMPNewInstance); + actCurrentGBACart = menu->addAction("GBA slot: " + emuInstance->gbaCartLabel()); + actCurrentGBACart->setEnabled(false); - submenu->addSeparator(); + actInsertGBACart = menu->addAction("Insert ROM cart..."); + connect(actInsertGBACart, &QAction::triggered, this, &MainWindow::onInsertGBACart); - actLANStartHost = submenu->addAction("Host LAN game"); - connect(actLANStartHost, &QAction::triggered, this, &MainWindow::onLANStartHost); - - actLANStartClient = submenu->addAction("Join LAN game"); - connect(actLANStartClient, &QAction::triggered, this, &MainWindow::onLANStartClient); - - /*submenu->addSeparator(); - - actNPStartHost = submenu->addAction("NETPLAY HOST"); - connect(actNPStartHost, &QAction::triggered, this, &MainWindow::onNPStartHost); - - actNPStartClient = submenu->addAction("NETPLAY CLIENT"); - connect(actNPStartClient, &QAction::triggered, this, &MainWindow::onNPStartClient); - - actNPTest = submenu->addAction("NETPLAY GO"); - connect(actNPTest, &QAction::triggered, this, &MainWindow::onNPTest);*/ - } - } - { - QMenu *menu = menubar->addMenu("View"); - - { - QMenu* submenu = menu->addMenu("Screen size"); - - for (int i = 0; i < 4; i++) { - int data = i+1; - actScreenSize[i] = submenu->addAction(QString("%1x").arg(data)); - actScreenSize[i]->setData(QVariant(data)); - connect(actScreenSize[i], &QAction::triggered, this, &MainWindow::onChangeScreenSize); - } - } - { - QMenu* submenu = menu->addMenu("Screen rotation"); - grpScreenRotation = new QActionGroup(submenu); + QMenu * submenu = menu->addMenu("Insert add-on cart"); + QAction *act; - for (int i = 0; i < screenRot_MAX; i++) - { - int data = i*90; - actScreenRotation[i] = submenu->addAction(QString("%1°").arg(data)); - actScreenRotation[i]->setActionGroup(grpScreenRotation); - actScreenRotation[i]->setData(QVariant(i)); - actScreenRotation[i]->setCheckable(true); - } - - connect(grpScreenRotation, &QActionGroup::triggered, this, &MainWindow::onChangeScreenRotation); - } - { - QMenu* submenu = menu->addMenu("Screen gap"); - grpScreenGap = new QActionGroup(submenu); - - const int screengap[] = {0, 1, 8, 64, 90, 128}; - - for (int i = 0; i < 6; i++) - { - int data = screengap[i]; - actScreenGap[i] = submenu->addAction(QString("%1 px").arg(data)); - actScreenGap[i]->setActionGroup(grpScreenGap); - actScreenGap[i]->setData(QVariant(data)); - actScreenGap[i]->setCheckable(true); - } - - connect(grpScreenGap, &QActionGroup::triggered, this, &MainWindow::onChangeScreenGap); - } - { - QMenu* submenu = menu->addMenu("Screen layout"); - grpScreenLayout = new QActionGroup(submenu); - - const char* screenlayout[] = {"Natural", "Vertical", "Horizontal", "Hybrid"}; - - for (int i = 0; i < screenLayout_MAX; i++) - { - actScreenLayout[i] = submenu->addAction(QString(screenlayout[i])); - actScreenLayout[i]->setActionGroup(grpScreenLayout); - actScreenLayout[i]->setData(QVariant(i)); - actScreenLayout[i]->setCheckable(true); - } - - connect(grpScreenLayout, &QActionGroup::triggered, this, &MainWindow::onChangeScreenLayout); - - submenu->addSeparator(); - - actScreenSwap = submenu->addAction("Swap screens"); - actScreenSwap->setCheckable(true); - connect(actScreenSwap, &QAction::triggered, this, &MainWindow::onChangeScreenSwap); - } - { - QMenu* submenu = menu->addMenu("Screen sizing"); - grpScreenSizing = new QActionGroup(submenu); - - const char* screensizing[] = {"Even", "Emphasize top", "Emphasize bottom", "Auto", "Top only", "Bottom only"}; - - for (int i = 0; i < screenSizing_MAX; i++) - { - actScreenSizing[i] = submenu->addAction(QString(screensizing[i])); - actScreenSizing[i]->setActionGroup(grpScreenSizing); - actScreenSizing[i]->setData(QVariant(i)); - actScreenSizing[i]->setCheckable(true); - } - - connect(grpScreenSizing, &QActionGroup::triggered, this, &MainWindow::onChangeScreenSizing); - - submenu->addSeparator(); - - actIntegerScaling = submenu->addAction("Force integer scaling"); - actIntegerScaling->setCheckable(true); - connect(actIntegerScaling, &QAction::triggered, this, &MainWindow::onChangeIntegerScaling); - } - { - QMenu* submenu = menu->addMenu("Aspect ratio"); - grpScreenAspectTop = new QActionGroup(submenu); - grpScreenAspectBot = new QActionGroup(submenu); - actScreenAspectTop = new QAction*[AspectRatiosNum]; - actScreenAspectBot = new QAction*[AspectRatiosNum]; - - for (int i = 0; i < 2; i++) - { - QActionGroup* group = grpScreenAspectTop; - QAction** actions = actScreenAspectTop; - - if (i == 1) + int addons[] = {GBAAddon_RAMExpansion, GBAAddon_RumblePak, -1}; + for (int i = 0; addons[i] != -1; i++) { - group = grpScreenAspectBot; - submenu->addSeparator(); - actions = actScreenAspectBot; + int addon = addons[i]; + act = submenu->addAction(emuInstance->gbaAddonName(addon)); + act->setData(QVariant(addon)); + connect(act, &QAction::triggered, this, &MainWindow::onInsertGBAAddon); + actInsertGBAAddon.append(act); + } + } + + actEjectGBACart = menu->addAction("Eject cart"); + connect(actEjectGBACart, &QAction::triggered, this, &MainWindow::onEjectGBACart); + + menu->addSeparator(); + + actImportSavefile = menu->addAction("Import savefile"); + connect(actImportSavefile, &QAction::triggered, this, &MainWindow::onImportSavefile); + + menu->addSeparator(); + + { + QMenu * submenu = menu->addMenu("Save state"); + + for (int i = 1; i < 9; i++) + { + actSaveState[i] = submenu->addAction(QString("%1").arg(i)); + actSaveState[i]->setShortcut(QKeySequence(Qt::ShiftModifier | (Qt::Key_F1 + i - 1))); + actSaveState[i]->setData(QVariant(i)); + connect(actSaveState[i], &QAction::triggered, this, &MainWindow::onSaveState); } - for (int j = 0; j < AspectRatiosNum; j++) + actSaveState[0] = submenu->addAction("File..."); + actSaveState[0]->setShortcut(QKeySequence(Qt::ShiftModifier | Qt::Key_F9)); + actSaveState[0]->setData(QVariant(0)); + connect(actSaveState[0], &QAction::triggered, this, &MainWindow::onSaveState); + } + { + QMenu * submenu = menu->addMenu("Load state"); + + for (int i = 1; i < 9; i++) { - auto ratio = aspectRatios[j]; - QString label = QString("%1 %2").arg(i ? "Bottom" : "Top", ratio.label); - actions[j] = submenu->addAction(label); - actions[j]->setActionGroup(group); - actions[j]->setData(QVariant(ratio.id)); - actions[j]->setCheckable(true); + actLoadState[i] = submenu->addAction(QString("%1").arg(i)); + actLoadState[i]->setShortcut(QKeySequence(Qt::Key_F1 + i - 1)); + actLoadState[i]->setData(QVariant(i)); + connect(actLoadState[i], &QAction::triggered, this, &MainWindow::onLoadState); } - connect(group, &QActionGroup::triggered, this, &MainWindow::onChangeScreenAspect); + actLoadState[0] = submenu->addAction("File..."); + actLoadState[0]->setShortcut(QKeySequence(Qt::Key_F9)); + actLoadState[0]->setData(QVariant(0)); + connect(actLoadState[0], &QAction::triggered, this, &MainWindow::onLoadState); + } + + actUndoStateLoad = menu->addAction("Undo state load"); + actUndoStateLoad->setShortcut(QKeySequence(Qt::Key_F12)); + connect(actUndoStateLoad, &QAction::triggered, this, &MainWindow::onUndoStateLoad); + + menu->addSeparator(); + actOpenConfig = menu->addAction("Open melonDS directory"); + connect(actOpenConfig, &QAction::triggered, this, [&]() + { + QDesktopServices::openUrl(QUrl::fromLocalFile(emuDirectory)); + }); + + menu->addSeparator(); + + actQuit = menu->addAction("Quit"); + connect(actQuit, &QAction::triggered, this, &MainWindow::onQuit); + actQuit->setShortcut(QKeySequence(QKeySequence::StandardKey::Quit)); + } + { + QMenu * menu = menubar->addMenu("System"); + + actPause = menu->addAction("Pause"); + actPause->setCheckable(true); + connect(actPause, &QAction::triggered, this, &MainWindow::onPause); + + actReset = menu->addAction("Reset"); + connect(actReset, &QAction::triggered, this, &MainWindow::onReset); + + actStop = menu->addAction("Stop"); + connect(actStop, &QAction::triggered, this, &MainWindow::onStop); + + actFrameStep = menu->addAction("Frame step"); + connect(actFrameStep, &QAction::triggered, this, &MainWindow::onFrameStep); + + menu->addSeparator(); + + actPowerManagement = menu->addAction("Power management"); + connect(actPowerManagement, &QAction::triggered, this, &MainWindow::onOpenPowerManagement); + + actDateTime = menu->addAction("Date and time"); + connect(actDateTime, &QAction::triggered, this, &MainWindow::onOpenDateTime); + + menu->addSeparator(); + + actEnableCheats = menu->addAction("Enable cheats"); + actEnableCheats->setCheckable(true); + connect(actEnableCheats, &QAction::triggered, this, &MainWindow::onEnableCheats); + + //if (inst == 0) + { + actSetupCheats = menu->addAction("Setup cheat codes"); + actSetupCheats->setMenuRole(QAction::NoRole); + connect(actSetupCheats, &QAction::triggered, this, &MainWindow::onSetupCheats); + + menu->addSeparator(); + actROMInfo = menu->addAction("ROM info"); + connect(actROMInfo, &QAction::triggered, this, &MainWindow::onROMInfo); + + actRAMInfo = menu->addAction("RAM search"); + connect(actRAMInfo, &QAction::triggered, this, &MainWindow::onRAMInfo); + + actTitleManager = menu->addAction("Manage DSi titles"); + connect(actTitleManager, &QAction::triggered, this, &MainWindow::onOpenTitleManager); + } + + { + menu->addSeparator(); + QMenu * submenu = menu->addMenu("Multiplayer"); + + actMPNewInstance = submenu->addAction("Launch new instance"); + connect(actMPNewInstance, &QAction::triggered, this, &MainWindow::onMPNewInstance); + + submenu->addSeparator(); + + actLANStartHost = submenu->addAction("Host LAN game"); + connect(actLANStartHost, &QAction::triggered, this, &MainWindow::onLANStartHost); + + actLANStartClient = submenu->addAction("Join LAN game"); + connect(actLANStartClient, &QAction::triggered, this, &MainWindow::onLANStartClient); + + /*submenu->addSeparator(); + + actNPStartHost = submenu->addAction("NETPLAY HOST"); + connect(actNPStartHost, &QAction::triggered, this, &MainWindow::onNPStartHost); + + actNPStartClient = submenu->addAction("NETPLAY CLIENT"); + connect(actNPStartClient, &QAction::triggered, this, &MainWindow::onNPStartClient); + + actNPTest = submenu->addAction("NETPLAY GO"); + connect(actNPTest, &QAction::triggered, this, &MainWindow::onNPTest);*/ } } + { + QMenu * menu = menubar->addMenu("View"); - menu->addSeparator(); + { + QMenu * submenu = menu->addMenu("Screen size"); - actNewWindow = menu->addAction("Open new window"); - connect(actNewWindow, &QAction::triggered, this, &MainWindow::onOpenNewWindow); + for (int i = 0; i < 4; i++) + { + int data = i + 1; + actScreenSize[i] = submenu->addAction(QString("%1x").arg(data)); + actScreenSize[i]->setData(QVariant(data)); + connect(actScreenSize[i], &QAction::triggered, this, &MainWindow::onChangeScreenSize); + } + } + { + QMenu * submenu = menu->addMenu("Screen rotation"); + grpScreenRotation = new QActionGroup(submenu); - menu->addSeparator(); + for (int i = 0; i < screenRot_MAX; i++) + { + int data = i * 90; + actScreenRotation[i] = submenu->addAction(QString("%1°").arg(data)); + actScreenRotation[i]->setActionGroup(grpScreenRotation); + actScreenRotation[i]->setData(QVariant(i)); + actScreenRotation[i]->setCheckable(true); + } - actScreenFiltering = menu->addAction("Screen filtering"); - actScreenFiltering->setCheckable(true); - connect(actScreenFiltering, &QAction::triggered, this, &MainWindow::onChangeScreenFiltering); + connect(grpScreenRotation, &QActionGroup::triggered, this, &MainWindow::onChangeScreenRotation); + } + { + QMenu * submenu = menu->addMenu("Screen gap"); + grpScreenGap = new QActionGroup(submenu); - actShowOSD = menu->addAction("Show OSD"); - actShowOSD->setCheckable(true); - connect(actShowOSD, &QAction::triggered, this, &MainWindow::onChangeShowOSD); - } - { - QMenu* menu = menubar->addMenu("Config"); + const int screengap[] = {0, 1, 8, 64, 90, 128}; - actEmuSettings = menu->addAction("Emu settings"); - connect(actEmuSettings, &QAction::triggered, this, &MainWindow::onOpenEmuSettings); + for (int i = 0; i < 6; i++) + { + int data = screengap[i]; + actScreenGap[i] = submenu->addAction(QString("%1 px").arg(data)); + actScreenGap[i]->setActionGroup(grpScreenGap); + actScreenGap[i]->setData(QVariant(data)); + actScreenGap[i]->setCheckable(true); + } + + connect(grpScreenGap, &QActionGroup::triggered, this, &MainWindow::onChangeScreenGap); + } + { + QMenu * submenu = menu->addMenu("Screen layout"); + grpScreenLayout = new QActionGroup(submenu); + + const char *screenlayout[] = {"Natural", "Vertical", "Horizontal", "Hybrid"}; + + for (int i = 0; i < screenLayout_MAX; i++) + { + actScreenLayout[i] = submenu->addAction(QString(screenlayout[i])); + actScreenLayout[i]->setActionGroup(grpScreenLayout); + actScreenLayout[i]->setData(QVariant(i)); + actScreenLayout[i]->setCheckable(true); + } + + connect(grpScreenLayout, &QActionGroup::triggered, this, &MainWindow::onChangeScreenLayout); + + submenu->addSeparator(); + + actScreenSwap = submenu->addAction("Swap screens"); + actScreenSwap->setCheckable(true); + connect(actScreenSwap, &QAction::triggered, this, &MainWindow::onChangeScreenSwap); + } + { + QMenu * submenu = menu->addMenu("Screen sizing"); + grpScreenSizing = new QActionGroup(submenu); + + const char *screensizing[] = {"Even", "Emphasize top", "Emphasize bottom", "Auto", "Top only", + "Bottom only"}; + + for (int i = 0; i < screenSizing_MAX; i++) + { + actScreenSizing[i] = submenu->addAction(QString(screensizing[i])); + actScreenSizing[i]->setActionGroup(grpScreenSizing); + actScreenSizing[i]->setData(QVariant(i)); + actScreenSizing[i]->setCheckable(true); + } + + connect(grpScreenSizing, &QActionGroup::triggered, this, &MainWindow::onChangeScreenSizing); + + submenu->addSeparator(); + + actIntegerScaling = submenu->addAction("Force integer scaling"); + actIntegerScaling->setCheckable(true); + connect(actIntegerScaling, &QAction::triggered, this, &MainWindow::onChangeIntegerScaling); + } + { + QMenu * submenu = menu->addMenu("Aspect ratio"); + grpScreenAspectTop = new QActionGroup(submenu); + grpScreenAspectBot = new QActionGroup(submenu); + actScreenAspectTop = new QAction *[AspectRatiosNum]; + actScreenAspectBot = new QAction *[AspectRatiosNum]; + + for (int i = 0; i < 2; i++) + { + QActionGroup * group = grpScreenAspectTop; + QAction **actions = actScreenAspectTop; + + if (i == 1) + { + group = grpScreenAspectBot; + submenu->addSeparator(); + actions = actScreenAspectBot; + } + + for (int j = 0; j < AspectRatiosNum; j++) + { + auto ratio = aspectRatios[j]; + QString label = QString("%1 %2").arg(i ? "Bottom" : "Top", ratio.label); + actions[j] = submenu->addAction(label); + actions[j]->setActionGroup(group); + actions[j]->setData(QVariant(ratio.id)); + actions[j]->setCheckable(true); + } + + connect(group, &QActionGroup::triggered, this, &MainWindow::onChangeScreenAspect); + } + } + + menu->addSeparator(); + + actNewWindow = menu->addAction("Open new window"); + connect(actNewWindow, &QAction::triggered, this, &MainWindow::onOpenNewWindow); + + menu->addSeparator(); + + actScreenFiltering = menu->addAction("Screen filtering"); + actScreenFiltering->setCheckable(true); + connect(actScreenFiltering, &QAction::triggered, this, &MainWindow::onChangeScreenFiltering); + + actShowOSD = menu->addAction("Show OSD"); + actShowOSD->setCheckable(true); + connect(actShowOSD, &QAction::triggered, this, &MainWindow::onChangeShowOSD); + } + { + QMenu * menu = menubar->addMenu("Config"); + + actEmuSettings = menu->addAction("Emu settings"); + connect(actEmuSettings, &QAction::triggered, this, &MainWindow::onOpenEmuSettings); #ifdef __APPLE__ - actPreferences = menu->addAction("Preferences..."); - connect(actPreferences, &QAction::triggered, this, &MainWindow::onOpenEmuSettings); - actPreferences->setMenuRole(QAction::PreferencesRole); + actPreferences = menu->addAction("Preferences..."); + connect(actPreferences, &QAction::triggered, this, &MainWindow::onOpenEmuSettings); + actPreferences->setMenuRole(QAction::PreferencesRole); #endif - actInputConfig = menu->addAction("Input and hotkeys"); - connect(actInputConfig, &QAction::triggered, this, &MainWindow::onOpenInputConfig); + actInputConfig = menu->addAction("Input and hotkeys"); + connect(actInputConfig, &QAction::triggered, this, &MainWindow::onOpenInputConfig); - actVideoSettings = menu->addAction("Video settings"); - connect(actVideoSettings, &QAction::triggered, this, &MainWindow::onOpenVideoSettings); + actVideoSettings = menu->addAction("Video settings"); + connect(actVideoSettings, &QAction::triggered, this, &MainWindow::onOpenVideoSettings); - actCameraSettings = menu->addAction("Camera settings"); - connect(actCameraSettings, &QAction::triggered, this, &MainWindow::onOpenCameraSettings); + actCameraSettings = menu->addAction("Camera settings"); + connect(actCameraSettings, &QAction::triggered, this, &MainWindow::onOpenCameraSettings); - actAudioSettings = menu->addAction("Audio settings"); - connect(actAudioSettings, &QAction::triggered, this, &MainWindow::onOpenAudioSettings); + actAudioSettings = menu->addAction("Audio settings"); + connect(actAudioSettings, &QAction::triggered, this, &MainWindow::onOpenAudioSettings); - actMPSettings = menu->addAction("Multiplayer settings"); - connect(actMPSettings, &QAction::triggered, this, &MainWindow::onOpenMPSettings); + actMPSettings = menu->addAction("Multiplayer settings"); + connect(actMPSettings, &QAction::triggered, this, &MainWindow::onOpenMPSettings); - actWifiSettings = menu->addAction("Wifi settings"); - connect(actWifiSettings, &QAction::triggered, this, &MainWindow::onOpenWifiSettings); + actWifiSettings = menu->addAction("Wifi settings"); + connect(actWifiSettings, &QAction::triggered, this, &MainWindow::onOpenWifiSettings); - actFirmwareSettings = menu->addAction("Firmware settings"); - connect(actFirmwareSettings, &QAction::triggered, this, &MainWindow::onOpenFirmwareSettings); + actFirmwareSettings = menu->addAction("Firmware settings"); + connect(actFirmwareSettings, &QAction::triggered, this, &MainWindow::onOpenFirmwareSettings); - actInterfaceSettings = menu->addAction("Interface settings"); - connect(actInterfaceSettings, &QAction::triggered, this, &MainWindow::onOpenInterfaceSettings); + actInterfaceSettings = menu->addAction("Interface settings"); + connect(actInterfaceSettings, &QAction::triggered, this, &MainWindow::onOpenInterfaceSettings); - actPathSettings = menu->addAction("Path settings"); - connect(actPathSettings, &QAction::triggered, this, &MainWindow::onOpenPathSettings); + actPathSettings = menu->addAction("Path settings"); + connect(actPathSettings, &QAction::triggered, this, &MainWindow::onOpenPathSettings); + { + QMenu * submenu = menu->addMenu("Savestate settings"); + + actSavestateSRAMReloc = submenu->addAction("Separate savefiles"); + actSavestateSRAMReloc->setCheckable(true); + connect(actSavestateSRAMReloc, &QAction::triggered, this, &MainWindow::onChangeSavestateSRAMReloc); + } + + menu->addSeparator(); + + actLimitFramerate = menu->addAction("Limit framerate"); + actLimitFramerate->setCheckable(true); + connect(actLimitFramerate, &QAction::triggered, this, &MainWindow::onChangeLimitFramerate); + + actAudioSync = menu->addAction("Audio sync"); + actAudioSync->setCheckable(true); + connect(actAudioSync, &QAction::triggered, this, &MainWindow::onChangeAudioSync); + } { - QMenu* submenu = menu->addMenu("Savestate settings"); - - actSavestateSRAMReloc = submenu->addAction("Separate savefiles"); - actSavestateSRAMReloc->setCheckable(true); - connect(actSavestateSRAMReloc, &QAction::triggered, this, &MainWindow::onChangeSavestateSRAMReloc); + QMenu * menu = menubar->addMenu("Help"); + actAbout = menu->addAction("About..."); + connect(actAbout, &QAction::triggered, this, [&] + { + auto dialog = AboutDialog(this); + dialog.exec(); + }); } - menu->addSeparator(); + setMenuBar(menubar); - actLimitFramerate = menu->addAction("Limit framerate"); - actLimitFramerate->setCheckable(true); - connect(actLimitFramerate, &QAction::triggered, this, &MainWindow::onChangeLimitFramerate); - - actAudioSync = menu->addAction("Audio sync"); - actAudioSync->setCheckable(true); - connect(actAudioSync, &QAction::triggered, this, &MainWindow::onChangeAudioSync); + if (localCfg.GetString("Firmware.Username") == "Arisotura") + actMPNewInstance->setText("Fart"); } - { - QMenu* menu = menubar->addMenu("Help"); - actAbout = menu->addAction("About..."); - connect(actAbout, &QAction::triggered, this, [&]{ - auto dialog = AboutDialog(this); - dialog.exec(); - }); - } - - setMenuBar(menubar); - - if (localCfg.GetString("Firmware.Username") == "Arisotura") - actMPNewInstance->setText("Fart"); #ifdef Q_OS_MAC QPoint screenCenter = screen()->availableGeometry().center(); @@ -695,87 +703,90 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : createScreenPanel(); - actEjectCart->setEnabled(false); - actEjectGBACart->setEnabled(false); - - if (globalCfg.GetInt("Emu.ConsoleType") == 1) + if (hasMenu) { - actInsertGBACart->setEnabled(false); - for (auto act : actInsertGBAAddon) - act->setEnabled(false); - } + actEjectCart->setEnabled(false); + actEjectGBACart->setEnabled(false); - for (int i = 0; i < 9; i++) - { - actSaveState[i]->setEnabled(false); - actLoadState[i]->setEnabled(false); - } - actUndoStateLoad->setEnabled(false); - actImportSavefile->setEnabled(false); - - actPause->setEnabled(false); - actReset->setEnabled(false); - actStop->setEnabled(false); - actFrameStep->setEnabled(false); - - actDateTime->setEnabled(true); - actPowerManagement->setEnabled(false); - - actSetupCheats->setEnabled(false); - actTitleManager->setEnabled(!globalCfg.GetString("DSi.NANDPath").empty()); - - actEnableCheats->setChecked(localCfg.GetBool("EnableCheats")); - - actROMInfo->setEnabled(false); - actRAMInfo->setEnabled(false); - - actSavestateSRAMReloc->setChecked(globalCfg.GetBool("Savestate.RelocSRAM")); - - actScreenRotation[windowCfg.GetInt("ScreenRotation")]->setChecked(true); - - int screenGap = windowCfg.GetInt("ScreenGap"); - for (int i = 0; i < 6; i++) - { - if (actScreenGap[i]->data().toInt() == screenGap) + if (globalCfg.GetInt("Emu.ConsoleType") == 1) { - actScreenGap[i]->setChecked(true); - break; + actInsertGBACart->setEnabled(false); + for (auto act: actInsertGBAAddon) + act->setEnabled(false); } - } - actScreenLayout[windowCfg.GetInt("ScreenLayout")]->setChecked(true); - actScreenSizing[windowCfg.GetInt("ScreenSizing")]->setChecked(true); - actIntegerScaling->setChecked(windowCfg.GetBool("IntegerScaling")); + for (int i = 0; i < 9; i++) + { + actSaveState[i]->setEnabled(false); + actLoadState[i]->setEnabled(false); + } + actUndoStateLoad->setEnabled(false); + actImportSavefile->setEnabled(false); - actScreenSwap->setChecked(windowCfg.GetBool("ScreenSwap")); + actPause->setEnabled(false); + actReset->setEnabled(false); + actStop->setEnabled(false); + actFrameStep->setEnabled(false); - int aspectTop = windowCfg.GetInt("ScreenAspectTop"); - int aspectBot = windowCfg.GetInt("ScreenAspectBot"); - for (int i = 0; i < AspectRatiosNum; i++) - { - if (aspectTop == aspectRatios[i].id) - actScreenAspectTop[i]->setChecked(true); - if (aspectBot == aspectRatios[i].id) - actScreenAspectBot[i]->setChecked(true); - } + actDateTime->setEnabled(true); + actPowerManagement->setEnabled(false); - actScreenFiltering->setChecked(windowCfg.GetBool("ScreenFilter")); - actShowOSD->setChecked(showOSD); + actSetupCheats->setEnabled(false); + actTitleManager->setEnabled(!globalCfg.GetString("DSi.NANDPath").empty()); - actLimitFramerate->setChecked(emuInstance->doLimitFPS); - actAudioSync->setChecked(emuInstance->doAudioSync); + actEnableCheats->setChecked(localCfg.GetBool("EnableCheats")); - if (emuInstance->instanceID > 0) - { - actEmuSettings->setEnabled(false); - actVideoSettings->setEnabled(false); - actMPSettings->setEnabled(false); - actWifiSettings->setEnabled(false); - actInterfaceSettings->setEnabled(false); + actROMInfo->setEnabled(false); + actRAMInfo->setEnabled(false); + + actSavestateSRAMReloc->setChecked(globalCfg.GetBool("Savestate.RelocSRAM")); + + actScreenRotation[windowCfg.GetInt("ScreenRotation")]->setChecked(true); + + int screenGap = windowCfg.GetInt("ScreenGap"); + for (int i = 0; i < 6; i++) + { + if (actScreenGap[i]->data().toInt() == screenGap) + { + actScreenGap[i]->setChecked(true); + break; + } + } + + actScreenLayout[windowCfg.GetInt("ScreenLayout")]->setChecked(true); + actScreenSizing[windowCfg.GetInt("ScreenSizing")]->setChecked(true); + actIntegerScaling->setChecked(windowCfg.GetBool("IntegerScaling")); + + actScreenSwap->setChecked(windowCfg.GetBool("ScreenSwap")); + + int aspectTop = windowCfg.GetInt("ScreenAspectTop"); + int aspectBot = windowCfg.GetInt("ScreenAspectBot"); + for (int i = 0; i < AspectRatiosNum; i++) + { + if (aspectTop == aspectRatios[i].id) + actScreenAspectTop[i]->setChecked(true); + if (aspectBot == aspectRatios[i].id) + actScreenAspectBot[i]->setChecked(true); + } + + actScreenFiltering->setChecked(windowCfg.GetBool("ScreenFilter")); + actShowOSD->setChecked(showOSD); + + actLimitFramerate->setChecked(emuInstance->doLimitFPS); + actAudioSync->setChecked(emuInstance->doAudioSync); + + if (emuInstance->instanceID > 0) + { + actEmuSettings->setEnabled(false); + actVideoSettings->setEnabled(false); + actMPSettings->setEnabled(false); + actWifiSettings->setEnabled(false); + actInterfaceSettings->setEnabled(false); #ifdef __APPLE__ - actPreferences->setEnabled(false); + actPreferences->setEnabled(false); #endif // __APPLE__ + } } QObject::connect(qApp, &QApplication::applicationStateChanged, this, &MainWindow::onAppStateChanged); @@ -786,8 +797,11 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : MainWindow::~MainWindow() { - delete[] actScreenAspectTop; - delete[] actScreenAspectBot; + if (hasMenu) + { + delete[] actScreenAspectTop; + delete[] actScreenAspectBot; + } } void MainWindow::osdAddMessage(unsigned int color, const char* msg) @@ -834,7 +848,8 @@ void MainWindow::createScreenPanel() } setCentralWidget(panel); - actScreenFiltering->setEnabled(hasOGL); + if (hasMenu) + actScreenFiltering->setEnabled(hasOGL); panel->osdSetEnabled(showOSD); connect(this, SIGNAL(screenLayoutChange()), panel, SLOT(onScreenLayoutChanged())); @@ -1635,6 +1650,8 @@ void MainWindow::onNPTest() void MainWindow::updateMPInterface(MPInterfaceType type) { + if (!hasMenu) return; + // MP interface was changed, reflect it in the UI bool enable = (type == MPInterface_Local); @@ -1995,24 +2012,28 @@ void MainWindow::onTitleUpdate(QString title) setWindowTitle(title); } -void ToggleFullscreen(MainWindow* mainWindow) +void MainWindow::toggleFullscreen() { - if (!mainWindow->isFullScreen()) + if (!isFullScreen()) { - mainWindow->showFullScreen(); - mainWindow->menuBar()->setFixedHeight(0); // Don't use hide() as menubar actions stop working + showFullScreen(); + if (hasMenu) + menuBar()->setFixedHeight(0); // Don't use hide() as menubar actions stop working } else { - mainWindow->showNormal(); - int menuBarHeight = mainWindow->menuBar()->sizeHint().height(); - mainWindow->menuBar()->setFixedHeight(menuBarHeight); + showNormal(); + if (hasMenu) + { + int menuBarHeight = menuBar()->sizeHint().height(); + menuBar()->setFixedHeight(menuBarHeight); + } } } void MainWindow::onFullscreenToggled() { - ToggleFullscreen(this); + toggleFullscreen(); } void MainWindow::onScreenEmphasisToggled() @@ -2033,6 +2054,8 @@ void MainWindow::onScreenEmphasisToggled() void MainWindow::onEmuStart() { + if (!hasMenu) return; + for (int i = 1; i < 9; i++) { actSaveState[i]->setEnabled(true); @@ -2056,6 +2079,8 @@ void MainWindow::onEmuStart() void MainWindow::onEmuStop() { + if (!hasMenu) return; + for (int i = 0; i < 9; i++) { actSaveState[i]->setEnabled(false); @@ -2076,11 +2101,15 @@ void MainWindow::onEmuStop() void MainWindow::onEmuPause(bool pause) { + if (!hasMenu) return; + actPause->setChecked(pause); } void MainWindow::onEmuReset() { + if (!hasMenu) return; + actUndoStateLoad->setEnabled(false); } diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h index b1391911..32ba5dd2 100644 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -111,6 +111,10 @@ public: EmuInstance* getEmuInstance() { return emuInstance; } Config::Table& getWindowConfig() { return windowCfg; } + bool winHasMenu() { return hasMenu; } + + void toggleFullscreen(); + bool hasOpenGL() { return hasOGL; } GL::Context* getOGLContext(); void initOpenGL(); @@ -263,6 +267,8 @@ private: public: ScreenPanel* panel; + bool hasMenu; + QAction* actOpenROM; QAction* actBootFirmware; QAction* actCurrentCart; @@ -335,6 +341,4 @@ public: QAction* actAbout; }; -void ToggleFullscreen(MainWindow* mainWindow); - #endif // WINDOW_H diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 6d18adaf..e63c8a9b 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -364,7 +364,7 @@ int main(int argc, char** argv) win->preloadROMs(dsfile, gbafile, options->boot); if (options->fullscreen) - ToggleFullscreen(win); + win->toggleFullscreen(); } int ret = melon.exec(); From 4ae4397547f7703d6425cecb61df05be673a9258 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 02:42:27 +0200 Subject: [PATCH 29/47] properly update display type across all windows (remind me to also propagate changes across instances) --- src/frontend/qt_sdl/EmuThread.cpp | 4 ++-- src/frontend/qt_sdl/Window.cpp | 24 +++++++++++++++++++++--- src/frontend/qt_sdl/Window.h | 1 + 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 07e03e0f..1bf22c36 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -70,7 +70,7 @@ EmuThread::EmuThread(EmuInstance* inst, QObject* parent) : QThread(parent) void EmuThread::attachWindow(MainWindow* window) { - connect(this, SIGNAL(windowUpdate()), window->panel, SLOT(repaint())); + //connect(this, SIGNAL(windowUpdate()), window->panel, SLOT(repaint())); connect(this, SIGNAL(windowTitleChange(QString)), window, SLOT(onTitleUpdate(QString))); connect(this, SIGNAL(windowEmuStart()), window, SLOT(onEmuStart())); connect(this, SIGNAL(windowEmuStop()), window, SLOT(onEmuStop())); @@ -89,7 +89,7 @@ void EmuThread::attachWindow(MainWindow* window) void EmuThread::detachWindow(MainWindow* window) { - disconnect(this, SIGNAL(windowUpdate()), window->panel, SLOT(repaint())); + //disconnect(this, SIGNAL(windowUpdate()), window->panel, SLOT(repaint())); disconnect(this, SIGNAL(windowTitleChange(QString)), window, SLOT(onTitleUpdate(QString))); disconnect(this, SIGNAL(windowEmuStart()), window, SLOT(onEmuStart())); disconnect(this, SIGNAL(windowEmuStop()), window, SLOT(onEmuStop())); diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 4a5fa439..16e30081 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -701,6 +701,7 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : } show(); + panel = nullptr; createScreenPanel(); if (hasMenu) @@ -827,6 +828,9 @@ void MainWindow::closeEvent(QCloseEvent* event) void MainWindow::createScreenPanel() { + if (panel) delete panel; + panel = nullptr; + hasOGL = globalCfg.GetBool("Screen.UseGL") || (globalCfg.GetInt("3D.Renderer") != renderer3D_Software); @@ -852,6 +856,8 @@ void MainWindow::createScreenPanel() actScreenFiltering->setEnabled(hasOGL); panel->osdSetEnabled(showOSD); + connect(emuThread, SIGNAL(windowUpdate()), panel, SLOT(repaint())); + connect(this, SIGNAL(screenLayoutChange()), panel, SLOT(onScreenLayoutChanged())); emit screenLayoutChange(); } @@ -2115,14 +2121,17 @@ void MainWindow::onEmuReset() void MainWindow::onUpdateVideoSettings(bool glchange) { + MainWindow* parentwin = (MainWindow*)parentWidget(); + if (parentwin) + return parentwin->onUpdateVideoSettings(glchange); + + bool hadOGL = hasOGL; if (glchange) { emuThread->emuPause(); - if (hasOGL) emuThread->deinitContext(windowID); + if (hadOGL) emuThread->deinitContext(windowID); - delete panel; createScreenPanel(); - connect(emuThread, SIGNAL(windowUpdate()), panel, SLOT(repaint())); } emuThread->updateVideoSettings(); @@ -2130,6 +2139,15 @@ void MainWindow::onUpdateVideoSettings(bool glchange) if (glchange) { if (hasOGL) emuThread->initContext(windowID); + + auto childwins = findChildren(Qt::FindDirectChildrenOnly); + for (auto child : childwins) + { + if (hadOGL) emuThread->deinitContext(child->windowID); + child->createScreenPanel(); + if (hasOGL) emuThread->initContext(child->windowID); + } + emuThread->emuUnpause(); } } diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h index 32ba5dd2..17575b53 100644 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -110,6 +110,7 @@ public: EmuInstance* getEmuInstance() { return emuInstance; } Config::Table& getWindowConfig() { return windowCfg; } + int getID() { return windowID; } bool winHasMenu() { return hasMenu; } From 2d561a60c88e42f230dc81e72a61469a90a91c42 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 09:16:46 +0100 Subject: [PATCH 30/47] fix Qt5 compatibility (sdffdf) --- src/frontend/qt_sdl/Window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 16e30081..50472300 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -2140,7 +2140,7 @@ void MainWindow::onUpdateVideoSettings(bool glchange) { if (hasOGL) emuThread->initContext(windowID); - auto childwins = findChildren(Qt::FindDirectChildrenOnly); + auto childwins = findChildren(nullptr, Qt::FindDirectChildrenOnly); for (auto child : childwins) { if (hadOGL) emuThread->deinitContext(child->windowID); From 2bf0eb7eadb3f5ee0ce5b532ecf53cac130d0c86 Mon Sep 17 00:00:00 2001 From: Gess1t <39861216+Mrcubix@users.noreply.github.com> Date: Sun, 27 Oct 2024 09:20:51 +0100 Subject: [PATCH 31/47] Handle failure of OpenGL context creation (#2172) --- src/frontend/qt_sdl/Screen.cpp | 12 ++++-------- src/frontend/qt_sdl/Window.cpp | 10 +++++++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/frontend/qt_sdl/Screen.cpp b/src/frontend/qt_sdl/Screen.cpp index 11a6150a..ff049120 100644 --- a/src/frontend/qt_sdl/Screen.cpp +++ b/src/frontend/qt_sdl/Screen.cpp @@ -753,10 +753,8 @@ bool ScreenPanelGL::createContext() if (parentwin) { if (windowinfo.has_value()) - { - glContext = parentwin->getOGLContext()->CreateSharedContext(*windowinfo); - glContext->DoneCurrent(); - } + if (glContext = parentwin->getOGLContext()->CreateSharedContext(*windowinfo)) + glContext->DoneCurrent(); } else { @@ -764,10 +762,8 @@ bool ScreenPanelGL::createContext() GL::Context::Version{GL::Context::Profile::Core, 4, 3}, GL::Context::Version{GL::Context::Profile::Core, 3, 2}}; if (windowinfo.has_value()) - { - glContext = GL::Context::Create(*windowinfo, versionsToTry); - glContext->DoneCurrent(); - } + if (glContext = GL::Context::Create(*windowinfo, versionsToTry)) + glContext->DoneCurrent(); } return glContext != nullptr; diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 50472300..3ba9ada5 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -841,7 +841,15 @@ void MainWindow::createScreenPanel() panel = panelGL; - panelGL->createContext(); + // Check that creating the context hasn't failed + if (panelGL->createContext() == false) + { + Log(LogLevel::Error, "Failed to create OpenGL context, falling back to Software Renderer.\n"); + hasOGL = false; + + globalCfg.SetBool("Screen.UseGL", false); + globalCfg.SetInt("3D.Renderer", renderer3D_Software); + } } if (!hasOGL) From 24ca1a5fdbd6f8c2a64966b2417eae678ab95c91 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 10:02:57 +0100 Subject: [PATCH 32/47] lay base for keeping config in sync across multiple instances --- src/frontend/qt_sdl/EmuInstance.cpp | 15 +++++++++ src/frontend/qt_sdl/EmuInstance.h | 3 ++ src/frontend/qt_sdl/Window.cpp | 50 ++++++++++++++++++++--------- src/frontend/qt_sdl/Window.h | 2 ++ src/frontend/qt_sdl/main.cpp | 12 +++++++ src/frontend/qt_sdl/main.h | 7 ++++ 6 files changed, 73 insertions(+), 16 deletions(-) diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index 09f6a2bc..7fc73670 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -241,6 +241,21 @@ void EmuInstance::deleteAllWindows() } +void EmuInstance::updateConfigInfo(int kind) +{ + switch (kind) + { + case Config_RecentFiles: + for (int i = 0; i < kMaxWindows; i++) + { + if (windowList[i]) + windowList[i]->loadRecentFilesMenu(true); + } + break; + } +} + + void EmuInstance::osdAddMessage(unsigned int color, const char* fmt, ...) { if (fmt == nullptr) diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index 8022867a..a7ecddf8 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -21,6 +21,7 @@ #include +#include "main.h" #include "NDS.h" #include "EmuThread.h" #include "Window.h" @@ -91,6 +92,8 @@ public: Config::Table& getGlobalConfig() { return globalCfg; } Config::Table& getLocalConfig() { return localCfg; } + void updateConfigInfo(int kind); + std::string instanceFileSuffix(); void createWindow(); diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 3ba9ada5..b44fed7a 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -271,7 +271,8 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : setStyleSheet("QMenuBar::item { padding: 4px 8px; }"); #endif - hasMenu = (!parent); + //hasMenu = (!parent); + hasMenu = true; if (hasMenu) { @@ -288,15 +289,7 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : actOpenROMArchive->setShortcut(QKeySequence(Qt::Key_O | Qt::CTRL | Qt::SHIFT));*/ recentMenu = menu->addMenu("Open recent"); - Config::Array recentROMs = globalCfg.GetArray("RecentROM"); - int numrecent = std::min(kMaxRecentROMs, (int) recentROMs.Size()); - for (int i = 0; i < numrecent; ++i) - { - std::string item = recentROMs.GetString(i); - if (!item.empty()) - recentFileList.push_back(QString::fromStdString(item)); - } - updateRecentFilesMenu(); + loadRecentFilesMenu(true); //actBootFirmware = menu->addAction("Launch DS menu"); actBootFirmware = menu->addAction("Boot firmware"); @@ -1280,12 +1273,23 @@ void MainWindow::onClearRecentFiles() updateRecentFilesMenu(); } -void MainWindow::updateRecentFilesMenu() +void MainWindow::loadRecentFilesMenu(bool loadcfg) { - recentMenu->clear(); + if (loadcfg) + { + recentFileList.clear(); - Config::Array recentroms = globalCfg.GetArray("RecentROM"); - recentroms.Clear(); + Config::Array recentROMs = globalCfg.GetArray("RecentROM"); + int numrecent = std::min(kMaxRecentROMs, (int) recentROMs.Size()); + for (int i = 0; i < numrecent; ++i) + { + std::string item = recentROMs.GetString(i); + if (!item.empty()) + recentFileList.push_back(QString::fromStdString(item)); + } + } + + recentMenu->clear(); for (int i = 0; i < recentFileList.size(); ++i) { @@ -1316,8 +1320,6 @@ void MainWindow::updateRecentFilesMenu() QAction *actRecentFile_i = recentMenu->addAction(QString("%1. %2").arg(i+1).arg(item_display)); actRecentFile_i->setData(item_full); connect(actRecentFile_i, &QAction::triggered, this, &MainWindow::onClickRecentFile); - - recentroms.SetQString(i, recentFileList.at(i)); } while (recentFileList.size() > 10) @@ -1330,8 +1332,24 @@ void MainWindow::updateRecentFilesMenu() if (recentFileList.empty()) actClearRecentList->setEnabled(false); +} + +void MainWindow::updateRecentFilesMenu() +{ + Config::Array recentroms = globalCfg.GetArray("RecentROM"); + recentroms.Clear(); + + for (int i = 0; i < recentFileList.size(); ++i) + { + if (i >= kMaxRecentROMs) break; + + recentroms.SetQString(i, recentFileList.at(i)); + } Config::Save(); + loadRecentFilesMenu(false); + + updateConfigInfoAll(Config_RecentFiles, emuInstance->getInstanceID()); } void MainWindow::onClickRecentFile() diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h index 17575b53..a344c1e3 100644 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -134,6 +134,8 @@ public: // called when the MP interface is changed void updateMPInterface(melonDS::MPInterfaceType type); + void loadRecentFilesMenu(bool loadcfg); + protected: void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index e63c8a9b..a4cc965e 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -168,6 +168,18 @@ int numEmuInstances() } +void updateConfigInfoAll(int kind, int sourceinst) +{ + for (int i = 0; i < kMaxEmuInstances; i++) + { + if (i == sourceinst) continue; + if (!emuInstances[i]) continue; + + emuInstances[i]->updateConfigInfo(kind); + } +} + + void pathInit() { // First, check for the portable directory next to the executable. diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index 77cdf4ee..b247d1fd 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -31,6 +31,11 @@ #include "ScreenLayout.h" #include "MPInterface.h" +enum +{ + Config_RecentFiles, +}; + class MelonApplication : public QApplication { Q_OBJECT @@ -50,6 +55,8 @@ void deleteEmuInstance(int id); void deleteAllEmuInstances(int first = 0); int numEmuInstances(); +void updateConfigInfoAll(int kind, int sourceinst); + void setMPInterface(melonDS::MPInterfaceType type); #endif // MAIN_H From e6f0d77aa00f490875430c95ab30c4157ace5c05 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 10:17:59 +0100 Subject: [PATCH 33/47] fix freeze when starting new emu instance while using OpenGL --- src/frontend/qt_sdl/EmuInstance.cpp | 2 +- src/frontend/qt_sdl/Screen.cpp | 4 +++- src/frontend/qt_sdl/Window.cpp | 24 ++++++++++++++++-------- src/frontend/qt_sdl/Window.h | 2 +- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index 7fc73670..3906b186 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -201,7 +201,7 @@ void EmuInstance::createWindow() emuThread->attachWindow(win); // if creating a secondary window, we may need to initialize its OpenGL context here - if (win->hasOpenGL() && (win != topWindow)) + if (win->hasOpenGL() && (id != 0)) emuThread->initContext(id); } diff --git a/src/frontend/qt_sdl/Screen.cpp b/src/frontend/qt_sdl/Screen.cpp index ff049120..37c35a65 100644 --- a/src/frontend/qt_sdl/Screen.cpp +++ b/src/frontend/qt_sdl/Screen.cpp @@ -749,8 +749,10 @@ bool ScreenPanelGL::createContext() // if our parent window is parented to another window, we will // share our OpenGL context with that window + MainWindow* ourwin = (MainWindow*)parentWidget(); MainWindow* parentwin = (MainWindow*)parentWidget()->parentWidget(); - if (parentwin) + //if (parentwin) + if (ourwin->getWindowID() != 0) { if (windowinfo.has_value()) if (glContext = parentwin->getOGLContext()->CreateSharedContext(*windowinfo)) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index b44fed7a..a231a6f8 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -2147,9 +2147,14 @@ void MainWindow::onEmuReset() void MainWindow::onUpdateVideoSettings(bool glchange) { - MainWindow* parentwin = (MainWindow*)parentWidget(); - if (parentwin) - return parentwin->onUpdateVideoSettings(glchange); + if (windowID != 0) + { + MainWindow* parentwin = (MainWindow*)parentWidget(); + if (parentwin) + parentwin->onUpdateVideoSettings(glchange); + + return; + } bool hadOGL = hasOGL; if (glchange) @@ -2166,12 +2171,15 @@ void MainWindow::onUpdateVideoSettings(bool glchange) { if (hasOGL) emuThread->initContext(windowID); - auto childwins = findChildren(nullptr, Qt::FindDirectChildrenOnly); - for (auto child : childwins) + if (windowID == 0) { - if (hadOGL) emuThread->deinitContext(child->windowID); - child->createScreenPanel(); - if (hasOGL) emuThread->initContext(child->windowID); + auto childwins = findChildren(nullptr, Qt::FindDirectChildrenOnly); + for (auto child: childwins) + { + if (hadOGL) emuThread->deinitContext(child->windowID); + child->createScreenPanel(); + if (hasOGL) emuThread->initContext(child->windowID); + } } emuThread->emuUnpause(); diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h index a344c1e3..73bb84bb 100644 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -110,7 +110,7 @@ public: EmuInstance* getEmuInstance() { return emuInstance; } Config::Table& getWindowConfig() { return windowCfg; } - int getID() { return windowID; } + int getWindowID() { return windowID; } bool winHasMenu() { return hasMenu; } From e576538268ba06e17324df675b549876ea66e849 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 11:21:30 +0100 Subject: [PATCH 34/47] synchronize pause/unpause across all instances --- src/frontend/qt_sdl/EmuInstance.cpp | 19 ++++++++++++++++--- src/frontend/qt_sdl/EmuInstance.h | 3 ++- src/frontend/qt_sdl/EmuThread.cpp | 18 +++++++++++------- src/frontend/qt_sdl/EmuThread.h | 6 +++--- src/frontend/qt_sdl/Window.cpp | 2 +- src/frontend/qt_sdl/main.cpp | 4 ++-- src/frontend/qt_sdl/main.h | 7 +++++-- 7 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index 3906b186..a848fc3e 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -241,11 +241,24 @@ void EmuInstance::deleteAllWindows() } -void EmuInstance::updateConfigInfo(int kind) +void EmuInstance::broadcastCommand(int cmd) { - switch (kind) + broadcastInstanceCommand(cmd, instanceID); +} + +void EmuInstance::handleCommand(int cmd) +{ + switch (cmd) { - case Config_RecentFiles: + case InstCmd_Pause: + emuThread->emuPause(false); + break; + + case InstCmd_Unpause: + emuThread->emuUnpause(false); + break; + + case InstCmd_UpdateRecentFiles: for (int i = 0; i < kMaxWindows; i++) { if (windowList[i]) diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index a7ecddf8..61090496 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -92,7 +92,8 @@ public: Config::Table& getGlobalConfig() { return globalCfg; } Config::Table& getLocalConfig() { return localCfg; } - void updateConfigInfo(int kind); + void broadcastCommand(int cmd); + void handleCommand(int cmd); std::string instanceFileSuffix(); diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 1bf22c36..583ed91c 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -70,7 +70,6 @@ EmuThread::EmuThread(EmuInstance* inst, QObject* parent) : QThread(parent) void EmuThread::attachWindow(MainWindow* window) { - //connect(this, SIGNAL(windowUpdate()), window->panel, SLOT(repaint())); connect(this, SIGNAL(windowTitleChange(QString)), window, SLOT(onTitleUpdate(QString))); connect(this, SIGNAL(windowEmuStart()), window, SLOT(onEmuStart())); connect(this, SIGNAL(windowEmuStop()), window, SLOT(onEmuStop())); @@ -89,7 +88,6 @@ void EmuThread::attachWindow(MainWindow* window) void EmuThread::detachWindow(MainWindow* window) { - //disconnect(this, SIGNAL(windowUpdate()), window->panel, SLOT(repaint())); disconnect(this, SIGNAL(windowTitleChange(QString)), window, SLOT(onTitleUpdate(QString))); disconnect(this, SIGNAL(windowEmuStart()), window, SLOT(onEmuStart())); disconnect(this, SIGNAL(windowEmuStop()), window, SLOT(onEmuStop())); @@ -676,24 +674,30 @@ void EmuThread::emuRun() waitMessage(); } -void EmuThread::emuPause() +void EmuThread::emuPause(bool broadcast) { sendMessage(msg_EmuPause); waitMessage(); + + if (broadcast) + emuInstance->broadcastCommand(InstCmd_Pause); } -void EmuThread::emuUnpause() +void EmuThread::emuUnpause(bool broadcast) { sendMessage(msg_EmuUnpause); waitMessage(); + + if (broadcast) + emuInstance->broadcastCommand(InstCmd_Unpause); } -void EmuThread::emuTogglePause() +void EmuThread::emuTogglePause(bool broadcast) { if (emuStatus == emuStatus_Paused) - emuUnpause(); + emuUnpause(broadcast); else - emuPause(); + emuPause(broadcast); } void EmuThread::emuStop(bool external) diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h index 57f389af..19e1a3a6 100644 --- a/src/frontend/qt_sdl/EmuThread.h +++ b/src/frontend/qt_sdl/EmuThread.h @@ -104,9 +104,9 @@ public: // to be called from the UI thread void emuRun(); - void emuPause(); - void emuUnpause(); - void emuTogglePause(); + void emuPause(bool broadcast = true); + void emuUnpause(bool broadcast = true); + void emuTogglePause(bool broadcast = true); void emuStop(bool external); void emuExit(); void emuFrameStep(); diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index a231a6f8..442274b5 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -1349,7 +1349,7 @@ void MainWindow::updateRecentFilesMenu() Config::Save(); loadRecentFilesMenu(false); - updateConfigInfoAll(Config_RecentFiles, emuInstance->getInstanceID()); + emuInstance->broadcastCommand(InstCmd_UpdateRecentFiles); } void MainWindow::onClickRecentFile() diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index a4cc965e..69485a8e 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -168,14 +168,14 @@ int numEmuInstances() } -void updateConfigInfoAll(int kind, int sourceinst) +void broadcastInstanceCommand(int cmd, int sourceinst) { for (int i = 0; i < kMaxEmuInstances; i++) { if (i == sourceinst) continue; if (!emuInstances[i]) continue; - emuInstances[i]->updateConfigInfo(kind); + emuInstances[i]->handleCommand(cmd); } } diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index b247d1fd..cd5a08f1 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -33,7 +33,10 @@ enum { - Config_RecentFiles, + InstCmd_Pause, + InstCmd_Unpause, + + InstCmd_UpdateRecentFiles, }; class MelonApplication : public QApplication @@ -55,7 +58,7 @@ void deleteEmuInstance(int id); void deleteAllEmuInstances(int first = 0); int numEmuInstances(); -void updateConfigInfoAll(int kind, int sourceinst); +void broadcastInstanceCommand(int cmd, int sourceinst); void setMPInterface(melonDS::MPInterfaceType type); From 6d345cc1eaabf426253b37359664af8d3dcfb0bd Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 13:43:26 +0100 Subject: [PATCH 35/47] correctly propagate video settings changes to all windows --- src/frontend/qt_sdl/EmuInstance.cpp | 10 +++++-- src/frontend/qt_sdl/EmuInstance.h | 4 +-- src/frontend/qt_sdl/Window.cpp | 44 ++++++++++++++++++----------- src/frontend/qt_sdl/Window.h | 1 + src/frontend/qt_sdl/main.cpp | 4 +-- src/frontend/qt_sdl/main.h | 3 +- 6 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index a848fc3e..7efa6509 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -241,12 +241,12 @@ void EmuInstance::deleteAllWindows() } -void EmuInstance::broadcastCommand(int cmd) +void EmuInstance::broadcastCommand(int cmd, QVariant param) { - broadcastInstanceCommand(cmd, instanceID); + broadcastInstanceCommand(cmd, param, instanceID); } -void EmuInstance::handleCommand(int cmd) +void EmuInstance::handleCommand(int cmd, QVariant& param) { switch (cmd) { @@ -265,6 +265,10 @@ void EmuInstance::handleCommand(int cmd) windowList[i]->loadRecentFilesMenu(true); } break; + + /*case InstCmd_UpdateVideoSettings: + mainWindow->updateVideoSettings(param.value()); + break;*/ } } diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index 61090496..a79b4f75 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -92,8 +92,8 @@ public: Config::Table& getGlobalConfig() { return globalCfg; } Config::Table& getLocalConfig() { return localCfg; } - void broadcastCommand(int cmd); - void handleCommand(int cmd); + void broadcastCommand(int cmd, QVariant param = QVariant()); + void handleCommand(int cmd, QVariant& param); std::string instanceFileSuffix(); diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 442274b5..fef51217 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -2147,14 +2147,11 @@ void MainWindow::onEmuReset() void MainWindow::onUpdateVideoSettings(bool glchange) { - if (windowID != 0) - { - MainWindow* parentwin = (MainWindow*)parentWidget(); - if (parentwin) - parentwin->onUpdateVideoSettings(glchange); - - return; - } + // if we have a parent window: pass the message over to the parent + // the topmost parent takes care of updating all the windows + MainWindow* parentwin = (MainWindow*)parentWidget(); + if (parentwin) + return parentwin->onUpdateVideoSettings(glchange); bool hadOGL = hasOGL; if (glchange) @@ -2170,18 +2167,33 @@ void MainWindow::onUpdateVideoSettings(bool glchange) if (glchange) { if (hasOGL) emuThread->initContext(windowID); + } - if (windowID == 0) + // update any child windows we have + auto childwins = findChildren(nullptr, Qt::FindDirectChildrenOnly); + for (auto child: childwins) + { + // child windows may belong to a different instance + // in that case we need to signal their thread appropriately + auto thread = child->getEmuInstance()->getEmuThread(); + + if (glchange) { - auto childwins = findChildren(nullptr, Qt::FindDirectChildrenOnly); - for (auto child: childwins) - { - if (hadOGL) emuThread->deinitContext(child->windowID); - child->createScreenPanel(); - if (hasOGL) emuThread->initContext(child->windowID); - } + if (hadOGL) thread->deinitContext(child->windowID); + child->createScreenPanel(); } + if (child->getWindowID() == 0) + thread->updateVideoSettings(); + + if (glchange) + { + if (hasOGL) thread->initContext(child->windowID); + } + } + + if (glchange) + { emuThread->emuUnpause(); } } diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h index 73bb84bb..64f17841 100644 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -135,6 +135,7 @@ public: void updateMPInterface(melonDS::MPInterfaceType type); void loadRecentFilesMenu(bool loadcfg); + //void updateVideoSettings(bool glchange); protected: void keyPressEvent(QKeyEvent* event) override; diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 69485a8e..d940340a 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -168,14 +168,14 @@ int numEmuInstances() } -void broadcastInstanceCommand(int cmd, int sourceinst) +void broadcastInstanceCommand(int cmd, QVariant& param, int sourceinst) { for (int i = 0; i < kMaxEmuInstances; i++) { if (i == sourceinst) continue; if (!emuInstances[i]) continue; - emuInstances[i]->handleCommand(cmd); + emuInstances[i]->handleCommand(cmd, param); } } diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index cd5a08f1..e0d38963 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -37,6 +37,7 @@ enum InstCmd_Unpause, InstCmd_UpdateRecentFiles, + //InstCmd_UpdateVideoSettings, }; class MelonApplication : public QApplication @@ -58,7 +59,7 @@ void deleteEmuInstance(int id); void deleteAllEmuInstances(int first = 0); int numEmuInstances(); -void broadcastInstanceCommand(int cmd, int sourceinst); +void broadcastInstanceCommand(int cmd, QVariant& param, int sourceinst); void setMPInterface(melonDS::MPInterfaceType type); From a61754bb589cdacd45db78dca504dcf840d9f04e Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 13:53:12 +0100 Subject: [PATCH 36/47] fix possible crash when closing window while video settings dialog is open --- src/frontend/qt_sdl/Window.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index fef51217..5115045a 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -2147,6 +2147,8 @@ void MainWindow::onEmuReset() void MainWindow::onUpdateVideoSettings(bool glchange) { + if (!emuInstance) return; + // if we have a parent window: pass the message over to the parent // the topmost parent takes care of updating all the windows MainWindow* parentwin = (MainWindow*)parentWidget(); From f2dce621ceb50f8f617fa4bd252821660ab6ef0e Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 14:24:59 +0100 Subject: [PATCH 37/47] proof all dialogs against use-after-free when closing main window while a dialog is open --- src/frontend/qt_sdl/AudioSettingsDialog.cpp | 6 ++++++ src/frontend/qt_sdl/CameraSettingsDialog.cpp | 6 ++++++ src/frontend/qt_sdl/EmuSettingsDialog.cpp | 7 +++++++ src/frontend/qt_sdl/FirmwareSettingsDialog.cpp | 7 +++++++ .../qt_sdl/InterfaceSettingsDialog.cpp | 7 +++++++ src/frontend/qt_sdl/LANDialog.cpp | 18 ++++++++++++++++++ src/frontend/qt_sdl/MPSettingsDialog.cpp | 7 +++++++ src/frontend/qt_sdl/NetplayDialog.cpp | 12 ++++++++++++ src/frontend/qt_sdl/PathSettingsDialog.cpp | 7 +++++++ src/frontend/qt_sdl/VideoSettingsDialog.cpp | 6 ++++++ src/frontend/qt_sdl/WifiSettingsDialog.cpp | 7 +++++++ 11 files changed, 90 insertions(+) diff --git a/src/frontend/qt_sdl/AudioSettingsDialog.cpp b/src/frontend/qt_sdl/AudioSettingsDialog.cpp index 37f856ac..5c0c9330 100644 --- a/src/frontend/qt_sdl/AudioSettingsDialog.cpp +++ b/src/frontend/qt_sdl/AudioSettingsDialog.cpp @@ -170,6 +170,12 @@ void AudioSettingsDialog::on_AudioSettingsDialog_accepted() void AudioSettingsDialog::on_AudioSettingsDialog_rejected() { + if (!((MainWindow*)parent())->getEmuInstance()) + { + closeDlg(); + return; + } + auto& cfg = emuInstance->getGlobalConfig(); auto& instcfg = emuInstance->getLocalConfig(); cfg.SetInt("Audio.Interpolation", oldInterp); diff --git a/src/frontend/qt_sdl/CameraSettingsDialog.cpp b/src/frontend/qt_sdl/CameraSettingsDialog.cpp index 39c05cef..63b7a76e 100644 --- a/src/frontend/qt_sdl/CameraSettingsDialog.cpp +++ b/src/frontend/qt_sdl/CameraSettingsDialog.cpp @@ -163,6 +163,12 @@ void CameraSettingsDialog::on_CameraSettingsDialog_accepted() void CameraSettingsDialog::on_CameraSettingsDialog_rejected() { + if (!((MainWindow*)parent())->getEmuInstance()) + { + closeDlg(); + return; + } + for (int i = 0; i < 2; i++) { camManager[i]->stop(); diff --git a/src/frontend/qt_sdl/EmuSettingsDialog.cpp b/src/frontend/qt_sdl/EmuSettingsDialog.cpp index 7a6c0f40..b37f7118 100644 --- a/src/frontend/qt_sdl/EmuSettingsDialog.cpp +++ b/src/frontend/qt_sdl/EmuSettingsDialog.cpp @@ -215,6 +215,13 @@ void EmuSettingsDialog::verifyFirmware() void EmuSettingsDialog::done(int r) { + if (!((MainWindow*)parent())->getEmuInstance()) + { + QDialog::done(r); + closeDlg(); + return; + } + needsReset = false; if (r == QDialog::Accepted) diff --git a/src/frontend/qt_sdl/FirmwareSettingsDialog.cpp b/src/frontend/qt_sdl/FirmwareSettingsDialog.cpp index 5d5ecd01..1f71b5b9 100644 --- a/src/frontend/qt_sdl/FirmwareSettingsDialog.cpp +++ b/src/frontend/qt_sdl/FirmwareSettingsDialog.cpp @@ -132,6 +132,13 @@ bool FirmwareSettingsDialog::verifyMAC() void FirmwareSettingsDialog::done(int r) { + if (!((MainWindow*)parent())->getEmuInstance()) + { + QDialog::done(r); + closeDlg(); + return; + } + needsReset = false; if (r == QDialog::Accepted) diff --git a/src/frontend/qt_sdl/InterfaceSettingsDialog.cpp b/src/frontend/qt_sdl/InterfaceSettingsDialog.cpp index 2e7e75c9..bd02405e 100644 --- a/src/frontend/qt_sdl/InterfaceSettingsDialog.cpp +++ b/src/frontend/qt_sdl/InterfaceSettingsDialog.cpp @@ -104,6 +104,13 @@ void InterfaceSettingsDialog::on_pbQuarter_clicked() void InterfaceSettingsDialog::done(int r) { + if (!((MainWindow*)parent())->getEmuInstance()) + { + QDialog::done(r); + closeDlg(); + return; + } + if (r == QDialog::Accepted) { auto& cfg = emuInstance->getGlobalConfig(); diff --git a/src/frontend/qt_sdl/LANDialog.cpp b/src/frontend/qt_sdl/LANDialog.cpp index 32539e3f..bec9c48f 100644 --- a/src/frontend/qt_sdl/LANDialog.cpp +++ b/src/frontend/qt_sdl/LANDialog.cpp @@ -65,6 +65,12 @@ LANStartHostDialog::~LANStartHostDialog() void LANStartHostDialog::done(int r) { + if (!((MainWindow*)parent())->getEmuInstance()) + { + QDialog::done(r); + return; + } + if (r == QDialog::Accepted) { if (ui->txtPlayerName->text().trimmed().isEmpty()) @@ -186,6 +192,12 @@ void LANStartClientDialog::onDirectConnect() void LANStartClientDialog::done(int r) { + if (!((MainWindow*)parent())->getEmuInstance()) + { + QDialog::done(r); + return; + } + if (r == QDialog::Accepted) { if (ui->txtPlayerName->text().trimmed().isEmpty()) @@ -313,6 +325,12 @@ void LANDialog::on_btnLeaveGame_clicked() void LANDialog::done(int r) { + if (!((MainWindow*)parent())->getEmuInstance()) + { + QDialog::done(r); + return; + } + bool showwarning = true; if (lan().GetNumPlayers() < 2) showwarning = false; diff --git a/src/frontend/qt_sdl/MPSettingsDialog.cpp b/src/frontend/qt_sdl/MPSettingsDialog.cpp index e241ba3d..54c35d15 100644 --- a/src/frontend/qt_sdl/MPSettingsDialog.cpp +++ b/src/frontend/qt_sdl/MPSettingsDialog.cpp @@ -59,6 +59,13 @@ MPSettingsDialog::~MPSettingsDialog() void MPSettingsDialog::done(int r) { + if (!((MainWindow*)parent())->getEmuInstance()) + { + QDialog::done(r); + closeDlg(); + return; + } + if (r == QDialog::Accepted) { auto& cfg = emuInstance->getGlobalConfig(); diff --git a/src/frontend/qt_sdl/NetplayDialog.cpp b/src/frontend/qt_sdl/NetplayDialog.cpp index e9ed6022..d7b7cf81 100644 --- a/src/frontend/qt_sdl/NetplayDialog.cpp +++ b/src/frontend/qt_sdl/NetplayDialog.cpp @@ -63,6 +63,12 @@ NetplayStartHostDialog::~NetplayStartHostDialog() void NetplayStartHostDialog::done(int r) { + if (!((MainWindow*)parent())->getEmuInstance()) + { + QDialog::done(r); + return; + } + if (r == QDialog::Accepted) { std::string player = ui->txtPlayerName->text().toStdString(); @@ -94,6 +100,12 @@ NetplayStartClientDialog::~NetplayStartClientDialog() void NetplayStartClientDialog::done(int r) { + if (!((MainWindow*)parent())->getEmuInstance()) + { + QDialog::done(r); + return; + } + if (r == QDialog::Accepted) { std::string player = ui->txtPlayerName->text().toStdString(); diff --git a/src/frontend/qt_sdl/PathSettingsDialog.cpp b/src/frontend/qt_sdl/PathSettingsDialog.cpp index b1bc8301..f3a453d1 100644 --- a/src/frontend/qt_sdl/PathSettingsDialog.cpp +++ b/src/frontend/qt_sdl/PathSettingsDialog.cpp @@ -72,6 +72,13 @@ PathSettingsDialog::~PathSettingsDialog() void PathSettingsDialog::done(int r) { + if (!((MainWindow*)parent())->getEmuInstance()) + { + QDialog::done(r); + closeDlg(); + return; + } + needsReset = false; if (r == QDialog::Accepted) diff --git a/src/frontend/qt_sdl/VideoSettingsDialog.cpp b/src/frontend/qt_sdl/VideoSettingsDialog.cpp index 7eebf5a4..619ecda3 100644 --- a/src/frontend/qt_sdl/VideoSettingsDialog.cpp +++ b/src/frontend/qt_sdl/VideoSettingsDialog.cpp @@ -121,6 +121,12 @@ void VideoSettingsDialog::on_VideoSettingsDialog_accepted() void VideoSettingsDialog::on_VideoSettingsDialog_rejected() { + if (!((MainWindow*)parent())->getEmuInstance()) + { + closeDlg(); + return; + } + bool old_gl = UsesGL(); auto& cfg = emuInstance->getGlobalConfig(); diff --git a/src/frontend/qt_sdl/WifiSettingsDialog.cpp b/src/frontend/qt_sdl/WifiSettingsDialog.cpp index c3f988b1..e0954c83 100644 --- a/src/frontend/qt_sdl/WifiSettingsDialog.cpp +++ b/src/frontend/qt_sdl/WifiSettingsDialog.cpp @@ -94,6 +94,13 @@ WifiSettingsDialog::~WifiSettingsDialog() void WifiSettingsDialog::done(int r) { + if (!((MainWindow*)parent())->getEmuInstance()) + { + QDialog::done(r); + closeDlg(); + return; + } + needsReset = false; if (r == QDialog::Accepted) From 94955aee81cc06c51db84300f87fb7ee41e62b69 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 14:51:11 +0100 Subject: [PATCH 38/47] fix another OpenGL bug (when closing secondary window) --- src/frontend/qt_sdl/EmuThread.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 583ed91c..3371a03b 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -559,7 +559,8 @@ void EmuThread::handleMessages() case msg_DeInitGL: emuInstance->deinitOpenGL(msg.param.value()); - useOpenGL = false; + if (msg.param.value() == 0) + useOpenGL = false; break; case msg_BootROM: From d79d45a117a219c3d47128f9458004b2560b7db8 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 16:21:09 +0100 Subject: [PATCH 39/47] properly sync up menus between windows of a same instance --- src/frontend/qt_sdl/EmuInstance.cpp | 11 ++++++++++ src/frontend/qt_sdl/EmuInstance.h | 2 ++ src/frontend/qt_sdl/Window.cpp | 34 +++++++++++++++++++++-------- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index 7efa6509..1387686e 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -240,6 +240,17 @@ void EmuInstance::deleteAllWindows() deleteWindow(i, true); } +void EmuInstance::doOnAllWindows(std::function func, int exclude) +{ + for (int i = 0; i < kMaxWindows; i++) + { + if (i == exclude) continue; + if (!windowList[i]) continue; + + func(windowList[i]); + } +} + void EmuInstance::broadcastCommand(int cmd, QVariant param) { diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index a79b4f75..ed6ca0df 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -89,6 +89,8 @@ public: MainWindow* getMainWindow() { return mainWindow; } MainWindow* getWindow(int id) { return windowList[id]; } + void doOnAllWindows(std::function func, int exclude = -1); + Config::Table& getGlobalConfig() { return globalCfg; } Config::Table& getLocalConfig() { return localCfg; } diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 5115045a..8f90a47f 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -781,6 +781,9 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : actPreferences->setEnabled(false); #endif // __APPLE__ } + + if (emuThread->emuIsActive()) + onEmuStart(); } QObject::connect(qApp, &QApplication::applicationStateChanged, this, &MainWindow::onAppStateChanged); @@ -1226,21 +1229,34 @@ QStringList MainWindow::pickROM(bool gba) void MainWindow::updateCartInserted(bool gba) { bool inserted; + QString label; if (gba) { - inserted = emuInstance->gbaCartInserted() && (globalCfg.GetInt("Emu.ConsoleType") == 0); - actCurrentGBACart->setText("GBA slot: " + emuInstance->gbaCartLabel()); - actEjectGBACart->setEnabled(inserted); + inserted = emuInstance->gbaCartInserted() && (emuInstance->getConsoleType() == 0); + label = "GBA slot: " + emuInstance->gbaCartLabel(); + + emuInstance->doOnAllWindows([=](MainWindow* win) + { + if (!win->hasMenu) return; + win->actCurrentGBACart->setText(label); + win->actEjectGBACart->setEnabled(inserted); + }); } else { inserted = emuInstance->cartInserted(); - actCurrentCart->setText("DS slot: " + emuInstance->cartLabel()); - actEjectCart->setEnabled(inserted); - actImportSavefile->setEnabled(inserted); - actSetupCheats->setEnabled(inserted); - actROMInfo->setEnabled(inserted); - actRAMInfo->setEnabled(inserted); + label = "DS slot: " + emuInstance->cartLabel(); + + emuInstance->doOnAllWindows([=](MainWindow* win) + { + if (!win->hasMenu) return; + win->actCurrentCart->setText(label); + win->actEjectCart->setEnabled(inserted); + win->actImportSavefile->setEnabled(inserted); + win->actSetupCheats->setEnabled(inserted); + win->actROMInfo->setEnabled(inserted); + win->actRAMInfo->setEnabled(inserted); + }); } } From 238c5525997c49d9c2ad50d51bb53e86f57d58a3 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 16:26:29 +0100 Subject: [PATCH 40/47] limit to 4 windows, and disable 'new window' menu item when that amount is reached --- src/frontend/qt_sdl/EmuInstance.cpp | 14 ++++++++++++++ src/frontend/qt_sdl/EmuInstance.h | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index 1387686e..12afb12b 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -203,6 +203,12 @@ void EmuInstance::createWindow() // if creating a secondary window, we may need to initialize its OpenGL context here if (win->hasOpenGL() && (id != 0)) emuThread->initContext(id); + + bool enable = (numWindows < kMaxWindows); + doOnAllWindows([=](MainWindow* win) + { + win->actNewWindow->setEnabled(enable); + }); } void EmuInstance::deleteWindow(int id, bool close) @@ -232,6 +238,14 @@ void EmuInstance::deleteWindow(int id, bool close) // if the main window is closed, Qt will take care of closing any secondary windows deleteEmuInstance(instanceID); } + else + { + bool enable = (numWindows < kMaxWindows); + doOnAllWindows([=](MainWindow* win) + { + win->actNewWindow->setEnabled(enable); + }); + } } void EmuInstance::deleteAllWindows() diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index ed6ca0df..0122b0d9 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -28,7 +28,7 @@ #include "Config.h" #include "SaveManager.h" -const int kMaxWindows = 16; +const int kMaxWindows = 4; enum { @@ -87,6 +87,7 @@ public: melonDS::NDS* getNDS() { return nds; } MainWindow* getMainWindow() { return mainWindow; } + int getNumWindows() { return numWindows; } MainWindow* getWindow(int id) { return windowList[id]; } void doOnAllWindows(std::function func, int exclude = -1); From e42829ea81c3a31706614e95488b27a5a3ca5f39 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 17:21:41 +0100 Subject: [PATCH 41/47] pause emu during file select prompts --- src/frontend/qt_sdl/Window.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 8f90a47f..b09f8354 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -1196,6 +1196,8 @@ QString MainWindow::pickFileFromArchive(QString archiveFileName) QStringList MainWindow::pickROM(bool gba) { + emuThread->emuPause(); + const QString console = gba ? "GBA" : "DS"; const QStringList& romexts = gba ? GbaRomExtensions : NdsRomExtensions; @@ -1220,10 +1222,16 @@ QStringList MainWindow::pickROM(bool gba) "All supported files (*" + allROMs + ")" + extraFilters ); - if (filename.isEmpty()) return {}; + if (filename.isEmpty()) + { + emuThread->emuUnpause(); + return {}; + } globalCfg.SetQString("LastROMFolder", QFileInfo(filename).dir().path()); - return splitArchivePath(filename, false); + auto ret = splitArchivePath(filename, false); + emuThread->emuUnpause(); + return ret; } void MainWindow::updateCartInserted(bool gba) @@ -1465,10 +1473,12 @@ void MainWindow::onSaveState() else { // TODO: specific 'last directory' for savestate files? + emuThread->emuPause(); filename = QFileDialog::getSaveFileName(this, "Save state", globalCfg.GetQString("LastROMFolder"), "melonDS savestates (*.mln);;Any file (*.*)"); + emuThread->emuUnpause(); if (filename.isEmpty()) return; } @@ -1498,10 +1508,12 @@ void MainWindow::onLoadState() else { // TODO: specific 'last directory' for savestate files? + emuThread->emuPause(); filename = QFileDialog::getOpenFileName(this, "Load state", globalCfg.GetQString("LastROMFolder"), "melonDS savestates (*.ml*);;Any file (*.*)"); + emuThread->emuUnpause(); if (filename.isEmpty()) return; } From 12b207d915e5437e532f92434cad70047e67e920 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 27 Oct 2024 18:49:17 +0100 Subject: [PATCH 42/47] remember which windows are opened --- src/frontend/qt_sdl/Config.cpp | 2 +- src/frontend/qt_sdl/EmuInstance.cpp | 34 ++++++++++++++++++++++++----- src/frontend/qt_sdl/EmuInstance.h | 3 ++- src/frontend/qt_sdl/Window.cpp | 15 ++++++++++++- src/frontend/qt_sdl/Window.h | 3 +++ 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/frontend/qt_sdl/Config.cpp b/src/frontend/qt_sdl/Config.cpp index 3f570302..02be5b65 100644 --- a/src/frontend/qt_sdl/Config.cpp +++ b/src/frontend/qt_sdl/Config.cpp @@ -99,7 +99,7 @@ DefaultList DefaultBools = {"3D.Soft.Threaded", true}, {"3D.GL.HiresCoordinates", true}, {"LimitFPS", true}, - {"Window*.ShowOSD", true}, + {"Instance*.Window*.ShowOSD", true}, {"Emu.DirectBoot", true}, {"Instance*.DS.Battery.LevelOkay", true}, {"Instance*.DSi.Battery.Charging", true}, diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index 12afb12b..90116692 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -137,6 +137,16 @@ EmuInstance::EmuInstance(int inst) : deleting(false), emuThread->start(); emuThread->emuPause(); + + // if any extra windows were saved as enabled, open them + for (int i = 1; i < kMaxWindows; i++) + { + //Config::Table tbl = localCfg.GetTable("Window"+std::to_string(i), "Window0"); + std::string key = "Window" + std::to_string(i) + ".Enabled"; + bool enable = localCfg.GetBool(key); + if (enable) + createWindow(i); + } } EmuInstance::~EmuInstance() @@ -173,7 +183,7 @@ std::string EmuInstance::instanceFileSuffix() return suffix; } -void EmuInstance::createWindow() +void EmuInstance::createWindow(int id) { if (numWindows >= kMaxWindows) { @@ -181,16 +191,20 @@ void EmuInstance::createWindow() return; } - int id = -1; - for (int i = 0; i < kMaxWindows; i++) + if (id == -1) { - if (windowList[i]) continue; - id = i; - break; + for (int i = 0; i < kMaxWindows; i++) + { + if (windowList[i]) continue; + id = i; + break; + } } if (id == -1) return; + if (windowList[id]) + return; MainWindow* win = new MainWindow(id, this, topWindow); if (!topWindow) topWindow = win; @@ -265,6 +279,14 @@ void EmuInstance::doOnAllWindows(std::function func, int excl } } +void EmuInstance::saveEnabledWindows() +{ + doOnAllWindows([=](MainWindow* win) + { + win->saveEnabled(true); + }); +} + void EmuInstance::broadcastCommand(int cmd, QVariant param) { diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index 0122b0d9..658247f0 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -91,6 +91,7 @@ public: MainWindow* getWindow(int id) { return windowList[id]; } void doOnAllWindows(std::function func, int exclude = -1); + void saveEnabledWindows(); Config::Table& getGlobalConfig() { return globalCfg; } Config::Table& getLocalConfig() { return localCfg; } @@ -100,7 +101,7 @@ public: std::string instanceFileSuffix(); - void createWindow(); + void createWindow(int id = -1); void deleteWindow(int id, bool close); void deleteAllWindows(); diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index b09f8354..2354fa20 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -234,7 +234,8 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : globalCfg(inst->globalCfg), localCfg(inst->localCfg), windowCfg(localCfg.GetTable("Window"+std::to_string(id), "Window0")), - emuThread(inst->getEmuThread()) + emuThread(inst->getEmuThread()), + enabledSaved(false) { #ifndef _WIN32 if (!parent) @@ -807,8 +808,20 @@ void MainWindow::osdAddMessage(unsigned int color, const char* msg) panel->osdAddMessage(color, msg); } +void MainWindow::saveEnabled(bool enabled) +{ + if (enabledSaved) return; + windowCfg.SetBool("Enabled", enabled); + enabledSaved = true; +} + void MainWindow::closeEvent(QCloseEvent* event) { + if (windowID == 0) + emuInstance->saveEnabledWindows(); + else + saveEnabled(false); + QByteArray geom = saveGeometry(); QByteArray enc = geom.toBase64(QByteArray::Base64Encoding); windowCfg.SetString("Geometry", enc.toStdString()); diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h index 64f17841..121115c0 100644 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -114,6 +114,8 @@ public: bool winHasMenu() { return hasMenu; } + void saveEnabled(bool enabled); + void toggleFullscreen(); bool hasOpenGL() { return hasOGL; } @@ -260,6 +262,7 @@ private: bool pausedManually; int windowID; + bool enabledSaved; EmuInstance* emuInstance; EmuThread* emuThread; From b03bceb5c1108f2a14a78b0e5cca5671e0c85ce7 Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Sun, 27 Oct 2024 21:22:49 +0100 Subject: [PATCH 43/47] flake: shell should also use qt6's stdenv --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index e898674a..8d500c03 100644 --- a/flake.nix +++ b/flake.nix @@ -74,7 +74,7 @@ drv = self.packages.${system}.default; }; devShells = { - default = pkgs.mkShell { + default = pkgs.mkShell.override { stdenv = pkgs.qt6.qtbase.stdenv; } { inputsFrom = [ self.packages.${system}.default ]; }; From 98d969ab15b8be1463386e330e48e64772a1584f Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Sun, 27 Oct 2024 21:23:15 +0100 Subject: [PATCH 44/47] only apply windows11 theme workaround to Qt6. Qt5 doesn't have it anywya. --- src/frontend/qt_sdl/Window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 2354fa20..5c599e70 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -265,7 +265,7 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : setAcceptDrops(true); setFocusPolicy(Qt::ClickFocus); -#ifdef WIN32 +#ifdef QT_VERSION_MAJOR == 6 && WIN32 // The "windows11" theme has pretty massive padding around menubar items, this makes Config and Help not fit in a window at 1x screen sizing // So let's reduce the padding a bit. if (QApplication::style()->name() == "windows11") From b60f42b281e4b465ff3cd6f964ab10d238ad31bd Mon Sep 17 00:00:00 2001 From: GalaxyShard <76917584+GalaxyShard@users.noreply.github.com> Date: Sun, 27 Oct 2024 21:06:59 +0000 Subject: [PATCH 45/47] Fix gdb break on start & gdb ports not closing after restarting/crashing (#2167) --- src/ARM.cpp | 1 + src/debug/GdbStub.cpp | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/src/ARM.cpp b/src/ARM.cpp index 4cf70749..b7b703da 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -110,6 +110,7 @@ const u32 ARM::ConditionTable[16] = ARM::ARM(u32 num, bool jit, std::optional gdb, melonDS::NDS& nds) : #ifdef GDBSTUB_ENABLED GdbStub(this, gdb ? (num ? gdb->PortARM7 : gdb->PortARM9) : 0), + BreakOnStartup(gdb ? (num ? gdb->ARM7BreakOnStartup : gdb->ARM9BreakOnStartup) : false), #endif Num(num), // well uh NDS(nds) diff --git a/src/debug/GdbStub.cpp b/src/debug/GdbStub.cpp index 14a8670a..b055794a 100644 --- a/src/debug/GdbStub.cpp +++ b/src/debug/GdbStub.cpp @@ -101,6 +101,15 @@ bool GdbStub::Init() Log(LogLevel::Error, "[GDB] err: can't create a socket fd\n"); goto err; } + { + // Make sure the port can be reused immediately after melonDS stops and/or restarts + int enable = 1; +#ifdef _WIN32 + setsockopt(SockFd, SOL_SOCKET, SO_REUSEADDR, (const char*)&enable, sizeof(enable)); +#else + setsockopt(SockFd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); +#endif + } #ifndef __linux__ SocketSetBlocking(SockFd, false); #endif From 58ab33210af3bbcfdba219990eb56b9716622e04 Mon Sep 17 00:00:00 2001 From: RSDuck Date: Sun, 27 Oct 2024 23:32:05 +0100 Subject: [PATCH 46/47] handle address wrap around in texture cache fixes out of bounds access in Mario 64 also slightly optimise paletted texture conversion --- src/GPU.h | 11 ++++ src/GPU3D_Soft.cpp | 50 ++++++++--------- src/GPU3D_Soft.h | 10 ---- src/GPU3D_Texcache.cpp | 61 ++++++++++----------- src/GPU3D_Texcache.h | 118 ++++++++++++++++++++++++----------------- 5 files changed, 136 insertions(+), 114 deletions(-) diff --git a/src/GPU.h b/src/GPU.h index 26e9d5df..5c373ca8 100644 --- a/src/GPU.h +++ b/src/GPU.h @@ -499,6 +499,17 @@ public: OAMDirty |= 1 << (addr / 1024); } + template + inline T ReadVRAMFlat_Texture(u32 addr) const + { + return *(T*)&VRAMFlat_Texture[addr & 0x7FFFF]; + } + template + inline T ReadVRAMFlat_TexPal(u32 addr) const + { + return *(T*)&VRAMFlat_TexPal[addr & 0x1FFFF]; + } + void SetPowerCnt(u32 val) noexcept; void StartFrame() noexcept; diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp index 1221ed59..a9d0bd64 100644 --- a/src/GPU3D_Soft.cpp +++ b/src/GPU3D_Soft.cpp @@ -193,10 +193,10 @@ void SoftRenderer::TextureLookup(const GPU& gpu, u32 texparam, u32 texpal, s16 s case 1: // A3I5 { vramaddr += ((t * width) + s); - u8 pixel = ReadVRAM_Texture(vramaddr, gpu); + u8 pixel = gpu.ReadVRAMFlat_Texture(vramaddr); texpal <<= 4; - *color = ReadVRAM_TexPal(texpal + ((pixel&0x1F)<<1), gpu); + *color = gpu.ReadVRAMFlat_TexPal(texpal + ((pixel&0x1F)<<1)); *alpha = ((pixel >> 3) & 0x1C) + (pixel >> 6); } break; @@ -204,12 +204,12 @@ void SoftRenderer::TextureLookup(const GPU& gpu, u32 texparam, u32 texpal, s16 s case 2: // 4-color { vramaddr += (((t * width) + s) >> 2); - u8 pixel = ReadVRAM_Texture(vramaddr, gpu); + u8 pixel = gpu.ReadVRAMFlat_Texture(vramaddr); pixel >>= ((s & 0x3) << 1); pixel &= 0x3; texpal <<= 3; - *color = ReadVRAM_TexPal(texpal + (pixel<<1), gpu); + *color = gpu.ReadVRAMFlat_TexPal(texpal + (pixel<<1)); *alpha = (pixel==0) ? alpha0 : 31; } break; @@ -217,12 +217,12 @@ void SoftRenderer::TextureLookup(const GPU& gpu, u32 texparam, u32 texpal, s16 s case 3: // 16-color { vramaddr += (((t * width) + s) >> 1); - u8 pixel = ReadVRAM_Texture(vramaddr, gpu); + u8 pixel = gpu.ReadVRAMFlat_Texture(vramaddr); if (s & 0x1) pixel >>= 4; else pixel &= 0xF; texpal <<= 4; - *color = ReadVRAM_TexPal(texpal + (pixel<<1), gpu); + *color = gpu.ReadVRAMFlat_TexPal(texpal + (pixel<<1)); *alpha = (pixel==0) ? alpha0 : 31; } break; @@ -230,10 +230,10 @@ void SoftRenderer::TextureLookup(const GPU& gpu, u32 texparam, u32 texpal, s16 s case 4: // 256-color { vramaddr += ((t * width) + s); - u8 pixel = ReadVRAM_Texture(vramaddr, gpu); + u8 pixel = gpu.ReadVRAMFlat_Texture(vramaddr); texpal <<= 4; - *color = ReadVRAM_TexPal(texpal + (pixel<<1), gpu); + *color = gpu.ReadVRAMFlat_TexPal(texpal + (pixel<<1)); *alpha = (pixel==0) ? alpha0 : 31; } break; @@ -253,31 +253,31 @@ void SoftRenderer::TextureLookup(const GPU& gpu, u32 texparam, u32 texpal, s16 s val = 0; else { - val = ReadVRAM_Texture(vramaddr, gpu); + val = gpu.ReadVRAMFlat_Texture(vramaddr); val >>= (2 * (s & 0x3)); } - u16 palinfo = ReadVRAM_Texture(slot1addr, gpu); + u16 palinfo = gpu.ReadVRAMFlat_Texture(slot1addr); u32 paloffset = (palinfo & 0x3FFF) << 2; texpal <<= 4; switch (val & 0x3) { case 0: - *color = ReadVRAM_TexPal(texpal + paloffset, gpu); + *color = gpu.ReadVRAMFlat_TexPal(texpal + paloffset); *alpha = 31; break; case 1: - *color = ReadVRAM_TexPal(texpal + paloffset + 2, gpu); + *color = gpu.ReadVRAMFlat_TexPal(texpal + paloffset + 2); *alpha = 31; break; case 2: if ((palinfo >> 14) == 1) { - u16 color0 = ReadVRAM_TexPal(texpal + paloffset, gpu); - u16 color1 = ReadVRAM_TexPal(texpal + paloffset + 2, gpu); + u16 color0 = gpu.ReadVRAMFlat_TexPal(texpal + paloffset); + u16 color1 = gpu.ReadVRAMFlat_TexPal(texpal + paloffset + 2); u32 r0 = color0 & 0x001F; u32 g0 = color0 & 0x03E0; @@ -294,8 +294,8 @@ void SoftRenderer::TextureLookup(const GPU& gpu, u32 texparam, u32 texpal, s16 s } else if ((palinfo >> 14) == 3) { - u16 color0 = ReadVRAM_TexPal(texpal + paloffset, gpu); - u16 color1 = ReadVRAM_TexPal(texpal + paloffset + 2, gpu); + u16 color0 = gpu.ReadVRAMFlat_TexPal(texpal + paloffset); + u16 color1 = gpu.ReadVRAMFlat_TexPal(texpal + paloffset + 2); u32 r0 = color0 & 0x001F; u32 g0 = color0 & 0x03E0; @@ -311,20 +311,20 @@ void SoftRenderer::TextureLookup(const GPU& gpu, u32 texparam, u32 texpal, s16 s *color = r | g | b; } else - *color = ReadVRAM_TexPal(texpal + paloffset + 4, gpu); + *color = gpu.ReadVRAMFlat_TexPal(texpal + paloffset + 4); *alpha = 31; break; case 3: if ((palinfo >> 14) == 2) { - *color = ReadVRAM_TexPal(texpal + paloffset + 6, gpu); + *color = gpu.ReadVRAMFlat_TexPal(texpal + paloffset + 6); *alpha = 31; } else if ((palinfo >> 14) == 3) { - u16 color0 = ReadVRAM_TexPal(texpal + paloffset, gpu); - u16 color1 = ReadVRAM_TexPal(texpal + paloffset + 2, gpu); + u16 color0 = gpu.ReadVRAMFlat_TexPal(texpal + paloffset); + u16 color1 = gpu.ReadVRAMFlat_TexPal(texpal + paloffset + 2); u32 r0 = color0 & 0x001F; u32 g0 = color0 & 0x03E0; @@ -353,10 +353,10 @@ void SoftRenderer::TextureLookup(const GPU& gpu, u32 texparam, u32 texpal, s16 s case 6: // A5I3 { vramaddr += ((t * width) + s); - u8 pixel = ReadVRAM_Texture(vramaddr, gpu); + u8 pixel = gpu.ReadVRAMFlat_Texture(vramaddr); texpal <<= 4; - *color = ReadVRAM_TexPal(texpal + ((pixel&0x7)<<1), gpu); + *color = gpu.ReadVRAMFlat_TexPal(texpal + ((pixel&0x7)<<1)); *alpha = (pixel >> 3); } break; @@ -364,7 +364,7 @@ void SoftRenderer::TextureLookup(const GPU& gpu, u32 texparam, u32 texpal, s16 s case 7: // direct color { vramaddr += (((t * width) + s) << 1); - *color = ReadVRAM_Texture(vramaddr, gpu); + *color = gpu.ReadVRAMFlat_Texture(vramaddr); *alpha = (*color & 0x8000) ? 31 : 0; } break; @@ -1659,8 +1659,8 @@ void SoftRenderer::ClearBuffers(const GPU& gpu) { for (int x = 0; x < 256; x++) { - u16 val2 = ReadVRAM_Texture(0x40000 + (yoff << 9) + (xoff << 1), gpu); - u16 val3 = ReadVRAM_Texture(0x60000 + (yoff << 9) + (xoff << 1), gpu); + u16 val2 = gpu.ReadVRAMFlat_Texture(0x40000 + (yoff << 9) + (xoff << 1)); + u16 val3 = gpu.ReadVRAMFlat_Texture(0x60000 + (yoff << 9) + (xoff << 1)); // TODO: confirm color conversion u32 r = (val2 << 1) & 0x3E; if (r) r++; diff --git a/src/GPU3D_Soft.h b/src/GPU3D_Soft.h index 55a698b0..73d02e4f 100644 --- a/src/GPU3D_Soft.h +++ b/src/GPU3D_Soft.h @@ -430,16 +430,6 @@ private: s32 ycoverage, ycov_incr; }; - template - inline T ReadVRAM_Texture(u32 addr, const GPU& gpu) const - { - return *(T*)&gpu.VRAMFlat_Texture[addr & 0x7FFFF]; - } - template - inline T ReadVRAM_TexPal(u32 addr, const GPU& gpu) const - { - return *(T*)&gpu.VRAMFlat_TexPal[addr & 0x1FFFF]; - } u32 AlphaBlend(const GPU3D& gpu3d, u32 srccolor, u32 dstcolor, u32 alpha) const noexcept; struct RendererPolygon diff --git a/src/GPU3D_Texcache.cpp b/src/GPU3D_Texcache.cpp index 196009e6..a6a40a04 100644 --- a/src/GPU3D_Texcache.cpp +++ b/src/GPU3D_Texcache.cpp @@ -75,11 +75,11 @@ inline u32 ConvertRGB5ToRGB6(u16 val) } template -void ConvertBitmapTexture(u32 width, u32 height, u32* output, u8* texData) +void ConvertBitmapTexture(u32 width, u32 height, u32* output, u32 addr, GPU& gpu) { for (u32 i = 0; i < width*height; i++) { - u16 value = *(u16*)&texData[i * 2]; + u16 value = gpu.ReadVRAMFlat_Texture(addr + i * 2); switch (outputFmt) { @@ -96,28 +96,28 @@ void ConvertBitmapTexture(u32 width, u32 height, u32* output, u8* texData) } } -template void ConvertBitmapTexture(u32 width, u32 height, u32* output, u8* texData); +template void ConvertBitmapTexture(u32 width, u32 height, u32* output, u32 addr, GPU& gpu); template -void ConvertCompressedTexture(u32 width, u32 height, u32* output, u8* texData, u8* texAuxData, u16* palData) +void ConvertCompressedTexture(u32 width, u32 height, u32* output, u32 addr, u32 addrAux, u32 palAddr, GPU& gpu) { // we process a whole block at the time for (int y = 0; y < height / 4; y++) { for (int x = 0; x < width / 4; x++) { - u32 data = ((u32*)texData)[x + y * (width / 4)]; - u16 auxData = ((u16*)texAuxData)[x + y * (width / 4)]; + u32 data = gpu.ReadVRAMFlat_Texture(addr + (x + y * (width / 4))*4); + u16 auxData = gpu.ReadVRAMFlat_Texture(addrAux + (x + y * (width / 4))*2); - u32 paletteOffset = auxData & 0x3FFF; - u16 color0 = palData[paletteOffset*2] | 0x8000; - u16 color1 = palData[paletteOffset*2+1] | 0x8000; - u16 color2, color3; + u32 paletteOffset = palAddr + (auxData & 0x3FFF) * 4; + u16 color0 = gpu.ReadVRAMFlat_TexPal(paletteOffset) | 0x8000; + u16 color1 = gpu.ReadVRAMFlat_TexPal(paletteOffset+2) | 0x8000; + u16 color2 = gpu.ReadVRAMFlat_TexPal(paletteOffset+4) | 0x8000; + u16 color3 = gpu.ReadVRAMFlat_TexPal(paletteOffset+6) | 0x8000; switch ((auxData >> 14) & 0x3) { case 0: - color2 = palData[paletteOffset*2+2] | 0x8000; color3 = 0; break; case 1: @@ -137,8 +137,6 @@ void ConvertCompressedTexture(u32 width, u32 height, u32* output, u8* texData, u color3 = 0; break; case 2: - color2 = palData[paletteOffset*2+2] | 0x8000; - color3 = palData[paletteOffset*2+3] | 0x8000; break; case 3: { @@ -179,7 +177,8 @@ void ConvertCompressedTexture(u32 width, u32 height, u32* output, u8* texData, u { for (int i = 0; i < 4; i++) { - u16 color = (packed >> 16 * (data >> 2 * (i + j * 4))) & 0xFFFF; + u32 colorIdx = 16 * ((data >> 2 * (i + j * 4)) & 0x3); + u16 color = (packed >> colorIdx) & 0xFFFF; u32 res; switch (outputFmt) { @@ -197,20 +196,20 @@ void ConvertCompressedTexture(u32 width, u32 height, u32* output, u8* texData, u } } -template void ConvertCompressedTexture(u32, u32, u32*, u8*, u8*, u16*); +template void ConvertCompressedTexture(u32, u32, u32*, u32, u32, u32, GPU&); template -void ConvertAXIYTexture(u32 width, u32 height, u32* output, u8* texData, u16* palData) +void ConvertAXIYTexture(u32 width, u32 height, u32* output, u32 addr, u32 palAddr, GPU& gpu) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - u8 val = texData[x + y * width]; + u8 val = gpu.ReadVRAMFlat_Texture(addr + x + y * width); u32 idx = val & ((1 << Y) - 1); - u16 color = palData[idx]; + u16 color = gpu.ReadVRAMFlat_TexPal(palAddr + idx * 2); u32 alpha = (val >> Y) & ((1 << X) - 1); if (X != 5) alpha = alpha * 4 + alpha / 2; @@ -228,22 +227,24 @@ void ConvertAXIYTexture(u32 width, u32 height, u32* output, u8* texData, u16* pa } } -template void ConvertAXIYTexture(u32, u32, u32*, u8*, u16*); -template void ConvertAXIYTexture(u32, u32, u32*, u8*, u16*); +template void ConvertAXIYTexture(u32, u32, u32*, u32, u32, GPU&); +template void ConvertAXIYTexture(u32, u32, u32*, u32, u32, GPU&); template -void ConvertNColorsTexture(u32 width, u32 height, u32* output, u8* texData, u16* palData, bool color0Transparent) +void ConvertNColorsTexture(u32 width, u32 height, u32* output, u32 addr, u32 palAddr, bool color0Transparent, GPU& gpu) { for (int y = 0; y < height; y++) { - for (int x = 0; x < width / (8 / colorBits); x++) + for (int x = 0; x < width / (16 / colorBits); x++) { - u8 val = texData[x + y * (width / (8 / colorBits))]; + // smallest possible row is 8 pixels with 2bpp => fits in u16 + u16 val = gpu.ReadVRAMFlat_Texture(addr + 2 * (x + y * (width / (16 / colorBits)))); - for (int i = 0; i < 8 / colorBits; i++) + for (int i = 0; i < 16 / colorBits; i++) { - u32 index = (val >> (i * colorBits)) & ((1 << colorBits) - 1); - u16 color = palData[index]; + u32 index = val & ((1 << colorBits) - 1); + val >>= colorBits; + u16 color = gpu.ReadVRAMFlat_TexPal(palAddr + index * 2); bool transparent = color0Transparent && index == 0; u32 res; @@ -256,14 +257,14 @@ void ConvertNColorsTexture(u32 width, u32 height, u32* output, u8* texData, u16* case outputFmt_BGRA8: res = ConvertRGB5ToBGR8(color) | (transparent ? 0 : 0xFF000000); break; } - output[x * (8 / colorBits) + y * width + i] = res; + output[x * (16 / colorBits) + y * width + i] = res; } } } } -template void ConvertNColorsTexture(u32, u32, u32*, u8*, u16*, bool); -template void ConvertNColorsTexture(u32, u32, u32*, u8*, u16*, bool); -template void ConvertNColorsTexture(u32, u32, u32*, u8*, u16*, bool); +template void ConvertNColorsTexture(u32, u32, u32*, u32, u32, bool, GPU&); +template void ConvertNColorsTexture(u32, u32, u32*, u32, u32, bool, GPU&); +template void ConvertNColorsTexture(u32, u32, u32*, u32, u32, bool, GPU&); } \ No newline at end of file diff --git a/src/GPU3D_Texcache.h b/src/GPU3D_Texcache.h index 214c6254..f2cd6416 100644 --- a/src/GPU3D_Texcache.h +++ b/src/GPU3D_Texcache.h @@ -32,13 +32,13 @@ enum }; template -void ConvertBitmapTexture(u32 width, u32 height, u32* output, u8* texData); +void ConvertBitmapTexture(u32 width, u32 height, u32* output, u32 addr, GPU& gpu); template -void ConvertCompressedTexture(u32 width, u32 height, u32* output, u8* texData, u8* texAuxData, u16* palData); +void ConvertCompressedTexture(u32 width, u32 height, u32* output, u32 addr, u32 addrAux, u32 palAddr, GPU& gpu); template -void ConvertAXIYTexture(u32 width, u32 height, u32* output, u8* texData, u16* palData); +void ConvertAXIYTexture(u32 width, u32 height, u32* output, u32 addr, u32 palAddr, GPU& gpu); template -void ConvertNColorsTexture(u32 width, u32 height, u32* output, u8* texData, u16* palData, bool color0Transparent); +void ConvertNColorsTexture(u32 width, u32 height, u32* output, u32 addr, u32 palAddr, bool color0Transparent, GPU& gpu); template class Texcache @@ -48,6 +48,50 @@ public: : TexLoader(texloader) // probably better if this would be a move constructor??? {} + u64 MaskedHash(u8* vram, u32 vramSize, u32 addr, u32 size) + { + u64 hash = 0; + + while (size > 0) + { + u32 pieceSize; + if (addr + size > vramSize) + // wraps around, only do the part inside + pieceSize = vramSize - addr; + else + // fits completely inside + pieceSize = size; + + hash = XXH64(&vram[addr], pieceSize, hash); + + addr += pieceSize; + addr &= (vramSize - 1); + assert(size >= pieceSize); + size -= pieceSize; + } + + return hash; + } + + bool CheckInvalid(u32 start, u32 size, u64 oldHash, u64* dirty, u8* vram, u32 vramSize) + { + u32 startBit = start / VRAMDirtyGranularity; + u32 bitsCount = ((start + size + VRAMDirtyGranularity - 1) / VRAMDirtyGranularity) - startBit; + + u32 startEntry = startBit >> 6; + u64 entriesCount = ((startBit + bitsCount + 0x3F) >> 6) - startEntry; + for (u32 j = startEntry; j < startEntry + entriesCount; j++) + { + if (GetRangedBitMask(j, startBit, bitsCount) & dirty[j & ((vramSize / VRAMDirtyGranularity)-1)]) + { + if (MaskedHash(vram, vramSize, start, size) != oldHash) + return true; + } + } + + return false; + } + bool Update(GPU& gpu) { auto textureDirty = gpu.VRAMDirty_Texture.DeriveState(gpu.VRAMMap_Texture, gpu); @@ -66,40 +110,21 @@ public: { for (u32 i = 0; i < 2; i++) { - u32 startBit = entry.TextureRAMStart[i] / VRAMDirtyGranularity; - u32 bitsCount = ((entry.TextureRAMStart[i] + entry.TextureRAMSize[i] + VRAMDirtyGranularity - 1) / VRAMDirtyGranularity) - startBit; - - u32 startEntry = startBit >> 6; - u64 entriesCount = ((startBit + bitsCount + 0x3F) >> 6) - startEntry; - for (u32 j = startEntry; j < startEntry + entriesCount; j++) - { - if (GetRangedBitMask(j, startBit, bitsCount) & textureDirty.Data[j]) - { - u64 newTexHash = XXH3_64bits(&gpu.VRAMFlat_Texture[entry.TextureRAMStart[i]], entry.TextureRAMSize[i]); - - if (newTexHash != entry.TextureHash[i]) - goto invalidate; - } - } + if (CheckInvalid(entry.TextureRAMStart[i], entry.TextureRAMSize[i], + entry.TextureHash[i], + textureDirty.Data, + gpu.VRAMFlat_Texture, sizeof(gpu.VRAMFlat_Texture))) + goto invalidate; } } if (texPalChanged && entry.TexPalSize > 0) { - u32 startBit = entry.TexPalStart / VRAMDirtyGranularity; - u32 bitsCount = ((entry.TexPalStart + entry.TexPalSize + VRAMDirtyGranularity - 1) / VRAMDirtyGranularity) - startBit; - - u32 startEntry = startBit >> 6; - u64 entriesCount = ((startBit + bitsCount + 0x3F) >> 6) - startEntry; - for (u32 j = startEntry; j < startEntry + entriesCount; j++) - { - if (GetRangedBitMask(j, startBit, bitsCount) & texPalDirty.Data[j]) - { - u64 newPalHash = XXH3_64bits(&gpu.VRAMFlat_TexPal[entry.TexPalStart], entry.TexPalSize); - if (newPalHash != entry.TexPalHash) - goto invalidate; - } - } + if (CheckInvalid(entry.TexPalStart, entry.TexPalSize, + entry.TexPalHash, + texPalDirty.Data, + gpu.VRAMFlat_TexPal, sizeof(gpu.VRAMFlat_TexPal))) + goto invalidate; } it++; @@ -163,17 +188,13 @@ public: { entry.TextureRAMSize[0] = width*height*2; - ConvertBitmapTexture(width, height, DecodingBuffer, &gpu.VRAMFlat_Texture[addr]); + ConvertBitmapTexture(width, height, DecodingBuffer, addr, gpu); } else if (fmt == 5) { - u8* texData = &gpu.VRAMFlat_Texture[addr]; u32 slot1addr = 0x20000 + ((addr & 0x1FFFC) >> 1); if (addr >= 0x40000) slot1addr += 0x10000; - u8* texAuxData = &gpu.VRAMFlat_Texture[slot1addr]; - - u16* palData = (u16*)(gpu.VRAMFlat_TexPal + palBase*16); entry.TextureRAMSize[0] = width*height/16*4; entry.TextureRAMStart[1] = slot1addr; @@ -181,7 +202,7 @@ public: entry.TexPalStart = palBase*16; entry.TexPalSize = 0x10000; - ConvertCompressedTexture(width, height, DecodingBuffer, texData, texAuxData, palData); + ConvertCompressedTexture(width, height, DecodingBuffer, addr, slot1addr, entry.TexPalStart, gpu); } else { @@ -204,30 +225,29 @@ public: entry.TexPalStart = palAddr; entry.TexPalSize = numPalEntries*2; - u8* texData = &gpu.VRAMFlat_Texture[addr]; - u16* palData = (u16*)(gpu.VRAMFlat_TexPal + palAddr); - //assert(entry.TexPalStart+entry.TexPalSize <= 128*1024*1024); bool color0Transparent = texParam & (1 << 29); switch (fmt) { - case 1: ConvertAXIYTexture(width, height, DecodingBuffer, texData, palData); break; - case 6: ConvertAXIYTexture(width, height, DecodingBuffer, texData, palData); break; - case 2: ConvertNColorsTexture(width, height, DecodingBuffer, texData, palData, color0Transparent); break; - case 3: ConvertNColorsTexture(width, height, DecodingBuffer, texData, palData, color0Transparent); break; - case 4: ConvertNColorsTexture(width, height, DecodingBuffer, texData, palData, color0Transparent); break; + case 1: ConvertAXIYTexture(width, height, DecodingBuffer, addr, palAddr, gpu); break; + case 6: ConvertAXIYTexture(width, height, DecodingBuffer, addr, palAddr, gpu); break; + case 2: ConvertNColorsTexture(width, height, DecodingBuffer, addr, palAddr, color0Transparent, gpu); break; + case 3: ConvertNColorsTexture(width, height, DecodingBuffer, addr, palAddr, color0Transparent, gpu); break; + case 4: ConvertNColorsTexture(width, height, DecodingBuffer, addr, palAddr, color0Transparent, gpu); break; } } for (int i = 0; i < 2; i++) { if (entry.TextureRAMSize[i]) - entry.TextureHash[i] = XXH3_64bits(&gpu.VRAMFlat_Texture[entry.TextureRAMStart[i]], entry.TextureRAMSize[i]); + entry.TextureHash[i] = MaskedHash(gpu.VRAMFlat_Texture, sizeof(gpu.VRAMFlat_Texture), + entry.TextureRAMStart[i], entry.TextureRAMSize[i]); } if (entry.TexPalSize) - entry.TexPalHash = XXH3_64bits(&gpu.VRAMFlat_TexPal[entry.TexPalStart], entry.TexPalSize); + entry.TexPalHash = MaskedHash(gpu.VRAMFlat_TexPal, sizeof(gpu.VRAMFlat_TexPal), + entry.TexPalStart, entry.TexPalSize); auto& texArrays = TexArrays[widthLog2][heightLog2]; auto& freeTextures = FreeTextures[widthLog2][heightLog2]; From dfd633899286d44b6c9751564d2d47ab9c5c1415 Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Mon, 28 Oct 2024 01:28:52 +0100 Subject: [PATCH 47/47] it shouldn't be ifdef... How did that even compile here? --- src/frontend/qt_sdl/Window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 5c599e70..0af72ef6 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -265,7 +265,7 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : setAcceptDrops(true); setFocusPolicy(Qt::ClickFocus); -#ifdef QT_VERSION_MAJOR == 6 && WIN32 +#if QT_VERSION_MAJOR == 6 && WIN32 // The "windows11" theme has pretty massive padding around menubar items, this makes Config and Help not fit in a window at 1x screen sizing // So let's reduce the padding a bit. if (QApplication::style()->name() == "windows11")