From 190a335f38404abe80a54ef700f2378c7cbf1959 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 27 Jun 2023 21:14:15 -0700 Subject: [PATCH 01/29] Adding Lua functions to programmatically set shader code. --- src/gui/gui.cc | 79 +++++++++++++++++++++++++++++++++ src/gui/widgets/shader-editor.h | 12 +++-- 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/gui/gui.cc b/src/gui/gui.cc index a0b08888b..a596bd921 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -70,6 +70,7 @@ #include "imgui_stdlib.h" #include "json.hpp" #include "lua/glffi.h" +#include "lua/luafile.h" #include "lua/luawrapper.h" #include "magic_enum/include/magic_enum.hpp" #include "nanovg/src/nanovg.h" @@ -294,6 +295,84 @@ void PCSX::GUI::setLua(Lua L) { settings.pushValue(L); L.settable(); L.pop(); + auto setText = [this](Lua L, Widgets::ShaderEditor* editor, + void (Widgets::ShaderEditor::*setText)(std::string_view)) -> int { + if (L.gettop() != 1) { + return L.error(_("One argument needed to the setText* functions")); + } + std::optional text; + if (L.istable(-1)) { + L.getfield("_type"); + if (L.tostring(-1) == "File") { + L.pop(); + L.getfield("_wrapper"); + auto wrapper = *L.topointer(-1); + text = wrapper->file->readStringAt(wrapper->file->size(), 0); + } + L.pop(); + } + if (!text.has_value()) { + text = L.tostring(-1); + } + if (!text.has_value()) { + return L.error( + _("The argument to the setText* functions need to be convertible to a string, or be a File object")); + } + (editor->*setText)(text.value()); + auto status = editor->compile(this); + if (!status.isOk()) { + return L.error(fmt::format(f_("Error compiling new shader code: {}"), status.getError())); + } + return 0; + }; + L.getfieldtable("GUI"); + L.getfieldtable("OffscreenShader"); + L.declareFunc( + "setDefaults", + [this](Lua L) -> int { + m_offscreenShaderEditor.setDefaults(); + auto status = m_offscreenShaderEditor.compile(this); + if (!status.isOk()) { + m_offscreenShaderEditor.setFallbacks(); + m_offscreenShaderEditor.compile(this); + } + return 0; + }, + -1); + L.declareFunc( + "setTextVS", + [this, setText](Lua L) { return setText(L, &m_offscreenShaderEditor, &Widgets::ShaderEditor::setTextVS); }, -1); + L.declareFunc( + "setTextPS", + [this, setText](Lua L) { return setText(L, &m_offscreenShaderEditor, &Widgets::ShaderEditor::setTextPS); }, -1); + L.declareFunc( + "setTextL", + [this, setText](Lua L) { return setText(L, &m_offscreenShaderEditor, &Widgets::ShaderEditor::setTextL); }, -1); + L.pop(); + L.getfieldtable("OutputShader"); + L.declareFunc( + "setDefaults", + [this](Lua L) -> int { + m_outputShaderEditor.setDefaults(); + auto status = m_outputShaderEditor.compile(this); + if (!status.isOk()) { + m_outputShaderEditor.setFallbacks(); + m_outputShaderEditor.compile(this); + } + return 0; + }, + -1); + L.declareFunc( + "setTextVS", + [this, setText](Lua L) { return setText(L, &m_outputShaderEditor, &Widgets::ShaderEditor::setTextVS); }, -1); + L.declareFunc( + "setTextPS", + [this, setText](Lua L) { return setText(L, &m_outputShaderEditor, &Widgets::ShaderEditor::setTextPS); }, -1); + L.declareFunc( + "setTextL", + [this, setText](Lua L) { return setText(L, &m_outputShaderEditor, &Widgets::ShaderEditor::setTextL); }, -1); + L.pop(); + L.pop(); L.pop(); auto offscreenStatus = m_offscreenShaderEditor.compile(this); auto outputStatus = m_outputShaderEditor.compile(this); diff --git a/src/gui/widgets/shader-editor.h b/src/gui/widgets/shader-editor.h index 6af7ca5dc..67045249e 100644 --- a/src/gui/widgets/shader-editor.h +++ b/src/gui/widgets/shader-editor.h @@ -48,12 +48,16 @@ class ShaderEditor { bool m_show = false; - void setText(const char* VS, const char* PS, const char* L) { - m_vertexShaderEditor.setText(VS); - m_pixelShaderEditor.setText(PS); - m_luaEditor.setText(L); + void setText(std::string_view VS, std::string_view PS, std::string_view L) { + setTextVS(VS); + setTextPS(PS); + setTextL(L); } + void setTextVS(std::string_view VS) { m_vertexShaderEditor.setText(std::string(VS)); } + void setTextPS(std::string_view PS) { m_pixelShaderEditor.setText(std::string(PS)); } + void setTextL(std::string_view L) { m_luaEditor.setText(std::string(L)); } + void setDefaults(); void setFallbacks(); void init(); From 18d5a03e1169b28cf4c48b642bc7dea6fe8eb021 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Sun, 9 Jul 2023 10:07:37 -0700 Subject: [PATCH 02/29] Rephrasing status. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 99b3be434..b29a1ab2a 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Since the inception of this codebase, several people have contributed to it. Ple When Sony released the Playstation Classic recently, I came to realize two things: first, the state of the Playstation emulation isn't that great, and second, the only half-decent debugging tool still available for this console is that old telnet debugger I wrote eons ago, while other emulators out there for other consoles gained a lot of debugging superpowers. I think it was time for the Playstation emulation to get to better standards with regards to debuggability. I also felt I had a responsability to cleaning up some of the horrors I've introduced myself in the codebase long ago, and that made me cry a little looking at them. Hopefully, I got better at programming. Hopefully. ## Status? -The codebase still requires a lot of cleanup, and the current product isn't properly usable yet. Despite that, a lot can already be achieved using the product in its current state. If you want to help with localization, you can find the translation project [on transifex](https://www.transifex.com/grumpycoders/pcsx-redux/languages/). +The codebase still requires a lot of cleanup, and while the product is usable in its current state and lots can be achieved with it, there is still ways to go for reaching the first stable release. If you want to help with localization, you can find the translation project [on transifex](https://www.transifex.com/grumpycoders/pcsx-redux/languages/). ### What works? - Dynamic Recompiler (x86-64, experimental arm64 support) From f989a021b3733c037a64b80bd1777b4127f454e3 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 9 Jul 2023 11:42:00 -0700 Subject: [PATCH 03/29] Overhauling command line arguments for cleaner access. --- src/core/arguments.cc | 30 ++++ src/core/arguments.h | 58 +++++++ src/core/gdb-server.cc | 9 -- src/core/psxemulator.cc | 15 -- src/core/r3000a.cc | 10 +- src/core/system.h | 13 +- src/core/ui.h | 5 +- src/gui/gui.cc | 3 +- src/gui/gui.h | 2 +- src/main/main.cc | 229 +++++++++++++++------------ src/main/textui.cc | 3 +- src/main/textui.h | 2 +- vsprojects/core/core.vcxproj | 2 + vsprojects/core/core.vcxproj.filters | 6 + 14 files changed, 246 insertions(+), 141 deletions(-) create mode 100644 src/core/arguments.cc create mode 100644 src/core/arguments.h diff --git a/src/core/arguments.cc b/src/core/arguments.cc new file mode 100644 index 000000000..27f820bbe --- /dev/null +++ b/src/core/arguments.cc @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2023 PCSX-Redux authors * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "core/arguments.h" + +PCSX::Arguments::Arguments(const CommandLine::args& args) { + if (args.get("lua_stdout") || args.get("no-ui") || args.get("cli")) { + m_luaStdoutEnabled = true; + } + if (args.get("stdout") && !args.get("tui")) m_stdoutEnabled = true; + if (args.get("no-ui") || args.get("cli")) m_stdoutEnabled = true; + if (args.get("testmode") || args.get("no-gui-log")) m_guiLogsEnabled = false; + if (args.get("testmode")) m_testModeEnabled = true; +} diff --git a/src/core/arguments.h b/src/core/arguments.h new file mode 100644 index 000000000..75dde0255 --- /dev/null +++ b/src/core/arguments.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2023 PCSX-Redux authors * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#pragma once + +#include + +#include "flags.h" + +namespace PCSX { + +class Arguments { + public: + Arguments(const CommandLine::args& args); + Arguments(const Arguments&) = delete; + Arguments(Arguments&&) = delete; + Arguments& operator=(const Arguments&) = delete; + Arguments& operator=(Arguments&&) = delete; + + // Returns true if stdout should be enabled. + // Enabled with the flags -stdout (but not when -tui is used), -no-ui, or -cli. + bool isStdoutEnabled() const { return m_stdoutEnabled; } + + // Returns true if Lua should be displaying its console output to stdout. + // Enabled with the flags -lua_stdout, -no-ui, or -cli. + bool isLuaStdoutEnabled() const { return m_luaStdoutEnabled; } + + // Returns true if the GUI logs window should be enabled. + // Disabled with -testmode or -no-gui-log. + bool enableGUILogs() const { return m_guiLogsEnabled; } + + // Returns true if the the flag -testmode was used. + bool isTestModeEnabled() const { return m_testModeEnabled; } + + private: + bool m_luaStdoutEnabled = false; + bool m_stdoutEnabled = false; + bool m_guiLogsEnabled = true; + bool m_testModeEnabled = false; +}; + +} // namespace PCSX diff --git a/src/core/gdb-server.cc b/src/core/gdb-server.cc index 2e363f081..3eed2bee6 100644 --- a/src/core/gdb-server.cc +++ b/src/core/gdb-server.cc @@ -37,15 +37,6 @@ PCSX::GdbServer::GdbServer() : m_listener(g_system->m_eventBus) { m_listener.listen([this](const auto& event) { auto& args = g_system->getArgs(); auto& settings = g_emulator->settings.get(); - if (args.get("gdb", false)) { - settings.get() = true; - } - if (args.get("no-gdb", false)) { - settings.get() = false; - } - if (args.get("gdb-port").has_value()) { - settings.get() = args.get("gdb-port").value(); - } if (settings.get() && (m_serverStatus != SERVER_STARTED)) { startServer(g_system->getLoop(), settings.get()); } diff --git a/src/core/psxemulator.cc b/src/core/psxemulator.cc index aef5413b2..f3c375d93 100644 --- a/src/core/psxemulator.cc +++ b/src/core/psxemulator.cc @@ -124,23 +124,8 @@ int PCSX::Emulator::init() { const auto& args = g_system->getArgs(); - if (args.get("openglgpu")) { - settings.get() = true; - } - if (args.get("softgpu")) { - settings.get() = false; - } - m_gpu = settings.get() ? GPU::getOpenGL() : GPU::getSoft(); - // Enable or disable Kiosk Mode if command line flags are set - if (args.get("kiosk")) { - settings.get() = true; - } - if (args.get("no-kiosk")) { - settings.get() = false; - } - setPGXPMode(m_config.PGXP_Mode); m_sio->init(); return ret; diff --git a/src/core/r3000a.cc b/src/core/r3000a.cc index 59cd7caaa..7e48569bf 100644 --- a/src/core/r3000a.cc +++ b/src/core/r3000a.cc @@ -40,12 +40,9 @@ int PCSX::R3000Acpu::psxInit() { g_system->printf(_("Copyright (C) 2019-2023 PCSX-Redux authors\n")); const auto& args = g_system->getArgs(); - if (args.get("interpreter")) - g_emulator->m_cpu = Cpus::Interpreted(); - else if (args.get("dynarec")) - g_emulator->m_cpu = Cpus::DynaRec(); - else if (g_emulator->settings.get()) + if (g_emulator->settings.get()) { g_emulator->m_cpu = Cpus::DynaRec(); + } if (!g_emulator->m_cpu) g_emulator->m_cpu = Cpus::Interpreted(); @@ -244,7 +241,8 @@ void PCSX::R3000Acpu::exception(uint32_t code, bool bd, bool cop0) { } } ec = 1 << ec; - if (!g_system->testmode() && ((debugSettings.get() & ec) != 0)) { + if (!g_system->getArgs().isTestModeEnabled() && + ((debugSettings.get() & ec) != 0)) { auto name = magic_enum::enum_name(e.value()); g_system->printf(fmt::format("First chance exception: {} from 0x{:08x}\n", name, m_regs.pc).c_str()); g_system->pause(true); diff --git a/src/core/system.h b/src/core/system.h index 38c33e3e9..63a30ab1f 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -29,7 +29,7 @@ #include #include -#include "flags.h" +#include "core/arguments.h" #include "fmt/format.h" #include "fmt/printf.h" #include "imgui.h" @@ -122,25 +122,25 @@ class System { virtual void hardReset() = 0; // Putc used by bios syscalls virtual void biosPutc(int c) = 0; - virtual const CommandLine::args &getArgs() = 0; + virtual const Arguments &getArgs() = 0; // Legacy printf stuff; needs to be replaced with loggers template - void printf(const char *format, const Args &... args) { + void printf(const char *format, const Args &...args) { std::string s = fmt::sprintf(format, args...); printf(std::move(s)); } virtual void printf(std::string &&) = 0; // Add a log line template - void log(LogClass logClass, const char *format, const Args &... args) { + void log(LogClass logClass, const char *format, const Args &...args) { std::string s = fmt::sprintf(format, args...); log(logClass, std::move(s)); } virtual void log(LogClass, std::string &&) = 0; // Display a popup message to the user template - void message(const char *format, const Args &... args) { + void message(const char *format, const Args &...args) { std::string s = fmt::sprintf(format, args...); message(std::move(s)); } @@ -240,8 +240,6 @@ class System { uv_loop_t *getLoop() { return &m_loop; } - bool testmode() { return m_testmode; } - private: uv_loop_t m_loop; std::map m_i18n; @@ -261,7 +259,6 @@ class System { std::filesystem::path m_binDir; PCSX::VersionInfo m_version; bool m_emergencyExit = true; - bool m_testmode = false; }; extern System *g_system; diff --git a/src/core/ui.h b/src/core/ui.h index 8f5df3f02..889b675ed 100644 --- a/src/core/ui.h +++ b/src/core/ui.h @@ -19,13 +19,14 @@ #pragma once +#include #include #include #include "core/system.h" +#include "flags.h" #include "json.hpp" #include "lua/luawrapper.h" -#include "flags.h" namespace PCSX { @@ -38,7 +39,7 @@ class UI { virtual void addNotification(const std::string ¬ification) = 0; virtual bool addLog(LogClass logClass, const std::string &msg) = 0; virtual void addLuaLog(const std::string &msg, bool error) = 0; - virtual void init() = 0; + virtual void init(std::function applyArguments) = 0; virtual void setLua(Lua L) = 0; virtual void close() = 0; virtual void update(bool vsync = false) = 0; diff --git a/src/gui/gui.cc b/src/gui/gui.cc index a596bd921..46a2ea9b4 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -411,7 +411,7 @@ void PCSX::GUI::setDefaultShaders() { m_outputShaderEditor.reset(this); } -void PCSX::GUI::init() { +void PCSX::GUI::init(std::function applyArguments) { int result; if (m_args.get("noshaders", false)) { @@ -566,6 +566,7 @@ void PCSX::GUI::init() { saveCfg(); } + applyArguments(); finishLoadSettings(); if (!m_args.get("noupdate") && emuSettings.get() && diff --git a/src/gui/gui.h b/src/gui/gui.h index 144382ffe..70a2eb9f6 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -214,7 +214,7 @@ class GUI final : public UI { assert(s_gui == this); s_gui = nullptr; } - void init(); + void init(std::function applyArguments) override; void setLua(Lua L); void close(); void update(bool vsync = false); diff --git a/src/main/main.cc b/src/main/main.cc index b45556488..efe984bc7 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -22,6 +22,7 @@ #include #include +#include "core/arguments.h" #include "core/cdrom.h" #include "core/gpu.h" #include "core/logger.h" @@ -51,42 +52,42 @@ class SystemImpl final : public PCSX::System { } } virtual void message(std::string &&s) final override { - if (!m_noGuiLog) s_ui->addNotification(s.c_str()); + if (m_args.enableGUILogs()) s_ui->addNotification(s.c_str()); if (s_ui->addLog(PCSX::LogClass::UI, s)) { - if (m_enableStdout) ::printf("%s", s.c_str()); + if (m_args.isStdoutEnabled()) ::fputs(s.c_str(), stdout); m_eventBus->signal(PCSX::Events::LogMessage{PCSX::LogClass::UI, s}); if (m_logfile) m_logfile->write(std::move(s)); } } virtual void log(PCSX::LogClass logClass, std::string &&s) final override { - if (!m_noGuiLog) { + if (m_args.enableGUILogs()) { if (!s_ui->addLog(logClass, s)) return; } - if (m_enableStdout) ::printf("%s", s.c_str()); + if (m_args.isStdoutEnabled()) ::fputs(s.c_str(), stdout); m_eventBus->signal(PCSX::Events::LogMessage{logClass, s}); if (m_logfile) m_logfile->write(std::move(s)); } virtual void printf(std::string &&s) final override { - if (!m_noGuiLog) { + if (m_args.enableGUILogs()) { if (!s_ui->addLog(PCSX::LogClass::UNCATEGORIZED, s)) return; } - if (m_enableStdout) ::printf("%s", s.c_str()); + if (m_args.isStdoutEnabled()) ::fputs(s.c_str(), stdout); m_eventBus->signal(PCSX::Events::LogMessage{PCSX::LogClass::UNCATEGORIZED, s}); if (m_logfile) m_logfile->write(std::move(s)); } virtual void luaMessage(const std::string &s, bool error) final override { - if (!m_noGuiLog) { + if (m_args.enableGUILogs()) { s_ui->addLuaLog(s, error); } - if ((error && m_inStartup) || args.get("lua_stdout", false) || args.get("no-ui", false) || - args.get("cli", false)) { + if ((error && m_inStartup) || m_args.isLuaStdoutEnabled()) { if (error) { - fprintf(stderr, "%s\n", s.c_str()); + fputs(s.c_str(), stderr); + fputc('\n', stderr); } else { - fprintf(stdout, "%s\n", s.c_str()); + puts(s.c_str()); } } } @@ -115,7 +116,7 @@ class SystemImpl final : public PCSX::System { virtual void purgeAllEvents() final override { uv_run(getLoop(), UV_RUN_DEFAULT); } virtual void testQuit(int code) final override { - if (testmode()) { + if (m_args.isTestModeEnabled()) { quit(code); } else { PCSX::System::log(PCSX::LogClass::UI, "PSX software requested an exit with code %i\n", code); @@ -123,13 +124,13 @@ class SystemImpl final : public PCSX::System { } } - virtual const CommandLine::args &getArgs() final override { return args; } + virtual const PCSX::Arguments &getArgs() final override { return m_args; } std::string m_putcharBuffer; PCSX::IO m_logfile; + const PCSX::Arguments m_args; public: - void setTestmode() { m_testmode = true; } void setBinDir(std::filesystem::path path) { m_binDir = path; m_version.loadFromFile(new PCSX::PosixFile(path / "version.json")); @@ -143,7 +144,7 @@ class SystemImpl final : public PCSX::System { } } - explicit SystemImpl(const CommandLine::args &args) : args(args) {} + explicit SystemImpl(const CommandLine::args &args) : m_args(args) {} ~SystemImpl() {} void setEmergencyExit() { m_emergencyExit = true; } @@ -151,15 +152,9 @@ class SystemImpl final : public PCSX::System { void useLogfile(const PCSX::u8string &filename) { m_logfile.setFile(new PCSX::UvFile(filename, PCSX::FileOps::TRUNCATE)); } - - bool m_enableStdout = false; - const CommandLine::args &args; bool m_inStartup = true; - bool m_noGuiLog = false; }; -using json = nlohmann::json; - struct Cleaner { Cleaner(std::function &&f) : f(std::move(f)) {} ~Cleaner() { f(); } @@ -176,7 +171,7 @@ int pcsxMain(int argc, char **argv) { PCSX::UvThreadOp::UvThread uvThread; #if defined(_WIN32) || defined(_WIN64) - if (args.get("stdout", false) || args.get("no-ui", false) || args.get("cli", false)) { + if (args.get("stdout") || args.get("no-ui") || args.get("cli")) { if (AllocConsole()) { freopen("CONIN$", "r", stdin); freopen("CONOUT$", "w", stdout); @@ -194,17 +189,9 @@ int pcsxMain(int argc, char **argv) { // Creating the "system" global object first, making sure anything logging-related is // enabled as much as possible. SystemImpl *system = new SystemImpl(args); - if (args.get("testmode", false)) { - system->setTestmode(); - } - if (args.get("stdout", false) && !args.get("tui", false)) system->m_enableStdout = true; - if (args.get("no-ui", false) || args.get("cli", false)) system->m_enableStdout = true; const auto &logfileArgOpt = args.get("logfile"); const PCSX::u8string logfileArg = MAKEU8(logfileArgOpt.has_value() ? logfileArgOpt->c_str() : ""); if (!logfileArg.empty()) system->useLogfile(logfileArg); - if (args.get("testmode", false) || args.get("no-gui-log", false) || args.get("cli", false)) { - system->m_noGuiLog = true; - } PCSX::g_system = system; std::filesystem::path self = argv[0]; std::filesystem::path binDir = std::filesystem::absolute(self).parent_path(); @@ -212,7 +199,7 @@ int pcsxMain(int argc, char **argv) { system->loadAllLocales(); // This is another early out, which can only be done once we have a system object. - if (args.get("version", false)) { + if (args.get("version")) { auto &version = system->getVersion(); if (version.failed()) { fmt::print("Failed to load version.json\n"); @@ -229,79 +216,117 @@ int pcsxMain(int argc, char **argv) { PCSX::Emulator *emulator = new PCSX::Emulator(); PCSX::g_emulator = emulator; - s_ui = args.get("no-ui", false) || args.get("cli", false) - ? reinterpret_cast(new PCSX::TUI(args)) - : reinterpret_cast(new PCSX::GUI(args)); + s_ui = args.get("no-ui") || args.get("cli") ? reinterpret_cast(new PCSX::TUI(args)) + : reinterpret_cast(new PCSX::GUI(args)); // Settings will be loaded after this initialization. - s_ui->init(); - // After settings are loaded, we're fine setting the SPU part of the emulation. - emulator->m_spu->init(); - // Start tweaking / sanitizing settings a bit, while continuing to parse the command line - // to handle overrides properly. - auto &emuSettings = emulator->settings; - auto &debugSettings = emuSettings.get(); - if (emuSettings.get().empty()) { - emuSettings.get() = MAKEU8(u8"memcard1.mcd"); - } + s_ui->init([&emulator, &args, &system]() { + // Start tweaking / sanitizing settings a bit, while continuing to parse the command line + // to handle overrides properly. + auto &emuSettings = emulator->settings; + auto &debugSettings = emuSettings.get(); + if (emuSettings.get().empty()) { + emuSettings.get() = MAKEU8(u8"memcard1.mcd"); + } - if (emuSettings.get().empty()) { - emuSettings.get() = MAKEU8(u8"memcard2.mcd"); - } + if (emuSettings.get().empty()) { + emuSettings.get() = MAKEU8(u8"memcard2.mcd"); + } - auto argPath1 = args.get("memcard1"); - auto argPath2 = args.get("memcard2"); - if (argPath1.has_value()) emuSettings.get().value = argPath1.value(); - if (argPath2.has_value()) emuSettings.get().value = argPath1.value(); - PCSX::u8string path1 = emuSettings.get().string(); - PCSX::u8string path2 = emuSettings.get().string(); + auto argPath1 = args.get("memcard1"); + auto argPath2 = args.get("memcard2"); + if (argPath1.has_value()) emuSettings.get() = argPath1.value(); + if (argPath2.has_value()) emuSettings.get() = argPath1.value(); + PCSX::u8string path1 = emuSettings.get().string(); + PCSX::u8string path2 = emuSettings.get().string(); - emulator->m_sio->loadMcds(path1, path2); - auto biosCfg = args.get("bios"); - if (biosCfg.has_value()) emuSettings.get() = biosCfg.value(); + emulator->m_sio->loadMcds(path1, path2); + auto biosCfg = args.get("bios"); + if (biosCfg.has_value()) emuSettings.get() = biosCfg.value(); - system->activateLocale(emuSettings.get()); + system->activateLocale(emuSettings.get()); - if (args.get("debugger", false)) { - debugSettings.get().value = true; - } + if (args.get("debugger")) { + debugSettings.get() = true; + } + if (args.get("no-debugger")) { + debugSettings.get() = false; + } - if (args.get("no-debugger", false)) { - debugSettings.get().value = false; - } + if (args.get("trace")) { + debugSettings.get() = true; + } + if (args.get("no-trace")) { + debugSettings.get() = false; + } - if (args.get("trace", false)) { - debugSettings.get().value = true; - } + if (args.get("8mb")) { + emuSettings.get() = true; + } + if (args.get("2mb")) { + emuSettings.get() = false; + } - if (args.get("no-trace", false)) { - debugSettings.get().value = false; - } + if (args.get("fastboot")) { + emuSettings.get() = true; + } + if (args.get("no-fastboot")) { + emuSettings.get() = false; + } - if (args.get("8mb", false)) { - emuSettings.get().value = true; - } + if (args.get("gdb")) { + debugSettings.get() = true; + } + if (args.get("no-gdb")) { + debugSettings.get() = false; + } - if (args.get("fastboot", false)) { - emuSettings.get().value = true; - } + if (args.get("gdb-port")) { + debugSettings.get() = args.get("gdb-port").value(); + } - if (args.get("no-fastboot", false)) { - emuSettings.get().value = false; - } + auto argPCdrvBase = args.get("pcdrvbase"); + if (args.get("pcdrv")) { + debugSettings.get() = true; + } + if (args.get("no-pcdrv")) { + debugSettings.get() = false; + } + if (argPCdrvBase.has_value()) { + debugSettings.get() = argPCdrvBase.value(); + } + + if (args.get("dynarec")) { + emuSettings.get() = true; + } + if (args.get("interpreted")) { + emuSettings.get() = false; + } + + if (args.get("openglgpu")) { + emuSettings.get() = true; + } + + if (args.get("softgpu")) { + emuSettings.get() = false; + } - // Now it's time to mount our filesystems; iso and pcdrv. + if (args.get("kiosk")) { + emuSettings.get() = true; + } + if (args.get("no-kiosk")) { + emuSettings.get() = false; + } + }); + + // Now it's time to mount our iso filesystem std::filesystem::path isoToOpen = args.get("iso", ""); if (isoToOpen.empty()) isoToOpen = args.get("loadiso", ""); if (isoToOpen.empty()) isoToOpen = args.get("disk", ""); - if (!isoToOpen.empty()) PCSX::g_emulator->m_cdrom->setIso(new PCSX::CDRIso(isoToOpen)); - PCSX::g_emulator->m_cdrom->check(); - auto argPCdrvBase = args.get("pcdrvbase"); - if (args.get("pcdrv", false)) { - debugSettings.get().value = true; - } - if (argPCdrvBase.has_value()) { - debugSettings.get().value = argPCdrvBase.value(); - } + if (!isoToOpen.empty()) emulator->m_cdrom->setIso(new PCSX::CDRIso(isoToOpen)); + emulator->m_cdrom->check(); + + // After settings are loaded, we're fine setting the SPU part of the emulation. + emulator->m_spu->init(); // Make sure the Lua environment is set. emulator->setLua(); @@ -310,6 +335,7 @@ int pcsxMain(int argc, char **argv) { assert(emulator->m_lua->gettop() == 0); // Starting up the whole emulator; we delay setting the GPU only now because why not. + auto &emuSettings = emulator->settings; emulator->m_spu->open(); emulator->init(); emulator->m_gpu->init(s_ui); @@ -319,7 +345,7 @@ int pcsxMain(int argc, char **argv) { emulator->reset(); // Looking at setting up what to run exactly within the emulator, if requested. - if (args.get("run", false)) system->resume(); + if (args.get("run")) system->resume(); s_ui->m_exeToLoad.set(MAKEU8(args.get("loadexe", "").c_str())); if (s_ui->m_exeToLoad.empty()) s_ui->m_exeToLoad.set(MAKEU8(args.get("exe", "").c_str())); @@ -347,16 +373,25 @@ int pcsxMain(int argc, char **argv) { PCSX::g_system = nullptr; }); try { - // Before going into the main loop, let's run all of the Lua "exec" commands - // specified on the command line. + // Before going into the main loop, let's first load all of the Lua files + // from the command-line specified using the -dofile switch. + auto dofiles = args.values("dofile"); + for (auto &dofile : dofiles) { + std::string name = std::string(dofile); + std::ifstream in(name, std::ifstream::in); + if (!in) { + throw std::runtime_error("Couldn't load file " + name); + } + std::ostringstream code; + code << in.rdbuf(); + in.close(); + emulator->m_lua->load(code.str(), name.c_str()); + } + + // Then run all of the Lua "exec" commands. auto luaexecs = args.values("exec"); for (auto &luaexec : luaexecs) { - try { - emulator->m_lua->load(luaexec.data(), "cmdline", false); - emulator->m_lua->pcall(); - } catch (std::exception &e) { - fprintf(stderr, "%s\n", e.what()); - } + emulator->m_lua->load(luaexec.data(), "cmdline"); } system->m_inStartup = false; diff --git a/src/main/textui.cc b/src/main/textui.cc index 7481e1866..68dfe83f4 100644 --- a/src/main/textui.cc +++ b/src/main/textui.cc @@ -29,8 +29,9 @@ bool PCSX::TUI::addLog(LogClass logClass, const std::string &msg) { return true; void PCSX::TUI::addLuaLog(const std::string &msg, bool error) {} -void PCSX::TUI::init() { +void PCSX::TUI::init(std::function applyArguments) { loadSettings(); + applyArguments(); finishLoadSettings(); } diff --git a/src/main/textui.h b/src/main/textui.h index ebd81e3e3..014005fb8 100644 --- a/src/main/textui.h +++ b/src/main/textui.h @@ -29,7 +29,7 @@ class TUI : public UI { ~TUI(); bool addLog(LogClass logClass, const std::string &msg) override; void addLuaLog(const std::string &msg, bool error) override; - void init() override; + void init(std::function applyArguments) override; void setLua(Lua L) override; void close() override; void update(bool vsync = false) override; diff --git a/vsprojects/core/core.vcxproj b/vsprojects/core/core.vcxproj index 7d4e959ca..e73f0f9b7 100644 --- a/vsprojects/core/core.vcxproj +++ b/vsprojects/core/core.vcxproj @@ -235,6 +235,7 @@ + @@ -283,6 +284,7 @@ + diff --git a/vsprojects/core/core.vcxproj.filters b/vsprojects/core/core.vcxproj.filters index cb3169dd6..713bdfdd3 100644 --- a/vsprojects/core/core.vcxproj.filters +++ b/vsprojects/core/core.vcxproj.filters @@ -139,6 +139,9 @@ Source Files + + Source Files + @@ -276,6 +279,9 @@ Header Files + + Header Files + From 511538965cd367cc0204073cae76a310696abd32 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Sun, 9 Jul 2023 18:58:13 -0700 Subject: [PATCH 04/29] Derp. --- src/core/r3000a.cc | 1 + src/main/main.cc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/r3000a.cc b/src/core/r3000a.cc index 7e48569bf..2df8fb117 100644 --- a/src/core/r3000a.cc +++ b/src/core/r3000a.cc @@ -47,6 +47,7 @@ int PCSX::R3000Acpu::psxInit() { if (!g_emulator->m_cpu) g_emulator->m_cpu = Cpus::Interpreted(); PGXP_Init(); + g_system->printf(_("CPU type: %s\n"), g_emulator->m_cpu->getName().c_str()); return g_emulator->m_cpu->Init(); } diff --git a/src/main/main.cc b/src/main/main.cc index efe984bc7..c93f5d056 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -298,7 +298,7 @@ int pcsxMain(int argc, char **argv) { if (args.get("dynarec")) { emuSettings.get() = true; } - if (args.get("interpreted")) { + if (args.get("interpreter")) { emuSettings.get() = false; } From c477cc9b2e9ed583f7b905ee7cb7d752ec38e68b Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 9 Jul 2023 21:35:36 -0700 Subject: [PATCH 05/29] More arguments cleanup, and adding portable flag computation. --- src/core/arguments.cc | 11 ++++++++ src/core/arguments.h | 34 ++++++++++++++++++++++++- src/core/ui.cc | 8 +++--- src/core/ui.h | 4 +-- src/gui/gui.cc | 58 +++++++++++++++++++++---------------------- src/gui/gui.h | 3 +-- src/main/main.cc | 12 ++++----- src/main/textui.cc | 2 +- src/main/textui.h | 2 +- 9 files changed, 86 insertions(+), 48 deletions(-) diff --git a/src/core/arguments.cc b/src/core/arguments.cc index 27f820bbe..660ad3cf4 100644 --- a/src/core/arguments.cc +++ b/src/core/arguments.cc @@ -19,6 +19,8 @@ #include "core/arguments.h" +#include + PCSX::Arguments::Arguments(const CommandLine::args& args) { if (args.get("lua_stdout") || args.get("no-ui") || args.get("cli")) { m_luaStdoutEnabled = true; @@ -27,4 +29,13 @@ PCSX::Arguments::Arguments(const CommandLine::args& args) { if (args.get("no-ui") || args.get("cli")) m_stdoutEnabled = true; if (args.get("testmode") || args.get("no-gui-log")) m_guiLogsEnabled = false; if (args.get("testmode")) m_testModeEnabled = true; + if (args.get("portable")) m_portable = true; + if (std::filesystem::exists("pcsx.json")) m_portable = true; + if (std::filesystem::exists("Makefile")) m_portable = true; + if (std::filesystem::exists(std::filesystem::path("..") / "pcsx-redux.sln")) m_portable = true; + if (args.get("safe") || args.get("testmode") || args.get("cli")) m_safeModeEnabled = true; + if (args.get("resetui")) m_uiResetRequested = true; + if (args.get("noshaders")) m_shadersDisabled = true; + if (args.get("noupdate")) m_updateDisabled = true; + if (args.get("noviewports")) m_viewportsDisabled = true; } diff --git a/src/core/arguments.h b/src/core/arguments.h index 75dde0255..6fe3e8354 100644 --- a/src/core/arguments.h +++ b/src/core/arguments.h @@ -43,16 +43,48 @@ class Arguments { // Returns true if the GUI logs window should be enabled. // Disabled with -testmode or -no-gui-log. - bool enableGUILogs() const { return m_guiLogsEnabled; } + bool isGUILogsEnabled() const { return m_guiLogsEnabled; } // Returns true if the the flag -testmode was used. bool isTestModeEnabled() const { return m_testModeEnabled; } + // Returns true if the the flag -portable was used, if the executable is + // located in the same directory as the pcsx.json file, or if the + // executable is being run from its source tree. + bool isPortable() const { return m_portable; } + + // Returns true if the safe mode was enabled. This implies + // that the pcsx.json file won't be loaded. + // Enabled with the flags -safe, -testmode, or -cli. + bool isSafeModeEnabled() const { return m_safeModeEnabled; } + + // Returns true if the user requested to reset the UI. + // Enabled with the flag -resetui. + bool isUIResetRequested() const { return m_uiResetRequested; } + + // Returns true if the user requested that no shaders be used. + // Enabled with the flag -noshaders. + bool isShadersDisabled() const { return m_shadersDisabled; } + + // Returns true if the user requested that no update be performed. + // Enabled with the flag -noupdate. + bool isUpdateDisabled() const { return m_updateDisabled; } + + // Returns true if the user requested that viewports be disabled. + // Enabled with the flag -noviewports. + bool isViewportsDisabled() const { return m_viewportsDisabled; } + private: bool m_luaStdoutEnabled = false; bool m_stdoutEnabled = false; bool m_guiLogsEnabled = true; bool m_testModeEnabled = false; + bool m_portable = false; + bool m_safeModeEnabled = false; + bool m_uiResetRequested = false; + bool m_shadersDisabled = false; + bool m_updateDisabled = false; + bool m_viewportsDisabled = false; }; } // namespace PCSX diff --git a/src/core/ui.cc b/src/core/ui.cc index fd3fc921a..20285d298 100644 --- a/src/core/ui.cc +++ b/src/core/ui.cc @@ -28,15 +28,14 @@ #include "core/spu.h" #include "supportpsx/binloader.h" -PCSX::UI::UI(const CommandLine::args &args) : m_args(args), m_listener(g_system->m_eventBus) { +PCSX::UI::UI() : m_listener(g_system->m_eventBus) { m_listener.listen([this](const auto& event) { shellReached(); }); } bool PCSX::UI::loadSettings() { std::ifstream cfg("pcsx.json"); auto& emuSettings = g_emulator->settings; - bool safeMode = m_args.get("safe", false) || m_args.get("testmode", false) || m_args.get("cli", false); - if (cfg.is_open() && !safeMode) { + if (cfg.is_open() && !g_system->getArgs().isSafeModeEnabled()) { try { cfg >> m_settingsJson; } catch (...) { @@ -55,10 +54,9 @@ bool PCSX::UI::loadSettings() { } void PCSX::UI::finishLoadSettings() { - bool safeMode = m_args.get("safe", false) || m_args.get("testmode", false) || m_args.get("cli", false); auto& emuSettings = g_emulator->settings; g_system->activateLocale(emuSettings.get()); - g_system->m_eventBus->signal(Events::SettingsLoaded{safeMode}); + g_system->m_eventBus->signal(Events::SettingsLoaded{g_system->getArgs().isSafeModeEnabled()}); } void PCSX::UI::setLuaCommon(Lua L) { diff --git a/src/core/ui.h b/src/core/ui.h index 889b675ed..5c4a36389 100644 --- a/src/core/ui.h +++ b/src/core/ui.h @@ -24,7 +24,6 @@ #include #include "core/system.h" -#include "flags.h" #include "json.hpp" #include "lua/luawrapper.h" @@ -34,7 +33,7 @@ enum class LogClass : unsigned; class UI { public: - UI(const CommandLine::args &args); + UI(); virtual ~UI() = default; virtual void addNotification(const std::string ¬ification) = 0; virtual bool addLog(LogClass logClass, const std::string &msg) = 0; @@ -64,7 +63,6 @@ class UI { protected: using json = nlohmann::json; json m_settingsJson; - const CommandLine::args &m_args; EventBus::Listener m_listener; bool loadSettings(); diff --git a/src/gui/gui.cc b/src/gui/gui.cc index 46a2ea9b4..f5273822e 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -414,30 +414,29 @@ void PCSX::GUI::setDefaultShaders() { void PCSX::GUI::init(std::function applyArguments) { int result; - if (m_args.get("noshaders", false)) { - m_disableShaders = true; - } - s_imguiUserErrorFunctor = [this](const char* msg) { m_gotImguiUserError = true; m_imguiUserError = msg; }; - m_luaConsole.setCmdExec([this](const std::string& cmd) { + bool luaStdout = g_system->getArgs().isLuaStdoutEnabled(); + m_luaConsole.setCmdExec([this, luaStdout](const std::string& cmd) { ScopedOnlyLog scopedOnlyLog(this); try { g_emulator->m_lua->load(cmd, "console", false); g_emulator->m_lua->pcall(); for (const auto& error : m_glErrors) { m_luaConsole.addError(error); - if (m_args.get("lua_stdout", false)) { - fprintf(stderr, "%s\n", error.c_str()); + if (luaStdout) { + fputs(error.c_str(), stderr); + fputc('\n', stderr); } } m_glErrors.clear(); } catch (std::exception& e) { m_luaConsole.addError(e.what()); - if (m_args.get("lua_stdout", false)) { - fprintf(stderr, "%s\n", e.what()); + if (luaStdout) { + fputs(e.what(), stderr); + fputc('\n', stderr); } } }); @@ -529,12 +528,10 @@ void PCSX::GUI::init(std::function applyArguments) { auto& io = ImGui::GetIO(); { io.IniFilename = nullptr; - auto& emuSettings = PCSX::g_emulator->settings; - const bool resetUI = m_args.get("resetui", false); - bool safeMode = - m_args.get("safe", false) || m_args.get("testmode", false) || m_args.get("cli", false); + auto& emuSettings = g_emulator->settings; if (loadSettings()) { - if (!resetUI && (m_settingsJson.count("imgui") == 1) && m_settingsJson["imgui"].is_string()) { + if (!g_system->getArgs().isUIResetRequested() && (m_settingsJson.count("imgui") == 1) && + m_settingsJson["imgui"].is_string()) { std::string imguicfg = m_settingsJson["imgui"]; ImGui::LoadIniSettingsFromMemory(imguicfg.c_str(), imguicfg.size()); } @@ -546,13 +543,13 @@ void PCSX::GUI::init(std::function applyArguments) { } auto& windowSizeX = settings.get(); auto& windowSizeY = settings.get(); - if (windowSizeX <= 0 || resetUI) { + if (windowSizeX <= 0 || g_system->getArgs().isUIResetRequested()) { windowSizeX.reset(); } - if (windowSizeY <= 0 || resetUI) { + if (windowSizeY <= 0 || g_system->getArgs().isUIResetRequested()) { windowSizeY.reset(); } - if (resetUI) { + if (g_system->getArgs().isUIResetRequested()) { settings.get().reset(); settings.get().reset(); } @@ -569,7 +566,7 @@ void PCSX::GUI::init(std::function applyArguments) { applyArguments(); finishLoadSettings(); - if (!m_args.get("noupdate") && emuSettings.get() && + if (!g_system->getArgs().isUpdateDisabled() && emuSettings.get() && !g_system->getVersion().failed()) { m_update.downloadUpdateInfo( g_system->getVersion(), @@ -591,7 +588,7 @@ void PCSX::GUI::init(std::function applyArguments) { // io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; #ifndef __linux__ - if (!m_args.get("noviewports")) { + if (!g_system->getArgs().isViewportsDisabled()) { io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; } #endif @@ -637,7 +634,7 @@ void PCSX::GUI::init(std::function applyArguments) { ImGui_ImplOpenGL3_Init(m_hasCoreProfile ? GL_SHADER_VERSION : nullptr); if (glDebugMessageCallback && - (g_emulator->settings.get() || m_args.get("testmode", false))) { + (g_emulator->settings.get() || g_system->getArgs().isTestModeEnabled())) { m_reportGLErrors = true; glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glEnable(GL_DEBUG_OUTPUT); @@ -1014,7 +1011,7 @@ void PCSX::GUI::endFrame() { ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus); - if (m_disableShaders) { + if (g_system->getArgs().isShadersDisabled()) { ImGui::Image(texture, logicalRenderSize, ImVec2(0, 0), ImVec2(1, 1)); } else { m_outputShaderEditor.renderWithImgui(this, texture, m_renderSize, logicalRenderSize); @@ -1035,7 +1032,7 @@ void PCSX::GUI::endFrame() { } ImGuiHelpers::normalizeDimensions(textureSize, renderRatio); ImTextureID texture = reinterpret_cast(m_offscreenTextures[m_currentTexture]); - if (m_disableShaders) { + if (g_system->getArgs().isShadersDisabled()) { ImGui::Image(texture, textureSize, ImVec2(0, 0), ImVec2(1, 1)); } else { m_outputShaderEditor.renderWithImgui(this, texture, m_renderSize, textureSize); @@ -1569,7 +1566,7 @@ their TV set to match the aspect ratio of the game.)")); ImGui::End(); } - if (!m_args.get("noupdate") && !g_system->getVersion().failed() && + if (!g_system->getArgs().isUpdateDisabled() && !g_system->getVersion().failed() && !emuSettings.get().value) { if (ImGui::Begin(_("Update configuration"), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::TextUnformatted((_(R"(PCSX-Redux can automatically update itself. @@ -1717,8 +1714,9 @@ the update and manually apply it.)"))); bool gotGLerror = false; for (const auto& error : m_glErrors) { m_luaConsole.addError(error); - if (m_args.get("lua_stdout", false)) { - fprintf(stderr, "%s\n", error.c_str()); + if (g_system->getArgs().isLuaStdoutEnabled()) { + fputs(error.c_str(), stderr); + fputc('\n', stderr); } gotGLerror = true; } @@ -1772,8 +1770,9 @@ the update and manually apply it.)"))); bool gotGLerror = false; for (const auto& error : m_glErrors) { m_luaConsole.addError(error); - if (m_args.get("lua_stdout", false)) { - fprintf(stderr, "%s\n", error.c_str()); + if (g_system->getArgs().isLuaStdoutEnabled()) { + fputs(error.c_str(), stderr); + fputc('\n', stderr); } gotGLerror = true; } @@ -1811,8 +1810,9 @@ the update and manually apply it.)"))); bool gotGLerror = false; for (const auto& error : m_glErrors) { m_luaConsole.addError(error); - if (m_args.get("lua_stdout", false)) { - fprintf(stderr, "%s\n", error.c_str()); + if (g_system->getArgs().isLuaStdoutEnabled()) { + fputs(error.c_str(), stderr); + fputc('\n', stderr); } gotGLerror = true; } diff --git a/src/gui/gui.h b/src/gui/gui.h index 70a2eb9f6..f5b7f9f61 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -206,7 +206,7 @@ class GUI final : public UI { GUI *m_gui = nullptr; }; std::vector getGLerrors() { return std::move(m_glErrors); } - GUI(const CommandLine::args &args) : m_listener(g_system->m_eventBus), UI(args) { + GUI() : m_listener(g_system->m_eventBus) { assert(s_gui == nullptr); s_gui = this; } @@ -298,7 +298,6 @@ class GUI final : public UI { private: GLFWwindow *m_window = nullptr; bool m_hasCoreProfile = false; - bool m_disableShaders = false; int &m_glfwPosX = settings.get().value; int &m_glfwPosY = settings.get().value; int &m_glfwSizeX = settings.get().value; diff --git a/src/main/main.cc b/src/main/main.cc index c93f5d056..faeffe6ad 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -52,7 +52,7 @@ class SystemImpl final : public PCSX::System { } } virtual void message(std::string &&s) final override { - if (m_args.enableGUILogs()) s_ui->addNotification(s.c_str()); + if (m_args.isGUILogsEnabled()) s_ui->addNotification(s.c_str()); if (s_ui->addLog(PCSX::LogClass::UI, s)) { if (m_args.isStdoutEnabled()) ::fputs(s.c_str(), stdout); m_eventBus->signal(PCSX::Events::LogMessage{PCSX::LogClass::UI, s}); @@ -61,7 +61,7 @@ class SystemImpl final : public PCSX::System { } virtual void log(PCSX::LogClass logClass, std::string &&s) final override { - if (m_args.enableGUILogs()) { + if (m_args.isGUILogsEnabled()) { if (!s_ui->addLog(logClass, s)) return; } if (m_args.isStdoutEnabled()) ::fputs(s.c_str(), stdout); @@ -70,7 +70,7 @@ class SystemImpl final : public PCSX::System { } virtual void printf(std::string &&s) final override { - if (m_args.enableGUILogs()) { + if (m_args.isGUILogsEnabled()) { if (!s_ui->addLog(PCSX::LogClass::UNCATEGORIZED, s)) return; } if (m_args.isStdoutEnabled()) ::fputs(s.c_str(), stdout); @@ -79,7 +79,7 @@ class SystemImpl final : public PCSX::System { } virtual void luaMessage(const std::string &s, bool error) final override { - if (m_args.enableGUILogs()) { + if (m_args.isGUILogsEnabled()) { s_ui->addLuaLog(s, error); } if ((error && m_inStartup) || m_args.isLuaStdoutEnabled()) { @@ -216,8 +216,8 @@ int pcsxMain(int argc, char **argv) { PCSX::Emulator *emulator = new PCSX::Emulator(); PCSX::g_emulator = emulator; - s_ui = args.get("no-ui") || args.get("cli") ? reinterpret_cast(new PCSX::TUI(args)) - : reinterpret_cast(new PCSX::GUI(args)); + s_ui = args.get("no-ui") || args.get("cli") ? reinterpret_cast(new PCSX::TUI()) + : reinterpret_cast(new PCSX::GUI()); // Settings will be loaded after this initialization. s_ui->init([&emulator, &args, &system]() { // Start tweaking / sanitizing settings a bit, while continuing to parse the command line diff --git a/src/main/textui.cc b/src/main/textui.cc index 68dfe83f4..122ab6acc 100644 --- a/src/main/textui.cc +++ b/src/main/textui.cc @@ -22,7 +22,7 @@ #include #include -PCSX::TUI::TUI(const CommandLine::args &args) : UI(args) {} +PCSX::TUI::TUI() {} PCSX::TUI::~TUI() {} bool PCSX::TUI::addLog(LogClass logClass, const std::string &msg) { return true; } diff --git a/src/main/textui.h b/src/main/textui.h index 014005fb8..34a711aba 100644 --- a/src/main/textui.h +++ b/src/main/textui.h @@ -25,7 +25,7 @@ namespace PCSX { class TUI : public UI { public: - TUI(const CommandLine::args &args); + TUI(); ~TUI(); bool addLog(LogClass logClass, const std::string &msg) override; void addLuaLog(const std::string &msg, bool error) override; From 6797e49cd8e19142f44e45f9950b530fbf1868a4 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 9 Jul 2023 22:24:41 -0700 Subject: [PATCH 06/29] Adding portable mode. --- src/core/memorycard.cc | 19 ++++++++++++++----- src/core/memorycard.h | 8 ++++---- src/core/system.cc | 9 +++++++++ src/core/system.h | 3 ++- src/core/ui.cc | 2 +- src/gui/gui.cc | 2 +- src/gui/widgets/shader-editor.cc | 12 ++++++++++-- src/main/main.cc | 2 +- 8 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/core/memorycard.cc b/src/core/memorycard.cc index 12539ff5c..4705a2f39 100644 --- a/src/core/memorycard.cc +++ b/src/core/memorycard.cc @@ -333,9 +333,12 @@ uint8_t PCSX::MemoryCard::tickPS_GetVersion(uint8_t value) { } // To-do: "All the code starting here is terrible and needs to be rewritten" -void PCSX::MemoryCard::loadMcd(const PCSX::u8string str) { +void PCSX::MemoryCard::loadMcd(PCSX::u8string mcd) { char *data = m_mcdData; - const char *fname = reinterpret_cast(str.c_str()); + if (std::filesystem::path(mcd).is_relative()) { + mcd = (g_system->getConfigDir() / mcd).u8string(); + } + const char *fname = reinterpret_cast(mcd.c_str()); size_t bytesRead; m_directoryFlag = Flags::DirectoryUnread; @@ -343,7 +346,7 @@ void PCSX::MemoryCard::loadMcd(const PCSX::u8string str) { FILE *f = fopen(fname, "rb"); if (f == nullptr) { PCSX::g_system->printf(_("The memory card %s doesn't exist - creating it\n"), fname); - createMcd(str); + createMcd(mcd); f = fopen(fname, "rb"); if (f != nullptr) { struct stat buf; @@ -386,7 +389,10 @@ void PCSX::MemoryCard::loadMcd(const PCSX::u8string str) { } } -void PCSX::MemoryCard::saveMcd(const PCSX::u8string mcd, const char *data, uint32_t adr, size_t size) { +void PCSX::MemoryCard::saveMcd(PCSX::u8string mcd, const char *data, uint32_t adr, size_t size) { + if (std::filesystem::path(mcd).is_relative()) { + mcd = (g_system->getConfigDir() / mcd).u8string(); + } const char *fname = reinterpret_cast(mcd.c_str()); FILE *f = fopen(fname, "r+b"); @@ -419,7 +425,10 @@ void PCSX::MemoryCard::saveMcd(const PCSX::u8string mcd, const char *data, uint3 } } -void PCSX::MemoryCard::createMcd(const PCSX::u8string mcd) { +void PCSX::MemoryCard::createMcd(PCSX::u8string mcd) { + if (std::filesystem::path(mcd).is_relative()) { + mcd = (g_system->getConfigDir() / mcd).u8string(); + } const char *fname = reinterpret_cast(mcd.c_str()); int s = c_cardSize; diff --git a/src/core/memorycard.h b/src/core/memorycard.h index 7a9fa6729..68881458d 100644 --- a/src/core/memorycard.h +++ b/src/core/memorycard.h @@ -48,14 +48,14 @@ class MemoryCard { saveMcd(path); } } - void createMcd(const PCSX::u8string mcd); + void createMcd(PCSX::u8string mcd); bool dataChanged() { return !m_savedToDisk; } void disablePocketstation() { m_pocketstationEnabled = false; }; void enablePocketstation() { m_pocketstationEnabled = true; }; char *getMcdData() { return m_mcdData; } - void loadMcd(const PCSX::u8string str); - void saveMcd(const PCSX::u8string mcd, const char *data, uint32_t adr, size_t size); - void saveMcd(const PCSX::u8string path) { saveMcd(path, m_mcdData, 0, c_cardSize); } + void loadMcd(PCSX::u8string mcd); + void saveMcd(PCSX::u8string mcd, const char *data, uint32_t adr, size_t size); + void saveMcd(PCSX::u8string mcd) { saveMcd(mcd, m_mcdData, 0, c_cardSize); } private: enum Commands : uint8_t { diff --git a/src/core/system.cc b/src/core/system.cc index 17bf7a991..3c91e9acb 100644 --- a/src/core/system.cc +++ b/src/core/system.cc @@ -290,3 +290,12 @@ bool PCSX::System::findResource(std::function @@ -225,6 +225,7 @@ class System { } std::filesystem::path getBinDir() const { return m_binDir; } + std::filesystem::path getConfigDir() const; const VersionInfo &getVersion() const { return m_version; } // needs to be odd, and is a replica of ImGui's range tables diff --git a/src/core/ui.cc b/src/core/ui.cc index 20285d298..e60bb36d4 100644 --- a/src/core/ui.cc +++ b/src/core/ui.cc @@ -33,7 +33,7 @@ PCSX::UI::UI() : m_listener(g_system->m_eventBus) { } bool PCSX::UI::loadSettings() { - std::ifstream cfg("pcsx.json"); + std::ifstream cfg(g_system->getConfigDir() / "pcsx.json"); auto& emuSettings = g_emulator->settings; if (cfg.is_open() && !g_system->getArgs().isSafeModeEnabled()) { try { diff --git a/src/gui/gui.cc b/src/gui/gui.cc index f5273822e..297e699c6 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -765,7 +765,7 @@ void PCSX::GUI::close() { } void PCSX::GUI::saveCfg() { - std::ofstream cfg("pcsx.json"); + std::ofstream cfg(g_system->getConfigDir() / "pcsx.json"); json j; if (m_fullscreen || glfwGetWindowAttrib(m_window, GLFW_ICONIFIED) > 0) { diff --git a/src/gui/widgets/shader-editor.cc b/src/gui/widgets/shader-editor.cc index fb4573e50..9a9298b04 100644 --- a/src/gui/widgets/shader-editor.cc +++ b/src/gui/widgets/shader-editor.cc @@ -185,6 +185,9 @@ PCSX::Widgets::ShaderEditor::ShaderEditor(const std::string &base, const std::st const std::string_view &dPS, const std::string_view &dL) : m_baseFilename(base), m_index(++s_index) { std::filesystem::path f = base; + if (f.is_relative()) { + f = g_system->getConfigDir() / f; + } { f.replace_extension("vert"); std::ifstream in(f, std::ifstream::in); @@ -226,10 +229,12 @@ PCSX::Widgets::ShaderEditor::ShaderEditor(const std::string &base, const std::st } } -PCSX::Widgets::ShaderEditor::ShaderEditor(const std::string &base) - : m_baseFilename(base), m_index(++s_index) { +PCSX::Widgets::ShaderEditor::ShaderEditor(const std::string &base) : m_baseFilename(base), m_index(++s_index) { setDefaults(); std::filesystem::path f = base; + if (f.is_relative()) { + f = g_system->getConfigDir() / f; + } { f.replace_extension("vert"); std::ifstream in(f, std::ifstream::in); @@ -385,6 +390,9 @@ PCSX::OpenGL::Status PCSX::Widgets::ShaderEditor::compile(GUI *gui, auto L = *g_emulator->m_lua; std::filesystem::path f = m_baseFilename; + if (f.is_relative()) { + f = g_system->getConfigDir() / f; + } if (m_autocompile) { m_lastLuaErrors.clear(); diff --git a/src/main/main.cc b/src/main/main.cc index faeffe6ad..b74771180 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -124,7 +124,7 @@ class SystemImpl final : public PCSX::System { } } - virtual const PCSX::Arguments &getArgs() final override { return m_args; } + virtual const PCSX::Arguments &getArgs() const final override { return m_args; } std::string m_putcharBuffer; PCSX::IO m_logfile; From b6d3fa2d12e1d7fdb37bd228a34607c21f3da106 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 9 Jul 2023 22:33:07 -0700 Subject: [PATCH 07/29] Also yeeting savestates to portable mode. --- src/core/memorycard.cc | 6 +++--- src/core/system.cc | 2 +- src/core/system.h | 2 +- src/core/ui.cc | 2 +- src/gui/gui.cc | 12 +++++++++--- src/gui/gui.h | 4 ++-- src/gui/widgets/shader-editor.cc | 6 +++--- 7 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/core/memorycard.cc b/src/core/memorycard.cc index 4705a2f39..9c66c9a75 100644 --- a/src/core/memorycard.cc +++ b/src/core/memorycard.cc @@ -336,7 +336,7 @@ uint8_t PCSX::MemoryCard::tickPS_GetVersion(uint8_t value) { void PCSX::MemoryCard::loadMcd(PCSX::u8string mcd) { char *data = m_mcdData; if (std::filesystem::path(mcd).is_relative()) { - mcd = (g_system->getConfigDir() / mcd).u8string(); + mcd = (g_system->getPersistentDir() / mcd).u8string(); } const char *fname = reinterpret_cast(mcd.c_str()); size_t bytesRead; @@ -391,7 +391,7 @@ void PCSX::MemoryCard::loadMcd(PCSX::u8string mcd) { void PCSX::MemoryCard::saveMcd(PCSX::u8string mcd, const char *data, uint32_t adr, size_t size) { if (std::filesystem::path(mcd).is_relative()) { - mcd = (g_system->getConfigDir() / mcd).u8string(); + mcd = (g_system->getPersistentDir() / mcd).u8string(); } const char *fname = reinterpret_cast(mcd.c_str()); FILE *f = fopen(fname, "r+b"); @@ -427,7 +427,7 @@ void PCSX::MemoryCard::saveMcd(PCSX::u8string mcd, const char *data, uint32_t ad void PCSX::MemoryCard::createMcd(PCSX::u8string mcd) { if (std::filesystem::path(mcd).is_relative()) { - mcd = (g_system->getConfigDir() / mcd).u8string(); + mcd = (g_system->getPersistentDir() / mcd).u8string(); } const char *fname = reinterpret_cast(mcd.c_str()); int s = c_cardSize; diff --git a/src/core/system.cc b/src/core/system.cc index 3c91e9acb..aec6cfd1e 100644 --- a/src/core/system.cc +++ b/src/core/system.cc @@ -291,7 +291,7 @@ bool PCSX::System::findResource(std::functionm_eventBus) { } bool PCSX::UI::loadSettings() { - std::ifstream cfg(g_system->getConfigDir() / "pcsx.json"); + std::ifstream cfg(g_system->getPersistentDir() / "pcsx.json"); auto& emuSettings = g_emulator->settings; if (cfg.is_open() && !g_system->getArgs().isSafeModeEnabled()) { try { diff --git a/src/gui/gui.cc b/src/gui/gui.cc index 297e699c6..73fbd3f2c 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -765,7 +765,7 @@ void PCSX::GUI::close() { } void PCSX::GUI::saveCfg() { - std::ofstream cfg(g_system->getConfigDir() / "pcsx.json"); + std::ofstream cfg(g_system->getPersistentDir() / "pcsx.json"); json j; if (m_fullscreen || glfwGetWindowAttrib(m_window, GLFW_ICONIFIED) > 0) { @@ -2334,14 +2334,20 @@ std::string PCSX::GUI::buildSaveStateFilename(int i) { } } -void PCSX::GUI::saveSaveState(const std::filesystem::path& filename) { +void PCSX::GUI::saveSaveState(std::filesystem::path filename) { + if (filename.is_relative()) { + filename = g_system->getPersistentDir() / filename; + } // TODO: yeet this to libuv's threadpool. ZWriter save(new UvFile(filename, FileOps::TRUNCATE), ZWriter::GZIP); if (!save.failed()) save.writeString(SaveStates::save()); save.close(); } -void PCSX::GUI::loadSaveState(const std::filesystem::path& filename) { +void PCSX::GUI::loadSaveState(std::filesystem::path filename) { + if (filename.is_relative()) { + filename = g_system->getPersistentDir() / filename; + } ZReader save(new PosixFile(filename)); if (save.failed()) return; std::ostringstream os; diff --git a/src/gui/gui.h b/src/gui/gui.h index f5b7f9f61..9bb9e5481 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -405,8 +405,8 @@ class GUI final : public UI { EventBus::Listener m_listener; std::string buildSaveStateFilename(int i); - void saveSaveState(const std::filesystem::path &filename); - void loadSaveState(const std::filesystem::path &filename); + void saveSaveState(std::filesystem::path filename); + void loadSaveState(std::filesystem::path filename); void applyTheme(int theme); void cherryTheme(); diff --git a/src/gui/widgets/shader-editor.cc b/src/gui/widgets/shader-editor.cc index 9a9298b04..ab5b1e15c 100644 --- a/src/gui/widgets/shader-editor.cc +++ b/src/gui/widgets/shader-editor.cc @@ -186,7 +186,7 @@ PCSX::Widgets::ShaderEditor::ShaderEditor(const std::string &base, const std::st : m_baseFilename(base), m_index(++s_index) { std::filesystem::path f = base; if (f.is_relative()) { - f = g_system->getConfigDir() / f; + f = g_system->getPersistentDir() / f; } { f.replace_extension("vert"); @@ -233,7 +233,7 @@ PCSX::Widgets::ShaderEditor::ShaderEditor(const std::string &base) : m_baseFilen setDefaults(); std::filesystem::path f = base; if (f.is_relative()) { - f = g_system->getConfigDir() / f; + f = g_system->getPersistentDir() / f; } { f.replace_extension("vert"); @@ -391,7 +391,7 @@ PCSX::OpenGL::Status PCSX::Widgets::ShaderEditor::compile(GUI *gui, auto L = *g_emulator->m_lua; std::filesystem::path f = m_baseFilename; if (f.is_relative()) { - f = g_system->getConfigDir() / f; + f = g_system->getPersistentDir() / f; } if (m_autocompile) { From ca1ed469e80bac9626cb31f8520d5709f876e532 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 10 Jul 2023 19:22:26 -0700 Subject: [PATCH 08/29] Making getPersistentDir more robust. --- src/core/system.cc | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/core/system.cc b/src/core/system.cc index aec6cfd1e..68d421c7f 100644 --- a/src/core/system.cc +++ b/src/core/system.cc @@ -293,9 +293,23 @@ bool PCSX::System::findResource(std::function Date: Mon, 10 Jul 2023 19:58:48 -0700 Subject: [PATCH 09/29] Avoid creating settings directory in portable mode. --- src/core/system.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/system.cc b/src/core/system.cc index 68d421c7f..cbd372ae8 100644 --- a/src/core/system.cc +++ b/src/core/system.cc @@ -292,6 +292,7 @@ bool PCSX::System::findResource(std::function Date: Tue, 11 Jul 2023 19:03:46 -0700 Subject: [PATCH 10/29] Derp memory leak. --- src/core/system.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/system.cc b/src/core/system.cc index cbd372ae8..436475397 100644 --- a/src/core/system.cc +++ b/src/core/system.cc @@ -300,6 +300,7 @@ std::filesystem::path PCSX::System::getPersistentDir() const { return ""; } std::filesystem::path persistentDir = std::filesystem::path(homeDir) / "pcsx-redux"; + free(homeDir); #else char* homeDir = getenv("HOME"); if (!homeDir) { From c8dd304e3f002ce795601068093e627a211c5da6 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Wed, 12 Jul 2023 20:06:16 +0300 Subject: [PATCH 11/29] Switch _declspec to __declspec __declspec is the "canonical" version nowadays and is the only one supported by eg MinGW --- src/gui/gui.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/gui.cc b/src/gui/gui.cc index 73fbd3f2c..8bae6fb9f 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -86,8 +86,8 @@ #ifdef _WIN32 extern "C" { -_declspec(dllexport) DWORD NvOptimusEnablement = 1; -_declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1; +__declspec(dllexport) DWORD NvOptimusEnablement = 1; +__declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1; } void PCSX::GUI::openUrl(const std::string_view& url) { From e6a813f0eb48906662573bd2054fd4b1bc4e1b67 Mon Sep 17 00:00:00 2001 From: Red Herring <70984234+glitch-in-the-herring@users.noreply.github.com> Date: Sun, 16 Jul 2023 17:00:16 +0700 Subject: [PATCH 12/29] Update the mapping tooltip text --- src/gui/widgets/breakpoints.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/breakpoints.cc b/src/gui/widgets/breakpoints.cc index ee13a25ab..0156cbbe8 100644 --- a/src/gui/widgets/breakpoints.cc +++ b/src/gui/widgets/breakpoints.cc @@ -38,7 +38,7 @@ void PCSX::Widgets::Breakpoints::draw(const char* title) { } ImGuiHelpers::ShowHelpMarker( _("The mapping feature is a simple concept, but requires some amount of explanation. See the documentation " - "website for more details, in the Advanced Features section.")); + "website for more details, in the Misc Features subsection of the Debugging section.")); ImGui::Checkbox(_("Map execution"), &debugger->m_mapping_e); ImGui::Checkbox(_("Map byte reads "), &debugger->m_mapping_r8); ImGui::SameLine(); From 71e4a548d97e8da23e432f4dad0e5d2710db3c83 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 19 Jul 2023 20:58:42 -0700 Subject: [PATCH 13/29] Adding Ko-Fi link. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b29a1ab2a..3615ab795 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ ![Debugger screenshot](https://pcsx-redux.consoledev.net/images/debugger1.png) +Buy Me a Coffee at ko-fi.com |Platform|Build status|Download| |--------|------------|--------| From ff8a7dbbf91967e1bc8f231bbc7ecf1b3506537a Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 19 Jul 2023 21:01:21 -0700 Subject: [PATCH 14/29] Trying to downgrade MacOS version. --- .github/workflows/macos-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macos-build.yml b/.github/workflows/macos-build.yml index 444bc9f6a..8e7fc06b9 100644 --- a/.github/workflows/macos-build.yml +++ b/.github/workflows/macos-build.yml @@ -39,7 +39,7 @@ jobs: path: '**/*.ps-exe' macos-build-and-test: - runs-on: macOS-latest + runs-on: macos-11 needs: build-openbios steps: - uses: actions/checkout@v1 From ba6f4b527157624af34eb94366f3380dc40fc77c Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 20 Jul 2023 16:57:26 +0300 Subject: [PATCH 15/29] Create funding.yml --- .github/funding.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/funding.yml diff --git a/.github/funding.yml b/.github/funding.yml new file mode 100644 index 000000000..4c91715de --- /dev/null +++ b/.github/funding.yml @@ -0,0 +1 @@ +ko_fi: nicolasnoble From 95239e2a4ea7a7730748c032f4f65b5bb630aead Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 21 Jul 2023 19:52:41 -0700 Subject: [PATCH 16/29] Import / export of Memory Cards. --- src/core/sio.cc | 5 --- src/core/sio.h | 8 +++- src/gui/gui.h | 8 ++-- src/gui/widgets/assembly.h | 2 +- src/gui/widgets/filedialog.cc | 4 +- src/gui/widgets/filedialog.h | 23 ++++++++--- src/gui/widgets/isobrowser.h | 2 +- src/gui/widgets/memcard_manager.cc | 62 ++++++++++++++++++++++++++++-- src/gui/widgets/memcard_manager.h | 10 +++++ src/gui/widgets/pio-cart.h | 2 +- src/gui/widgets/typed_debugger.h | 4 +- 11 files changed, 105 insertions(+), 25 deletions(-) diff --git a/src/core/sio.cc b/src/core/sio.cc index 029be4fbb..d899dc6f8 100644 --- a/src/core/sio.cc +++ b/src/core/sio.cc @@ -362,11 +362,6 @@ void PCSX::SIO::interrupt() { #endif } -void PCSX::SIO::loadMcds(const PCSX::u8string mcd1, const PCSX::u8string mcd2) { - m_memoryCard[0].loadMcd(mcd1); - m_memoryCard[1].loadMcd(mcd2); -} - void PCSX::SIO::getMcdBlockInfo(int mcd, int block, McdBlock &info) { if (block < 1 || block > 15) { throw std::runtime_error(_("Wrong block number")); diff --git a/src/core/sio.h b/src/core/sio.h index 00beb1621..586e2b43b 100644 --- a/src/core/sio.h +++ b/src/core/sio.h @@ -109,7 +109,13 @@ class SIO { void getMcdBlockInfo(int mcd, int block, McdBlock &info); char *getMcdData(int mcd); char *getMcdData(const McdBlock &block) { return getMcdData(block.mcd); } - void loadMcds(const PCSX::u8string mcd1, const PCSX::u8string mcd2); + void loadMcd(const PCSX::u8string &path, int mcd) { + if (mcd > 0 && mcd <= c_cardCount) m_memoryCard[mcd - 1].loadMcd(path); + } + void loadMcds(const PCSX::u8string &mcd1, const PCSX::u8string &mcd2) { + m_memoryCard[0].loadMcd(mcd1); + m_memoryCard[1].loadMcd(mcd2); + } void saveMcd(int mcd); static constexpr int otherMcd(int mcd) { if ((mcd != 1) && (mcd != 2)) throw std::runtime_error("Bad memory card number"); diff --git a/src/gui/gui.h b/src/gui/gui.h index 9bb9e5481..ad531534f 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -371,10 +371,10 @@ class GUI final : public UI { Widgets::Registers m_registers = {settings.get().value}; Widgets::Assembly m_assembly = {settings.get().value}; Widgets::Disassembly m_disassembly = {settings.get().value}; - Widgets::FileDialog m_openIsoFileDialog = {[]() { return _("Open Disk Image"); }}; - Widgets::FileDialog m_openBinaryDialog = {[]() { return _("Open Binary"); }}; - Widgets::FileDialog m_selectBiosDialog = {[]() { return _("Select BIOS"); }}; - Widgets::FileDialog m_selectEXP1Dialog = {[]() { return _("Select EXP1"); }}; + Widgets::FileDialog<> m_openIsoFileDialog = {[]() { return _("Open Disk Image"); }}; + Widgets::FileDialog<> m_openBinaryDialog = {[]() { return _("Open Binary"); }}; + Widgets::FileDialog<> m_selectBiosDialog = {[]() { return _("Select BIOS"); }}; + Widgets::FileDialog<> m_selectEXP1Dialog = {[]() { return _("Select EXP1"); }}; Widgets::Breakpoints m_breakpoints = {settings.get().value}; Widgets::IsoBrowser m_isoBrowser = {settings.get().value}; diff --git a/src/gui/widgets/assembly.h b/src/gui/widgets/assembly.h index 23c5563cd..97e49f101 100644 --- a/src/gui/widgets/assembly.h +++ b/src/gui/widgets/assembly.h @@ -59,7 +59,7 @@ class Assembly : private Disasm { int m_numColumns = 4; char m_jumpAddressString[20]; uint32_t m_previousPC = 0; - FileDialog m_symbolsFileDialog = {[]() { return _("Load Symbols"); }}; + FileDialog<> m_symbolsFileDialog = {[]() { return _("Load Symbols"); }}; std::vector> m_arrows; // Disasm section diff --git a/src/gui/widgets/filedialog.cc b/src/gui/widgets/filedialog.cc index ef5b691d3..d35d76933 100644 --- a/src/gui/widgets/filedialog.cc +++ b/src/gui/widgets/filedialog.cc @@ -21,7 +21,7 @@ #include "GL/gl3w.h" -void* PCSX::Widgets::FileDialog::CreateTexture(uint8_t* data, int w, int h, char fmt) { +void* PCSX::Widgets::FileDialogBase::CreateTexture(uint8_t* data, int w, int h, char fmt) { GLuint tex; glGenTextures(1, &tex); @@ -37,7 +37,7 @@ void* PCSX::Widgets::FileDialog::CreateTexture(uint8_t* data, int w, int h, char return (void*)tex; } -void PCSX::Widgets::FileDialog::setDeleteTexture() { +void PCSX::Widgets::FileDialogBase::setDeleteTexture() { DeleteTexture = [](void* tex) { GLuint texID = reinterpret_cast(tex); glDeleteTextures(1, &texID); diff --git a/src/gui/widgets/filedialog.h b/src/gui/widgets/filedialog.h index 8d9c81b71..8e86431fe 100644 --- a/src/gui/widgets/filedialog.h +++ b/src/gui/widgets/filedialog.h @@ -30,7 +30,18 @@ namespace PCSX { namespace Widgets { -class FileDialog : private ifd::FileDialog { +class FileDialogBase : protected ifd::FileDialog { + public: + virtual void* CreateTexture(uint8_t* data, int w, int h, char fmt) override; + + protected: + void setDeleteTexture(); +}; + +enum class FileDialogMode { Open, MultiSelect, Save }; + +template +class FileDialog : public FileDialogBase { public: FileDialog(std::function title) : m_title(title) { setToCurrentPath(); @@ -39,7 +50,12 @@ class FileDialog : private ifd::FileDialog { virtual ~FileDialog() = default; void setToCurrentPath() { m_currentPath = std::filesystem::current_path(); } void openDialog() { - Open(m_title(), m_title(), "*.*", false, reinterpret_cast(m_currentPath.u8string().c_str())); + if constexpr (mode == FileDialogMode::Open) { + Open(m_title(), m_title(), "*.*", mode == FileDialogMode::MultiSelect, + reinterpret_cast(m_currentPath.u8string().c_str())); + } else if constexpr (mode == FileDialogMode::Save) { + Save(m_title(), m_title(), "*.*", reinterpret_cast(m_currentPath.u8string().c_str())); + } } const std::vector& selected() const { return m_results; } bool draw() { @@ -56,10 +72,7 @@ class FileDialog : private ifd::FileDialog { } std::filesystem::path m_currentPath; - virtual void* CreateTexture(uint8_t* data, int w, int h, char fmt) override; - private: - void setDeleteTexture(); const std::function m_title; std::vector m_results; }; diff --git a/src/gui/widgets/isobrowser.h b/src/gui/widgets/isobrowser.h index 932a780c2..0b544b376 100644 --- a/src/gui/widgets/isobrowser.h +++ b/src/gui/widgets/isobrowser.h @@ -47,7 +47,7 @@ class IsoBrowser { float m_crcProgress = 0.0f; Coroutine<> computeCRC(CDRIso*); - FileDialog m_openIsoFileDialog = {[]() { return _("Open Disk Image"); }}; + FileDialog<> m_openIsoFileDialog = {[]() { return _("Open Disk Image"); }}; }; } // namespace Widgets diff --git a/src/gui/widgets/memcard_manager.cc b/src/gui/widgets/memcard_manager.cc index b7677bf4d..561f8d34c 100644 --- a/src/gui/widgets/memcard_manager.cc +++ b/src/gui/widgets/memcard_manager.cc @@ -26,6 +26,7 @@ #include "fmt/format.h" #include "gui/gui.h" #include "support/imgui-helpers.h" +#include "support/uvfile.h" void PCSX::Widgets::MemcardManager::initTextures() { // Initialize the OpenGL textures used for the icon images @@ -50,11 +51,67 @@ bool PCSX::Widgets::MemcardManager::draw(GUI* gui, const char* title) { ImGui::SetNextWindowPos(ImVec2(600, 600), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); - if (!ImGui::Begin(title, &m_show)) { + if (!ImGui::Begin(title, &m_show, ImGuiWindowFlags_MenuBar)) { ImGui::End(); return false; } + bool showImportMemoryCardDialog = false; + bool showExportMemoryCardDialog = false; + + if (ImGui::BeginMenuBar()) { + if (ImGui::BeginMenu(_("File"))) { + if (ImGui::MenuItem(_("Import file into memory card 1"))) { + showImportMemoryCardDialog = true; + m_memoryCardImportExportIndex = 1; + } + if (ImGui::MenuItem(_("Import file into memory card 2"))) { + showImportMemoryCardDialog = true; + m_memoryCardImportExportIndex = 2; + } + if (ImGui::MenuItem(_("Export memory card 1 to file"))) { + showExportMemoryCardDialog = true; + m_memoryCardImportExportIndex = 1; + } + if (ImGui::MenuItem(_("Export memory card 2 to file"))) { + showExportMemoryCardDialog = true; + m_memoryCardImportExportIndex = 2; + } + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + if (showImportMemoryCardDialog) { + m_importMemoryCardDialog.openDialog(); + } + + if (m_importMemoryCardDialog.draw()) { + std::vector fileToOpen = m_importMemoryCardDialog.selected(); + if (!fileToOpen.empty()) { + g_emulator->m_sio->loadMcd(fileToOpen[0], m_memoryCardImportExportIndex); + g_emulator->m_sio->saveMcd(m_memoryCardImportExportIndex); + clearUndoBuffer(); + } + } + + if (showExportMemoryCardDialog) { + m_exportMemoryCardDialog.openDialog(); + } + + if (m_exportMemoryCardDialog.draw()) { + std::vector fileToOpen = m_exportMemoryCardDialog.selected(); + if (!fileToOpen.empty()) { + IO out = new UvFile(fileToOpen[0], FileOps::TRUNCATE); + if (!out->failed()) { + const auto dataCard = g_emulator->m_sio->getMcdData(m_memoryCardImportExportIndex); + Slice slice; + slice.copy(dataCard, 128 * 1024); + out->writeAt(std::move(slice), 0); + } + } + } + const bool undoDisabled = m_undo.size() == 0; if (undoDisabled) { ImGui::BeginDisabled(); @@ -92,8 +149,7 @@ bool PCSX::Widgets::MemcardManager::draw(GUI* gui, const char* title) { ImGui::EndDisabled(); } if (ImGui::Button(_("Clear Undo buffer"))) { - m_undo.clear(); - m_undoIndex = 0; + clearUndoBuffer(); } // Insert or remove memory cards. Send a SIO IRQ to the emulator if this happens as well. diff --git a/src/gui/widgets/memcard_manager.h b/src/gui/widgets/memcard_manager.h index b13731d49..eb064ae0b 100644 --- a/src/gui/widgets/memcard_manager.h +++ b/src/gui/widgets/memcard_manager.h @@ -28,6 +28,7 @@ #include "GL/gl3w.h" #include "clip/clip.h" #include "core/sio.h" +#include "gui/widgets/filedialog.h" #include "imgui.h" namespace PCSX { @@ -72,6 +73,15 @@ class MemcardManager { int m_undoIndex = 0; std::unique_ptr m_latest; + Widgets::FileDialog<> m_importMemoryCardDialog = {[]() { return _("Import Memory Card file"); }}; + Widgets::FileDialog m_exportMemoryCardDialog = { + []() { return _("Export Memory Card file"); }}; + unsigned m_memoryCardImportExportIndex = 0; + + void clearUndoBuffer() { + m_undo.clear(); + m_undoIndex = 0; + } }; } // namespace Widgets diff --git a/src/gui/widgets/pio-cart.h b/src/gui/widgets/pio-cart.h index 3a073657b..eadf40a5c 100644 --- a/src/gui/widgets/pio-cart.h +++ b/src/gui/widgets/pio-cart.h @@ -33,7 +33,7 @@ class PIOCart { bool& m_show; private: - Widgets::FileDialog m_selectEXP1Dialog = {[]() { return _("Select EXP1"); }}; + Widgets::FileDialog<> m_selectEXP1Dialog = {[]() { return _("Select EXP1"); }}; int m_flashSizeIndex; bool m_switchOn = 1; }; diff --git a/src/gui/widgets/typed_debugger.h b/src/gui/widgets/typed_debugger.h index 50882fe1b..ce40e7626 100644 --- a/src/gui/widgets/typed_debugger.h +++ b/src/gui/widgets/typed_debugger.h @@ -45,9 +45,9 @@ class TypedDebugger { * Data importation. */ std::vector m_dataTypesFile; - Widgets::FileDialog m_importDataTypesFileDialog = {[]() { return _("Import data types"); }}; + Widgets::FileDialog<> m_importDataTypesFileDialog = {[]() { return _("Import data types"); }}; std::vector m_functionsFile; - Widgets::FileDialog m_importFunctionsFileDialog = {[]() { return _("Import functions"); }}; + Widgets::FileDialog<> m_importFunctionsFileDialog = {[]() { return _("Import functions"); }}; enum class ImportType { DataTypes, Functions }; void import(std::string_view filename, ImportType importType); From d5c4af91f2cd165528f6dfd52c90d3318de746b4 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 22 Jul 2023 10:18:12 -0700 Subject: [PATCH 17/29] Various fixes for memory cards in OpenBIOS Many derps and typos. --- src/mips/openbios/card/backupunit.c | 7 ++++--- src/mips/openbios/card/device.c | 2 +- src/mips/openbios/sio0/card.c | 8 ++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/mips/openbios/card/backupunit.c b/src/mips/openbios/card/backupunit.c index 17334188e..21ffacfa7 100644 --- a/src/mips/openbios/card/backupunit.c +++ b/src/mips/openbios/card/backupunit.c @@ -178,7 +178,7 @@ static int buValidateEntryAndCorrect(int port, int entryId) { if ((blocks > 0) && (next != -1)) { int16_t ptr = next; int count = blocks; - while (mask != (entries[ptr].allocState) & 0xf0) { + while (mask != ((entries[ptr].allocState) & 0xf0)) { ptr = entries[ptr].nextBlock; if ((--count < 0) || (ptr == -1)) return 0; } @@ -236,7 +236,8 @@ int buInit(int deviceId) { uint32_t entriesStates[15]; for (unsigned i = 0; i < 15; i++) { entriesStates[i] = 0; - if (buValidateEntryAndCorrect(port, i)) entriesStates[i] = 0x52; // this makes no sense + // this makes no sense, as it'll get overwritten by the next loop + if (buValidateEntryAndCorrect(port, i)) entriesStates[i] = 0x52; } for (unsigned i = 0; i < 15; i++) entriesStates[i] = 0; for (unsigned i = 0; i < 15; i++) { @@ -344,7 +345,7 @@ void buLowLevelOpCompleted() { break; } case 6: - g_buOpBuffer[port] = 3; + g_buOperation[port] = 3; // fallthrough case 3: { if (--g_buOpSectorCount[port] == 0) { diff --git a/src/mips/openbios/card/device.c b/src/mips/openbios/card/device.c index e26497177..4fef109b5 100644 --- a/src/mips/openbios/card/device.c +++ b/src/mips/openbios/card/device.c @@ -205,7 +205,7 @@ struct File *g_buOpFile[2]; static int s_buOpError[2]; int buRelativeToAbsoluteSector(int port, int block, int sector) { - while (sector >= 0x3f) { + while (sector > 0x3f) { block = g_buDirEntries[port][block].nextBlock; sector = sector - 0x40; if (block == -1) return -1; diff --git a/src/mips/openbios/sio0/card.c b/src/mips/openbios/sio0/card.c index 322106b3a..65261298e 100644 --- a/src/mips/openbios/sio0/card.c +++ b/src/mips/openbios/sio0/card.c @@ -48,10 +48,10 @@ void mcResetStatus() { g_mcErrors[2] = 0; g_mcErrors[3] = 0; - syscall_undeliverEvent(EVENT_VBLANK, 0x0004); - syscall_undeliverEvent(EVENT_VBLANK, 0x8000); - syscall_undeliverEvent(EVENT_VBLANK, 0x2000); - syscall_undeliverEvent(EVENT_VBLANK, 0x0100); + syscall_undeliverEvent(EVENT_BU, 0x0004); + syscall_undeliverEvent(EVENT_BU, 0x8000); + syscall_undeliverEvent(EVENT_BU, 0x2000); + syscall_undeliverEvent(EVENT_BU, 0x0100); } int mcWaitForStatus() { From fc0cf68e03d1cfb3a98cf655564fbfeb730c8160 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 22 Jul 2023 10:16:37 -0700 Subject: [PATCH 18/29] Enabling drag-and-drop of bioses. --- src/gui/gui.cc | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/gui/gui.cc b/src/gui/gui.cc index 8bae6fb9f..6b827c218 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -2297,10 +2297,13 @@ void PCSX::GUI::update(bool vsync) { void PCSX::GUI::magicOpen(const char* pathStr) { std::filesystem::path path = pathStr; bool success = false; + IO file = new PosixFile(path); + + // Is this something that looks like a binary we can load ? try { BinaryLoader::Info info; std::map symbols; - success = BinaryLoader::load(new PosixFile(path), new Mem4G(), info, symbols); + success = BinaryLoader::load(file, new Mem4G(), info, symbols); if (success) success = info.pc.has_value(); } catch (...) { success = false; @@ -2310,10 +2313,39 @@ void PCSX::GUI::magicOpen(const char* pathStr) { m_exeToLoad.set(path.u8string()); g_system->log(LogClass::UI, "Scheduling to load %s and soft reseting.\n", path.string()); g_system->softReset(); - } else { - g_emulator->m_cdrom->setIso(new CDRIso(path)); - g_emulator->m_cdrom->check(); + return; } + + // Is this something that looks like a bios maybe ? + if (file->size() == 512 * 1024) { + // bit of a crude way to check if it's a bios, but it's good enough + // we're assuming all bioses start with setting the timings for the + // bios bus, which is basically these instructions: + + // li $t0, (19 << 16) | 0x243f + // sw $t0, SBUS_DEV2_CTRL + // nop + + // this code translates to the following bytes: + static constexpr uint8_t biosSignature[] = {0x13, 0x00, 0x08, 0x3c, 0x3f, 0x24, 0x08, 0x35, 0x80, 0x1f, + 0x01, 0x3c, 0x10, 0x10, 0x28, 0xac, 0x00, 0x00, 0x00, 0x00}; + // we could potentially also check the rest, but I think some bioses + // may differ there, so we'll just check the first 20 bytes for now + + uint8_t buffer[sizeof(biosSignature)]; + file->readAt(buffer, sizeof(buffer), 0); + + if (memcmp(buffer, biosSignature, sizeof(biosSignature)) == 0) { + g_system->hardReset(); + g_system->log(LogClass::UI, "Temporary overriding bios with %s and hard resetting.\n", path.string()); + file->readAt(g_emulator->m_mem->m_bios, 512 * 1024, 0); + return; + } + } + + // Iso loader is last because its detection is the most broken at the moment. + g_emulator->m_cdrom->setIso(new CDRIso(path)); + g_emulator->m_cdrom->check(); } std::string PCSX::GUI::buildSaveStateFilename(int i) { From 9052c2c729757d02c7ca6ab2eb47e7118b114642 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 22 Jul 2023 11:29:38 -0700 Subject: [PATCH 19/29] Check presence of BuildID before reading it. Not all compilers seem to generate buildid information, so let's have an extra check to skip displaying it --- src/mips/openbios/main/main.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/mips/openbios/main/main.c b/src/mips/openbios/main/main.c index 8b83c8ad8..0cd71ab57 100644 --- a/src/mips/openbios/main/main.c +++ b/src/mips/openbios/main/main.c @@ -271,7 +271,7 @@ void gameMainThunk(struct psxExeHeader *binaryInfo, int argc, char **argv) { exec(binaryInfo, argc, argv); } -extern struct BuildId __build_id; +extern struct BuildId __build_id, __build_id_end; static void boot(char *systemCnfPath, char *binaryPath) { POST = 1; @@ -297,17 +297,19 @@ static void boot(char *systemCnfPath, char *binaryPath) { POST = 5; /* this is a bit specific to OpenBIOS to retrieve the buildid from the raw data */ { - char buildIDstring[65]; - uint32_t count = __build_id.descsz; - if (count > 32) count = 32; - const uint8_t *buildId = __build_id.strings + __build_id.namesz; - static const char *const hex = "0123456789abcdef"; - for (int i = 0; i < count; i++) { - uint8_t c = buildId[i]; - buildIDstring[i * 2 + 0] = hex[c & 0xf]; - buildIDstring[i * 2 + 1] = hex[(c >> 4) & 0xf]; + char buildIDstring[65] = "unknown"; + if (&__build_id != &__build_id_end) { + uint32_t count = __build_id.descsz; + if (count > 32) count = 32; + const uint8_t *buildId = __build_id.strings + __build_id.namesz; + static const char *const hex = "0123456789abcdef"; + for (int i = 0; i < count; i++) { + uint8_t c = buildId[i]; + buildIDstring[i * 2 + 0] = hex[c & 0xf]; + buildIDstring[i * 2 + 1] = hex[(c >> 4) & 0xf]; + } + buildIDstring[count * 2] = 0; } - buildIDstring[count * 2] = 0; psxprintf("PS-X Realtime Kernel OpenBios - build id %s.\nCopyright (C) 2019-2023 PCSX-Redux authors.\n", buildIDstring); } From 3d19d29b9b19b50609ae15590634f92cd252f9fb Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 22 Jul 2023 22:43:25 -0700 Subject: [PATCH 20/29] Fixing dev_bu_open --- src/mips/openbios/card/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/openbios/card/device.c b/src/mips/openbios/card/device.c index 4fef109b5..6b9ba2d91 100644 --- a/src/mips/openbios/card/device.c +++ b/src/mips/openbios/card/device.c @@ -118,7 +118,7 @@ int dev_bu_open(struct File *file, const char *path, int mode) { syscall_setDeviceStatus(0); firstIndex = buNextFileInternal(deviceId, 0, path); if (firstIndex != -1) { - file->errno = PSXENOENT; + file->errno = PSXEEXIST; return 1; } int availableBlocks = 0; From 9b3b6676b6c33f07b2f0422404da166f1cd894f4 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 22 Jul 2023 22:43:47 -0700 Subject: [PATCH 21/29] Adding dev_bu_erase --- src/mips/openbios/card/card.h | 2 +- src/mips/openbios/card/device.c | 67 +++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/mips/openbios/card/card.h b/src/mips/openbios/card/card.h index 62f0ca51d..5309e5afa 100644 --- a/src/mips/openbios/card/card.h +++ b/src/mips/openbios/card/card.h @@ -42,7 +42,7 @@ int dev_bu_open(struct File *file, const char *filename, int mode); int dev_bu_close(struct File *file); int dev_bu_read(struct File *file, void *buffer, int size); int dev_bu_write(struct File *file, void *buffer, int size); -void dev_bu_erase(); +int dev_bu_erase(struct File *file, const char *path); void dev_bu_undelete(); struct DirEntry *dev_bu_firstFile(struct File *file, const char *filename, struct DirEntry *entry); struct DirEntry *dev_bu_nextFile(struct File *file, struct DirEntry *entry); diff --git a/src/mips/openbios/card/device.c b/src/mips/openbios/card/device.c index 6b9ba2d91..6204f1d34 100644 --- a/src/mips/openbios/card/device.c +++ b/src/mips/openbios/card/device.c @@ -434,10 +434,69 @@ int dev_bu_write(struct File *file, void *buffer, int size) { return size; } -void dev_bu_erase() { - uint32_t ra; - asm("move %0, $ra\n" : "=r"(ra)); - dev_bu_unimplemented("mcErase", ra); +int dev_bu_erase(struct File *file, const char *path) { + file->errno = PSXEBUSY; + int deviceId = file->deviceId; + int port = deviceId >= 0 ? deviceId : deviceId + 15; + port >>= 4; + + if (g_buOperation[port] != 0) return 1; + + mcResetStatus(); + if (!buDevInit(deviceId)) return 1; + + syscall_setDeviceStatus(0); + int index = buNextFileInternal(deviceId, 0, path); + if (index == -1) { + file->errno = PSXENOENT; + return 1; + } + int bitmap[15]; + for (unsigned i = 0; i < 15; i++) { + bitmap[i] = 0; + } + struct BuDirectoryEntry *entry = &g_buDirEntries[port][index]; + entry->allocState = 0xa1; + bitmap[index] = 0x51; + int size = entry->fileSize; + int nextBlock = entry->nextBlock; + if (size < 0) size += 0x1fff; + int count = (size >> 13) - 1; + if (count > 0) { + entry = &g_buDirEntries[port][nextBlock]; + while ((entry->nextBlock != -1) && (entry->allocState == 0x52)) { + int block = nextBlock; + nextBlock = entry->nextBlock; + entry->allocState = 0xa2; + count--; + bitmap[block] = 0x52; + if (count < 1) break; + entry = &g_buDirEntries[port][nextBlock]; + } + } + if (count > 0) { + entry = &g_buDirEntries[port][nextBlock]; + if ((entry->nextBlock == -1) && (entry->allocState == 0x53)) { + entry->allocState = 0xa3; + bitmap[nextBlock] = 0x52; + } + } + + if (buWriteTOC(deviceId, bitmap) != 0) { + for (unsigned i = 0; i < 15; i++) { + if (bitmap[i]) { + entry = &g_buDirEntries[port][i]; + entry->fileSize = 0; + entry->nextBlock = -1; + entry->allocState = 0xa0; + } + } + file->errno = PSXEBUSY; + return 1; + } + + file->errno = PSXENOERR; + return 0; } void dev_bu_undelete() { From 826fb30a37e50db77dc94fbb15e3406e53ff2ca1 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 22 Jul 2023 22:44:00 -0700 Subject: [PATCH 22/29] Adding dev_bu_rename --- src/mips/openbios/card/card.h | 2 +- src/mips/openbios/card/device.c | 40 +++++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/mips/openbios/card/card.h b/src/mips/openbios/card/card.h index 5309e5afa..f277d650a 100644 --- a/src/mips/openbios/card/card.h +++ b/src/mips/openbios/card/card.h @@ -47,7 +47,7 @@ void dev_bu_undelete(); struct DirEntry *dev_bu_firstFile(struct File *file, const char *filename, struct DirEntry *entry); struct DirEntry *dev_bu_nextFile(struct File *file, struct DirEntry *entry); int dev_bu_format(struct File *file); -void dev_bu_rename(); +int dev_bu_rename(struct File *file, const char *oldName, void *, const char *newName); void dev_bu_deinit(); extern int g_buOpSectorStart[2]; diff --git a/src/mips/openbios/card/device.c b/src/mips/openbios/card/device.c index 6204f1d34..6fbcb8e2f 100644 --- a/src/mips/openbios/card/device.c +++ b/src/mips/openbios/card/device.c @@ -582,10 +582,42 @@ int dev_bu_format(struct File *file) { return 0; } -void dev_bu_rename() { - uint32_t ra; - asm("move %0, $ra\n" : "=r"(ra)); - dev_bu_unimplemented("mcRename", ra); +int dev_bu_rename(struct File *file, const char *oldName, void *, const char *newName) { + file->errno = PSXEBUSY; + int deviceId = file->deviceId; + int port = deviceId >= 0 ? deviceId : deviceId + 15; + port >>= 4; + + if (g_buOperation[port] != 0) return 1; + + mcResetStatus(); + if (!buDevInit(deviceId)) return 1; + + syscall_setDeviceStatus(0); + if (buNextFileInternal(deviceId, 0, newName) != -1) { + file->errno = PSXEEXIST; + return 1; + } + int index = buNextFileInternal(deviceId, 0, oldName); + if (index == -1) { + file->errno = PSXENOENT; + return 1; + } + int bitmap[15]; + for (unsigned i = 0; i < 15; i++) { + bitmap[i] = 0; + } + char *entryToUpdate = g_buDirEntries[port][index].name; + strcpy(entryToUpdate, newName); + bitmap[index] = 0x51; + if (buWriteTOC(deviceId, bitmap) != 0) { + strcpy(entryToUpdate, oldName); + file->errno = PSXEBUSY; + return 1; + } + + file->errno = PSXENOERR; + return 0; } void dev_bu_deinit() { From 9ba9af27e8ee4c691a368f2f2603cd3bed841112 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 22 Jul 2023 22:50:03 -0700 Subject: [PATCH 23/29] Fixing compilation. --- src/mips/openbios/card/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/openbios/card/device.c b/src/mips/openbios/card/device.c index 6fbcb8e2f..17c87d174 100644 --- a/src/mips/openbios/card/device.c +++ b/src/mips/openbios/card/device.c @@ -582,7 +582,7 @@ int dev_bu_format(struct File *file) { return 0; } -int dev_bu_rename(struct File *file, const char *oldName, void *, const char *newName) { +int dev_bu_rename(struct File *file, const char *oldName, void *unused, const char *newName) { file->errno = PSXEBUSY; int deviceId = file->deviceId; int port = deviceId >= 0 ? deviceId : deviceId + 15; From 4c022351e70f9f32aa1a0c7a26cb398d10009ba5 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 22 Jul 2023 23:47:29 -0700 Subject: [PATCH 24/29] Actually gluing everything together... --- src/mips/common/psxlibc/device.h | 8 +++- src/mips/openbios/card/card.h | 2 +- src/mips/openbios/card/device.c | 2 +- src/mips/openbios/fileio/fileio.h | 3 ++ src/mips/openbios/fileio/stdio.c | 74 +++++++++++++++++++++++++++++ src/mips/openbios/kernel/handlers.c | 2 +- 6 files changed, 86 insertions(+), 5 deletions(-) diff --git a/src/mips/common/psxlibc/device.h b/src/mips/common/psxlibc/device.h index fdf0ebe4f..0c3fcba7b 100644 --- a/src/mips/common/psxlibc/device.h +++ b/src/mips/common/psxlibc/device.h @@ -52,9 +52,11 @@ typedef int (*device_close)(struct File *); typedef int (*device_ioctl)(struct File *, int cmd, int arg); typedef int (*device_read)(struct File *, void *buffer, int size); typedef int (*device_write)(struct File *, void *buffer, int size); +typedef int (*device_erase)(struct File *, const char *path); typedef struct DirEntry *(*device_firstFile)(struct File *file, const char *filename, struct DirEntry *entry); typedef struct DirEntry *(*device_nextFile)(struct File *file, struct DirEntry *entry); typedef int (*device_format)(struct File *file); +typedef int (*device_rename)(struct File *oldFile, const char *oldName, struct File *newFile, const char *newName); typedef void (*device_deinit)(); struct Device { @@ -69,11 +71,13 @@ struct Device { device_ioctl ioctl; device_read read; device_write write; - void *erase, *undelete; + device_erase erase; + void *undelete; device_firstFile firstFile; device_nextFile nextFile; device_format format; - void *chdir, *rename; + void *chdir; + device_rename rename; device_deinit deinit; void *check; }; diff --git a/src/mips/openbios/card/card.h b/src/mips/openbios/card/card.h index f277d650a..cad9b703f 100644 --- a/src/mips/openbios/card/card.h +++ b/src/mips/openbios/card/card.h @@ -47,7 +47,7 @@ void dev_bu_undelete(); struct DirEntry *dev_bu_firstFile(struct File *file, const char *filename, struct DirEntry *entry); struct DirEntry *dev_bu_nextFile(struct File *file, struct DirEntry *entry); int dev_bu_format(struct File *file); -int dev_bu_rename(struct File *file, const char *oldName, void *, const char *newName); +int dev_bu_rename(struct File *file, const char *oldName, struct File *unused, const char *newName); void dev_bu_deinit(); extern int g_buOpSectorStart[2]; diff --git a/src/mips/openbios/card/device.c b/src/mips/openbios/card/device.c index 17c87d174..28659afbb 100644 --- a/src/mips/openbios/card/device.c +++ b/src/mips/openbios/card/device.c @@ -582,7 +582,7 @@ int dev_bu_format(struct File *file) { return 0; } -int dev_bu_rename(struct File *file, const char *oldName, void *unused, const char *newName) { +int dev_bu_rename(struct File *file, const char *oldName, struct File *unused, const char *newName) { file->errno = PSXEBUSY; int deviceId = file->deviceId; int port = deviceId >= 0 ? deviceId : deviceId + 15; diff --git a/src/mips/openbios/fileio/fileio.h b/src/mips/openbios/fileio/fileio.h index e2ab6cd44..7b7b696c9 100644 --- a/src/mips/openbios/fileio/fileio.h +++ b/src/mips/openbios/fileio/fileio.h @@ -68,6 +68,9 @@ struct DirEntry *firstFile(const char *filepath, struct DirEntry *entry); struct DirEntry *nextFile(struct DirEntry *entry); int format(const char *deviceName); +int psxrename(const char *oldName, const char *newName); +int psxerase(const char *path); + extern struct File *g_firstFile; int getDeviceStatus(); diff --git a/src/mips/openbios/fileio/stdio.c b/src/mips/openbios/fileio/stdio.c index 537fec919..1ae0be0d4 100644 --- a/src/mips/openbios/fileio/stdio.c +++ b/src/mips/openbios/fileio/stdio.c @@ -335,3 +335,77 @@ int psxprintf(const char* fmt, ...) { vxprintf(xprintfcallback, NULL, fmt, ap); va_end(ap); } + +int psxrename(const char* oldName, const char* newName) { + struct File* oldFile = findEmptyFile(); + if (!oldFile) { + psxerrno = PSXEMFILE; + return 0; + } + struct File* newFile = findEmptyFile(); + if (!newFile) { + psxerrno = PSXEMFILE; + oldFile->flags = 0; + return 0; + } + struct Device* oldDevice; + int oldDeviceId; + const char* oldFilename = splitFilepathAndFindDevice(oldName, &oldDevice, &oldDeviceId); + if (oldFilename == ((char*)-1)) { + psxerrno = PSXENODEV; + oldFile->flags = 0; + newFile->flags = 0; + return 0; + } + struct Device* newDevice; + int newDeviceId; + const char* newFilename = splitFilepathAndFindDevice(newName, &newDevice, &newDeviceId); + if (oldDeviceId != newDeviceId) { + psxerrno = PSXEXDEV; + oldFile->flags = 0; + newFile->flags = 0; + return 0; + } + if (newFilename == ((char*)-1)) { + psxerrno = PSXENODEV; + oldFile->flags = 0; + newFile->flags = 0; + return 0; + } + oldFile->deviceId = oldDeviceId; + oldFile->device = oldDevice; + newFile->deviceId = newDeviceId; + newFile->device = newDevice; + if (oldDevice->rename(oldFile, oldFilename, newFile, newFilename) != 0) { + psxerrno = oldFile->errno; + oldFile->flags = 0; + newFile->flags = 0; + return 0; + } + oldFile->flags = 0; + newFile->flags = 0; + return 1; +} + +int psxerase(const char* path) { + struct File* file = findEmptyFile(); + if (!file) { + psxerrno = PSXEMFILE; + return 0; + } + struct Device* device; + int deviceId; + const char* filename = splitFilepathAndFindDevice(path, &device, &deviceId); + if (filename == ((char*)-1)) { + psxerrno = PSXENODEV; + file->flags = 0; + return 0; + } + file->deviceId = deviceId; + file->device = device; + if (device->erase(file, filename) != 0) { + psxerrno = file->errno; + file->flags = 0; + return 0; + } +} diff --git a/src/mips/openbios/kernel/handlers.c b/src/mips/openbios/kernel/handlers.c index 1ee91e9a4..9195c2420 100644 --- a/src/mips/openbios/kernel/handlers.c +++ b/src/mips/openbios/kernel/handlers.c @@ -236,7 +236,7 @@ void *B0table[0x60] = { psxexit, isFileConsole, psxgetc, psxputc, // 38 psxgetchar, psxputchar, psxgets, psxputs, // 3c unimplementedThunk, format, firstFile, nextFile, // 40 - unimplementedThunk, unimplementedThunk, unimplementedThunk, addDevice, // 44 + psxrename, psxerase, unimplementedThunk, addDevice, // 44 removeDevice, printInstalledDevices, initCard, startCard, // 48 stopCard, cardInfoInternal, mcWriteSector, mcReadSector, // 4c mcAllowNewCard, Krom2RawAdd, unimplementedThunk, Krom2Offset, // 50 From fdbdb082f00ed333961c91c1852b52bc0c673045 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 23 Jul 2023 06:15:04 -0700 Subject: [PATCH 25/29] Properly refactoring the viewports CLI flags. --- src/core/arguments.cc | 3 ++- src/core/arguments.h | 12 ++++++++---- src/gui/gui.cc | 4 +--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/core/arguments.cc b/src/core/arguments.cc index 660ad3cf4..4a8219f52 100644 --- a/src/core/arguments.cc +++ b/src/core/arguments.cc @@ -37,5 +37,6 @@ PCSX::Arguments::Arguments(const CommandLine::args& args) { if (args.get("resetui")) m_uiResetRequested = true; if (args.get("noshaders")) m_shadersDisabled = true; if (args.get("noupdate")) m_updateDisabled = true; - if (args.get("noviewports")) m_viewportsDisabled = true; + if (args.get("viewports")) m_viewportsEnabled = true; + if (args.get("no-viewports")) m_viewportsEnabled = false; } diff --git a/src/core/arguments.h b/src/core/arguments.h index 6fe3e8354..80f9727ca 100644 --- a/src/core/arguments.h +++ b/src/core/arguments.h @@ -70,9 +70,9 @@ class Arguments { // Enabled with the flag -noupdate. bool isUpdateDisabled() const { return m_updateDisabled; } - // Returns true if the user requested that viewports be disabled. - // Enabled with the flag -noviewports. - bool isViewportsDisabled() const { return m_viewportsDisabled; } + // Returns true if the user requested that viewports be enabled. + // Toggled with the flags -viewports / -no-viewports. + bool isViewportsEnabled() const { return m_viewportsEnabled; } private: bool m_luaStdoutEnabled = false; @@ -84,7 +84,11 @@ class Arguments { bool m_uiResetRequested = false; bool m_shadersDisabled = false; bool m_updateDisabled = false; - bool m_viewportsDisabled = false; +#ifdef __linux__ + bool m_viewportsEnabled = false; +#else + bool m_viewportsEnabled = true; +#endif }; } // namespace PCSX diff --git a/src/gui/gui.cc b/src/gui/gui.cc index 6b827c218..c06e128b9 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -587,11 +587,9 @@ void PCSX::GUI::init(std::function applyArguments) { io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; -#ifndef __linux__ - if (!g_system->getArgs().isViewportsDisabled()) { + if (g_system->getArgs().isViewportsEnabled()) { io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; } -#endif io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleViewports; // io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleFonts; From 9e8d182e46b4104e842571707105d99ac1b220be Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 23 Jul 2023 11:33:24 -0700 Subject: [PATCH 26/29] Derp. --- src/mips/openbios/fileio/stdio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mips/openbios/fileio/stdio.c b/src/mips/openbios/fileio/stdio.c index 1ae0be0d4..e632ef53c 100644 --- a/src/mips/openbios/fileio/stdio.c +++ b/src/mips/openbios/fileio/stdio.c @@ -408,4 +408,6 @@ int psxerase(const char* path) { file->flags = 0; return 0; } + file->flags = 0; + return 1; } From 682b89f1856134d0f2cb5cd5899643d5f4e20490 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 23 Jul 2023 21:55:09 -0700 Subject: [PATCH 27/29] Fixing 24-bits rendering for the software GPU. --- src/gpu/soft/draw.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gpu/soft/draw.cc b/src/gpu/soft/draw.cc index f47b5f405..fe082e523 100644 --- a/src/gpu/soft/draw.cc +++ b/src/gpu/soft/draw.cc @@ -33,9 +33,10 @@ void PCSX::SoftGPU::impl::doBufferSwap(bool fromGui) { GLuint textureID; if (m_softDisplay.RGB24) { + auto offset = (m_softDisplay.DisplayPosition.x * 2) % 3; textureID = m_vramTexture24; glBindTexture(GL_TEXTURE_2D, textureID); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 682, 512, GL_RGB, GL_UNSIGNED_BYTE, m_vram16); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 682, 512, GL_RGB, GL_UNSIGNED_BYTE, m_vram + offset); } else { textureID = m_vramTexture16; glBindTexture(GL_TEXTURE_2D, textureID); From a26ec9b50413359152a0b68d12352b5997bb44a2 Mon Sep 17 00:00:00 2001 From: "codesee-maps[bot]" <86324825+codesee-maps[bot]@users.noreply.github.com> Date: Mon, 24 Jul 2023 22:36:12 +0000 Subject: [PATCH 28/29] Install the CodeSee workflow. Learn more at https://docs.codesee.io --- .github/workflows/codesee-arch-diagram.yml | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/codesee-arch-diagram.yml diff --git a/.github/workflows/codesee-arch-diagram.yml b/.github/workflows/codesee-arch-diagram.yml new file mode 100644 index 000000000..806d41d12 --- /dev/null +++ b/.github/workflows/codesee-arch-diagram.yml @@ -0,0 +1,23 @@ +# This workflow was added by CodeSee. Learn more at https://codesee.io/ +# This is v2.0 of this workflow file +on: + push: + branches: + - main + pull_request_target: + types: [opened, synchronize, reopened] + +name: CodeSee + +permissions: read-all + +jobs: + codesee: + runs-on: ubuntu-latest + continue-on-error: true + name: Analyze the repo with CodeSee + steps: + - uses: Codesee-io/codesee-action@v2 + with: + codesee-token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }} + codesee-url: https://app.codesee.io From 6457b0f188e2c6904dfd931b59a8f0ab24ef83c6 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 25 Jul 2023 20:10:02 -0700 Subject: [PATCH 29/29] Only interrupts should be skipped while stepping. --- src/core/debug.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/debug.cc b/src/core/debug.cc index a688d81e0..35aa97566 100644 --- a/src/core/debug.cc +++ b/src/core/debug.cc @@ -160,7 +160,10 @@ void PCSX::Debug::process(uint32_t oldPC, uint32_t newPC, uint32_t oldCode, uint } if (m_step == STEP_NONE) return; - if (!m_wasInISR && g_emulator->m_cpu->m_inISR) return; + if (!m_wasInISR && g_emulator->m_cpu->m_inISR) { + uint32_t cause = (regs.CP0.n.Cause >> 2) & 0x1f; + if (cause == 0) return; + } switch (m_step) { case STEP_IN: {