From 63d7250d2bad5791276b4902277905977645b9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Mon, 20 Jan 2025 13:36:11 +0100 Subject: [PATCH 001/267] Remove legacy configuration support LoadLegacyConfig was written five years ago, I believe we're confident enough that most configurations have been migrated by now. --- Source/Core/Core/HotkeyManager.cpp | 38 ------------------------------ 1 file changed, 38 deletions(-) diff --git a/Source/Core/Core/HotkeyManager.cpp b/Source/Core/Core/HotkeyManager.cpp index 5178377aef34..87a225e3afc6 100644 --- a/Source/Core/Core/HotkeyManager.cpp +++ b/Source/Core/Core/HotkeyManager.cpp @@ -253,43 +253,6 @@ bool IsPressed(int id, bool held) return false; } -// This function exists to load the old "Keys" group so pre-existing configs don't break. -// TODO: Remove this at a future date when we're confident most configs are migrated. -static void LoadLegacyConfig(ControllerEmu::EmulatedController* controller) -{ - Common::IniFile inifile; - if (inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Hotkeys.ini")) - { - if (!inifile.Exists("Hotkeys") && inifile.Exists("Hotkeys1")) - { - auto sec = inifile.GetOrCreateSection("Hotkeys1"); - - { - std::string defdev; - sec->Get("Device", &defdev, ""); - controller->SetDefaultDevice(defdev); - } - - for (auto& group : controller->groups) - { - for (auto& control : group->controls) - { - std::string key("Keys/" + control->name); - - if (sec->Exists(key)) - { - std::string expression; - sec->Get(key, &expression, ""); - control->control_ref->SetExpression(std::move(expression)); - } - } - } - - controller->UpdateReferences(g_controller_interface); - } - } -} - void Initialize() { if (s_config.ControllersNeedToBeCreated()) @@ -308,7 +271,6 @@ void Initialize() void LoadConfig() { s_config.LoadConfig(); - LoadLegacyConfig(s_config.GetController(0)); } ControllerEmu::ControlGroup* GetHotkeyGroup(HotkeyGroup group) From a1bdc40245eb9b7aad1d2e0374d589cfd2db8ccc Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 26 Oct 2025 23:24:45 -0500 Subject: [PATCH 002/267] CMake: Default SKIP_POSTPROCESS_BUNDLE to ON Most users do not need it --- BuildMacOSUniversalBinary.py | 2 ++ CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/BuildMacOSUniversalBinary.py b/BuildMacOSUniversalBinary.py index 5eff0d0cfc44..a4d421765a1d 100755 --- a/BuildMacOSUniversalBinary.py +++ b/BuildMacOSUniversalBinary.py @@ -295,6 +295,8 @@ def build(config): "-DENABLE_AUTOUPDATE=" + python_to_cmake_bool(config["autoupdate"]), '-DDISTRIBUTOR=' + config['distributor'], + # Distributable bundles need to be postprocessed to embed dependencies + "-DSKIP_POSTPROCESS_BUNDLE=OFF", # Always use libraries from Externals to prevent any libraries # installed by Homebrew from leaking in to the app "-DUSE_SYSTEM_LIBS=OFF", diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c708e9987a8..bbd80fd46d50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,7 +140,7 @@ if(APPLE) enable_language(OBJC) enable_language(OBJCXX) option(MACOS_USE_DEFAULT_SEARCH_PATH "Don't prioritize system library paths" OFF) - option(SKIP_POSTPROCESS_BUNDLE "Skip postprocessing bundle for redistributability" OFF) + option(SKIP_POSTPROCESS_BUNDLE "Skip postprocessing bundle for redistributability" ON) # Enable adhoc code signing by default (otherwise makefile builds on ARM will not work) option(MACOS_CODE_SIGNING "Enable codesigning" ON) option(USE_BUNDLED_MOLTENVK "Build MoltenVK from Externals with Dolphin-specific patches" ON) From 95701349b7a03b70bf72d1ce5dad7d5666720743 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Mon, 10 Mar 2025 17:25:34 -0500 Subject: [PATCH 003/267] DolphinAnalytics: Use Config::Get instead of accessing g_Config. --- Source/Core/Core/DolphinAnalytics.cpp | 64 ++++++++++++++++----------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/Source/Core/Core/DolphinAnalytics.cpp b/Source/Core/Core/DolphinAnalytics.cpp index 2d6b78429cd3..91dc14ac8a38 100644 --- a/Source/Core/Core/DolphinAnalytics.cpp +++ b/Source/Core/Core/DolphinAnalytics.cpp @@ -30,6 +30,7 @@ #include "Common/Random.h" #include "Common/Timer.h" #include "Common/Version.h" +#include "Core/Config/GraphicsSettings.h" #include "Core/Config/MainSettings.h" #include "Core/ConfigManager.h" #include "Core/HW/GCPad.h" @@ -329,9 +330,9 @@ void DolphinAnalytics::MakeBaseBuilder() m_base_builder = builder; } -static const char* GetShaderCompilationMode(const VideoConfig& video_config) +static const char* GetShaderCompilationMode() { - switch (video_config.iShaderCompilationMode) + switch (Config::Get(Config::GFX_SHADER_COMPILATION_MODE)) { case ShaderCompilationMode::AsynchronousUberShaders: return "async-ubershaders"; @@ -345,6 +346,11 @@ static const char* GetShaderCompilationMode(const VideoConfig& video_config) } } +static bool UseVertexRounding() +{ + return Config::Get(Config::GFX_HACK_VERTEX_ROUNDING) && Config::Get(Config::GFX_EFB_SCALE) != 1; +} + void DolphinAnalytics::MakePerGameBuilder() { Common::AnalyticsReportBuilder builder(m_base_builder); @@ -374,34 +380,40 @@ void DolphinAnalytics::MakePerGameBuilder() } // Video configuration. - builder.AddData("cfg-gfx-multisamples", g_Config.iMultisamples); - builder.AddData("cfg-gfx-ssaa", g_Config.bSSAA); - builder.AddData("cfg-gfx-anisotropy", Common::ToUnderlying(g_Config.iMaxAnisotropy)); - builder.AddData("cfg-gfx-vsync", g_Config.bVSync); - builder.AddData("cfg-gfx-aspect-ratio", static_cast(g_Config.aspect_mode)); - builder.AddData("cfg-gfx-efb-access", g_Config.bEFBAccessEnable); - builder.AddData("cfg-gfx-efb-copy-format-changes", g_Config.bEFBEmulateFormatChanges); - builder.AddData("cfg-gfx-efb-copy-ram", !g_Config.bSkipEFBCopyToRam); - builder.AddData("cfg-gfx-xfb-copy-ram", !g_Config.bSkipXFBCopyToRam); - builder.AddData("cfg-gfx-defer-efb-copies", g_Config.bDeferEFBCopies); - builder.AddData("cfg-gfx-immediate-xfb", !g_Config.bImmediateXFB); - builder.AddData("cfg-gfx-efb-copy-scaled", g_Config.bCopyEFBScaled); - builder.AddData("cfg-gfx-internal-resolution", g_Config.iEFBScale); - builder.AddData("cfg-gfx-tc-samples", g_Config.iSafeTextureCache_ColorSamples); - builder.AddData("cfg-gfx-stereo-mode", static_cast(g_Config.stereo_mode)); + builder.AddData("cfg-gfx-multisamples", Config::Get(Config::GFX_MSAA)); + builder.AddData("cfg-gfx-ssaa", Config::Get(Config::GFX_SSAA)); + builder.AddData("cfg-gfx-anisotropy", + Common::ToUnderlying(Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY))); + builder.AddData("cfg-gfx-vsync", Config::Get(Config::GFX_VSYNC)); + builder.AddData("cfg-gfx-aspect-ratio", static_cast(Config::Get(Config::GFX_ASPECT_RATIO))); + builder.AddData("cfg-gfx-efb-access", Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE)); + builder.AddData("cfg-gfx-efb-copy-format-changes", + Config::Get(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES)); + builder.AddData("cfg-gfx-efb-copy-ram", !Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM)); + builder.AddData("cfg-gfx-xfb-copy-ram", !Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM)); + builder.AddData("cfg-gfx-defer-efb-copies", Config::Get(Config::GFX_HACK_DEFER_EFB_COPIES)); + // Note: Incorrectly inverted. Keeping as-is to not break analytics history. + builder.AddData("cfg-gfx-immediate-xfb", !Config::Get(Config::GFX_HACK_IMMEDIATE_XFB)); + builder.AddData("cfg-gfx-efb-copy-scaled", Config::Get(Config::GFX_HACK_COPY_EFB_SCALED)); + builder.AddData("cfg-gfx-internal-resolution", Config::Get(Config::GFX_EFB_SCALE)); + builder.AddData("cfg-gfx-tc-samples", Config::Get(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES)); + builder.AddData("cfg-gfx-stereo-mode", static_cast(Config::Get(Config::GFX_STEREO_MODE))); builder.AddData("cfg-gfx-stereo-per-eye-resolution-full", - g_Config.stereo_per_eye_resolution_full); - builder.AddData("cfg-gfx-hdr", static_cast(g_Config.bHDR)); - builder.AddData("cfg-gfx-per-pixel-lighting", g_Config.bEnablePixelLighting); - builder.AddData("cfg-gfx-shader-compilation-mode", GetShaderCompilationMode(g_Config)); - builder.AddData("cfg-gfx-wait-for-shaders", g_Config.bWaitForShadersBeforeStarting); - builder.AddData("cfg-gfx-fast-depth", g_Config.bFastDepthCalc); - builder.AddData("cfg-gfx-vertex-rounding", g_Config.UseVertexRounding()); + Config::Get(Config::GFX_STEREO_PER_EYE_RESOLUTION_FULL)); + // Note: An int for some reason. Keeping as-is to not break analytics history. + builder.AddData("cfg-gfx-hdr", static_cast(Config::Get(Config::GFX_ENHANCE_HDR_OUTPUT))); + builder.AddData("cfg-gfx-per-pixel-lighting", Config::Get(Config::GFX_ENABLE_PIXEL_LIGHTING)); + builder.AddData("cfg-gfx-shader-compilation-mode", GetShaderCompilationMode()); + builder.AddData("cfg-gfx-wait-for-shaders", + Config::Get(Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING)); + builder.AddData("cfg-gfx-fast-depth", Config::Get(Config::GFX_FAST_DEPTH_CALC)); + builder.AddData("cfg-gfx-vertex-rounding", UseVertexRounding()); // GPU features. - if (g_Config.iAdapter < static_cast(g_backend_info.Adapters.size())) + const int adapter_index = Config::Get(Config::GFX_ADAPTER); + if (adapter_index < static_cast(g_backend_info.Adapters.size())) { - builder.AddData("gpu-adapter", g_backend_info.Adapters[g_Config.iAdapter]); + builder.AddData("gpu-adapter", g_backend_info.Adapters[adapter_index]); } else if (!g_backend_info.AdapterName.empty()) { From 5e65536376ab4b2085cb34a69c6d01bb7fbf9ea8 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Tue, 14 Oct 2025 22:39:17 -0500 Subject: [PATCH 004/267] WindowsDevice: Add GetDeviceInterfaceList function and NullTerminatedStringList template. --- Source/Core/Common/WindowsDevice.cpp | 30 +++++++++++++++++++ Source/Core/Common/WindowsDevice.h | 43 ++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/Source/Core/Common/WindowsDevice.cpp b/Source/Core/Common/WindowsDevice.cpp index 405ea5e25b77..9102f24b93d6 100644 --- a/Source/Core/Common/WindowsDevice.cpp +++ b/Source/Core/Common/WindowsDevice.cpp @@ -83,6 +83,36 @@ std::optional GetDeviceInterfaceStringProperty(LPCWSTR iface, DEVPROP_TYPE_STRING); } +NullTerminatedStringList GetDeviceInterfaceList(LPGUID iface_class_guid, DEVINSTID device_id, + ULONG flags) +{ + while (true) + { + ULONG list_size = 0; + const auto size_result = + CM_Get_Device_Interface_List_Size(&list_size, iface_class_guid, device_id, flags); + if (size_result != CR_SUCCESS || list_size == 0) + list_size = 1; + + auto buffer = std::make_unique_for_overwrite(list_size); + const auto list_result = + CM_Get_Device_Interface_List(iface_class_guid, device_id, buffer.get(), list_size, flags); + + // "A new device can be added to the system causing the size returned to no longer be valid." + // Microsoft recommends trying again in a loop. + if (list_result == CR_BUFFER_SMALL) + continue; + + if (list_result != CR_SUCCESS) + { + ERROR_LOG_FMT(COMMON, "CM_Get_Device_Interface_List: {}", list_result); + buffer[0] = 0; + } + + return {std::move(buffer)}; + } +} + } // namespace Common #endif diff --git a/Source/Core/Common/WindowsDevice.h b/Source/Core/Common/WindowsDevice.h index 463c6299b4ec..43acaa5092fe 100644 --- a/Source/Core/Common/WindowsDevice.h +++ b/Source/Core/Common/WindowsDevice.h @@ -5,6 +5,8 @@ #ifdef _WIN32 +#include +#include #include #include @@ -32,6 +34,47 @@ std::optional GetDevNodeStringProperty(DEVINST device, std::optional GetDeviceInterfaceStringProperty(LPCWSTR iface, const DEVPROPKEY* requested_property); +// Allows iterating null-separated/terminated string lists returned by the Windows API. +template +struct NullTerminatedStringList +{ + class Iterator + { + friend NullTerminatedStringList; + + public: + constexpr T* operator*() { return m_ptr; } + + constexpr Iterator& operator++() + { + m_ptr += std::basic_string_view(m_ptr).size() + 1; + return *this; + } + + constexpr Iterator operator++(int) + { + const auto result{*this}; + ++*this; + return result; + } + + constexpr bool operator==(std::default_sentinel_t) const { return *m_ptr == T{}; } + + private: + constexpr Iterator(T* ptr) : m_ptr{ptr} {} + + T* m_ptr; + }; + + constexpr auto begin() const { return Iterator{list.get()}; } + constexpr auto end() const { return std::default_sentinel; } + + std::unique_ptr list; +}; + +NullTerminatedStringList GetDeviceInterfaceList(LPGUID iface_class_guid, DEVINSTID device_id, + ULONG flags); + } // namespace Common #endif From 24426267719faa2a09ce4837e9f79ba3234f27af Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Tue, 14 Oct 2025 22:39:55 -0500 Subject: [PATCH 005/267] USBUtils: Replace GetDeviceNameUsingSetupAPI with GetDeviceNameUsingCfgMgr32. SetupAPI seems to be no longer recommended. --- Source/Core/Core/USBUtils.cpp | 50 ++++++++++++++++------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/Source/Core/Core/USBUtils.cpp b/Source/Core/Core/USBUtils.cpp index b2edfd0b22a3..79b3a1958c46 100644 --- a/Source/Core/Core/USBUtils.cpp +++ b/Source/Core/Core/USBUtils.cpp @@ -3,6 +3,7 @@ #include "Core/USBUtils.h" +#include #include #include #include @@ -21,9 +22,11 @@ #include #endif #ifdef _WIN32 -#include #include #include +#include +// initguid.h must be included before usbiodef.h +#include #include "Common/StringUtil.h" #include "Common/WindowsDevice.h" @@ -119,43 +122,36 @@ static std::optional GetDeviceNameUsingKnownDevices(u16 vid, u16 pi } #ifdef _WIN32 -static std::optional GetDeviceNameUsingSetupAPI(u16 vid, u16 pid) +static std::optional GetDeviceNameUsingCfgMgr32(u16 vid, u16 pid) { - std::optional device_name; + auto class_guid = GUID_DEVINTERFACE_USB_DEVICE; + const ULONG flags = CM_GET_DEVICE_INTERFACE_LIST_PRESENT; const std::wstring filter = fmt::format(L"VID_{:04X}&PID_{:04X}", vid, pid); - HDEVINFO dev_info = - SetupDiGetClassDevs(nullptr, nullptr, nullptr, DIGCF_PRESENT | DIGCF_ALLCLASSES); - if (dev_info == INVALID_HANDLE_VALUE) - return std::nullopt; - SP_DEVINFO_DATA dev_info_data; - dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA); - - for (DWORD i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); ++i) + for (auto* iface : Common::GetDeviceInterfaceList(&class_guid, nullptr, flags)) { - TCHAR instance_id[MAX_DEVICE_ID_LEN]; - if (CM_Get_Device_ID(dev_info_data.DevInst, instance_id, MAX_DEVICE_ID_LEN, 0) != CR_SUCCESS) + if (!std::basic_string_view{iface}.contains(filter)) continue; - const std::wstring_view id_wstr(instance_id); - if (id_wstr.find(filter) == std::wstring::npos) - continue; + auto dev_inst_id = Common::GetDeviceInterfaceStringProperty(iface, &DEVPKEY_Device_InstanceId); + if (!dev_inst_id.has_value()) + return std::nullopt; - std::wstring property_value = - Common::GetDeviceProperty(dev_info, &dev_info_data, &DEVPKEY_Device_FriendlyName); - if (property_value.empty()) + DEVINST dev_inst{}; + if (CM_Locate_DevNode(&dev_inst, dev_inst_id->data(), CM_LOCATE_DEVNODE_NORMAL) != CR_SUCCESS) { - property_value = - Common::GetDeviceProperty(dev_info, &dev_info_data, &DEVPKEY_Device_DeviceDesc); + ERROR_LOG_FMT(COMMON, "CM_Locate_DevNode"); + return std::nullopt; } - if (!property_value.empty()) - device_name = WStringToUTF8(property_value); - break; + // FYI: BusReportedDeviceDesc seems to be more of a friendly name + // while DeviceDesc tends to be something more like "USB Input Device". + return Common::GetDevNodeStringProperty(dev_inst, &DEVPKEY_Device_BusReportedDeviceDesc) + .or_else(std::bind(Common::GetDevNodeStringProperty, dev_inst, &DEVPKEY_Device_DeviceDesc)) + .transform(WStringToUTF8); } - SetupDiDestroyDeviceInfoList(dev_info); - return device_name; + return std::nullopt; } #endif @@ -245,7 +241,7 @@ std::optional GetDeviceNameFromVIDPID(u16 vid, u16 pid) &GetDeviceNameUsingHWDB, #endif #ifdef _WIN32 - &GetDeviceNameUsingSetupAPI, + &GetDeviceNameUsingCfgMgr32, #endif #if defined(__LIBUSB__) && !defined(_WIN32) &GetDeviceNameUsingLibUSB, From 2fb1fdfb16d5e45888fc327f850cd3d78330ce96 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Tue, 14 Oct 2025 22:13:05 -0500 Subject: [PATCH 006/267] WiimoteReal/IOWin: Use Common::GetDeviceInterfaceList. --- Source/Core/Core/HW/WiimoteReal/IOWin.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp index af442355cd40..d44428feaf48 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp @@ -583,20 +583,8 @@ auto WiimoteScannerWindows::FindWiimoteHIDDevices() -> FindResults // Enumerate connected HID interfaces IDs. auto class_guid = GUID_DEVINTERFACE_HID; constexpr ULONG flags = CM_GET_DEVICE_INTERFACE_LIST_PRESENT; - ULONG list_size = 0; - CM_Get_Device_Interface_List_Size(&list_size, &class_guid, nullptr, flags); - const auto buffer = std::make_unique_for_overwrite(list_size); - const auto list_result = - CM_Get_Device_Interface_List(&class_guid, nullptr, buffer.get(), list_size, flags); - if (list_result != CR_SUCCESS) - { - ERROR_LOG_FMT(WIIMOTE, "CM_Get_Device_Interface_List: {}", list_result); - return results; - } - - for (const WCHAR* hid_iface = buffer.get(); *hid_iface != L'\0'; - hid_iface += wcslen(hid_iface) + 1) + for (auto* hid_iface : Common::GetDeviceInterfaceList(&class_guid, nullptr, flags)) { // TODO: WiimoteWindows::GetId() does a redundant conversion. const auto hid_iface_utf8 = WStringToUTF8(hid_iface); From 28be9dc64f50bd5102a65495627830c2c258e54c Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Tue, 14 Oct 2025 22:32:12 -0500 Subject: [PATCH 007/267] WindowsDevice: Remove GetDeviceProperty function in favor of the CfgMgr32 versions. SetupAPI seems to be no longer recommended. --- Source/Core/Common/WindowsDevice.cpp | 23 ----------------------- Source/Core/Common/WindowsDevice.h | 4 ---- 2 files changed, 27 deletions(-) diff --git a/Source/Core/Common/WindowsDevice.cpp b/Source/Core/Common/WindowsDevice.cpp index 9102f24b93d6..4bbd21377499 100644 --- a/Source/Core/Common/WindowsDevice.cpp +++ b/Source/Core/Common/WindowsDevice.cpp @@ -14,29 +14,6 @@ namespace Common { -std::wstring GetDeviceProperty(const HDEVINFO& device_info, const PSP_DEVINFO_DATA device_data, - const DEVPROPKEY* requested_property) -{ - DWORD required_size = 0; - DEVPROPTYPE device_property_type; - BOOL result; - - result = SetupDiGetDeviceProperty(device_info, device_data, requested_property, - &device_property_type, nullptr, 0, &required_size, 0); - if (!result && GetLastError() != ERROR_INSUFFICIENT_BUFFER) - return std::wstring(); - - std::vector unicode_buffer(required_size / sizeof(TCHAR)); - - result = SetupDiGetDeviceProperty( - device_info, device_data, requested_property, &device_property_type, - reinterpret_cast(unicode_buffer.data()), required_size, nullptr, 0); - if (!result) - return std::wstring(); - - return std::wstring(unicode_buffer.data()); -} - std::optional GetPropertyHelper(auto function, auto dev, const DEVPROPKEY* requested_property, DEVPROPTYPE expected_type) diff --git a/Source/Core/Common/WindowsDevice.h b/Source/Core/Common/WindowsDevice.h index 43acaa5092fe..8c682ac8500d 100644 --- a/Source/Core/Common/WindowsDevice.h +++ b/Source/Core/Common/WindowsDevice.h @@ -24,10 +24,6 @@ namespace Common { -// Obtains a device property and returns it as a wide string. -std::wstring GetDeviceProperty(const HANDLE& device_info, const PSP_DEVINFO_DATA device_data, - const DEVPROPKEY* requested_property); - std::optional GetDevNodeStringProperty(DEVINST device, const DEVPROPKEY* requested_property); From 165852023c733078e3c733504adc1d1ec15755e5 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Fri, 19 Sep 2025 12:49:39 -0500 Subject: [PATCH 008/267] MemTools: Clean up SIGSEGV handler. --- Source/Core/Core/MemTools.cpp | 82 +++++++++++++---------------------- 1 file changed, 30 insertions(+), 52 deletions(-) diff --git a/Source/Core/Core/MemTools.cpp b/Source/Core/Core/MemTools.cpp index 75d20dd6a94c..f9e7eef64d3f 100644 --- a/Source/Core/Core/MemTools.cpp +++ b/Source/Core/Core/MemTools.cpp @@ -258,73 +258,51 @@ bool IsExceptionHandlerSupported() #elif defined(_POSIX_VERSION) && !defined(_M_GENERIC) static struct sigaction old_sa_segv; +#if defined(__APPLE__) static struct sigaction old_sa_bus; +#endif static void sigsegv_handler(int sig, siginfo_t* info, void* raw_context) { - if (sig != SIGSEGV && sig != SIGBUS) + if (sig != SIGSEGV +#if defined(__APPLE__) + && sig != SIGBUS +#endif + ) { // We are not interested in other signals - handle it as usual. return; } - ucontext_t* context = (ucontext_t*)raw_context; - int sicode = info->si_code; + auto* const context = static_cast(raw_context); + const int sicode = info->si_code; if (sicode != SEGV_MAPERR && sicode != SEGV_ACCERR) { // Huh? Return. return; } - uintptr_t bad_address = (uintptr_t)info->si_addr; + const auto bad_address = reinterpret_cast(info->si_addr); // Get all the information we can out of the context. #ifdef __OpenBSD__ - ucontext_t* ctx = context; + SContext* const ctx = context; +#elif defined(__APPLE__) + // `uc_mcontext` is already a pointer here. + SContext* const ctx = context->uc_mcontext; #else - mcontext_t* ctx = &context->uc_mcontext; + SContext* const ctx = &context->uc_mcontext; #endif - // assume it's not a write - if (!Core::System::GetInstance().GetJitInterface().HandleFault(bad_address, -#ifdef __APPLE__ - *ctx -#else - ctx + if (Core::System::GetInstance().GetJitInterface().HandleFault(bad_address, ctx)) + return; + + // If JIT didn't handle the signal, restore the original handler and invoke it. + const auto& old_sa = +#if defined(__APPLE__) + (sig == SIGBUS) ? old_sa_bus : #endif - )) - { - // retry and crash - // According to the sigaction man page, if sa_flags "SA_SIGINFO" is set to the sigaction - // function pointer, otherwise sa_handler contains one of: - // SIG_DEF: The 'default' action is performed - // SIG_IGN: The signal is ignored - // Any other value is a function pointer to a signal handler - - struct sigaction* old_sa; - if (sig == SIGSEGV) - { - old_sa = &old_sa_segv; - } - else - { - old_sa = &old_sa_bus; - } + old_sa_segv; - if (old_sa->sa_flags & SA_SIGINFO) - { - old_sa->sa_sigaction(sig, info, raw_context); - return; - } - if (old_sa->sa_handler == SIG_DFL) - { - signal(sig, SIG_DFL); - return; - } - if (old_sa->sa_handler == SIG_IGN) - { - // Ignore signal - return; - } - old_sa->sa_handler(sig); - } + sigaction(sig, &old_sa, nullptr); + raise(sig); } void InstallExceptionHandler() @@ -337,10 +315,9 @@ void InstallExceptionHandler() #endif signal_stack.ss_size = SIGSTKSZ; signal_stack.ss_flags = 0; - if (sigaltstack(&signal_stack, nullptr)) - PanicAlertFmt("sigaltstack failed"); - struct sigaction sa; - sa.sa_handler = nullptr; + if (sigaltstack(&signal_stack, nullptr) != 0) + PanicAlertFmt("sigaltstack failed: {}", Common::LastStrerrorString()); + struct sigaction sa{}; sa.sa_sigaction = &sigsegv_handler; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); @@ -352,7 +329,8 @@ void InstallExceptionHandler() void UninstallExceptionHandler() { - stack_t signal_stack, old_stack; + stack_t signal_stack; + stack_t old_stack; signal_stack.ss_flags = SS_DISABLE; if (!sigaltstack(&signal_stack, &old_stack) && !(old_stack.ss_flags & SS_DISABLE)) { From 1804608d2f00ac25b5c12a687d316f1c00ce8380 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 9 Nov 2025 22:35:16 -0600 Subject: [PATCH 009/267] CMake: Switch from SKIP_POSTPROCESS_BUNDLE to POSTPROCESS_BUNDLE --- BuildMacOSUniversalBinary.py | 2 +- CMakeLists.txt | 2 +- Source/Core/DolphinQt/CMakeLists.txt | 2 +- Source/Core/MacUpdater/CMakeLists.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/BuildMacOSUniversalBinary.py b/BuildMacOSUniversalBinary.py index a4d421765a1d..3fc84a1c15f2 100755 --- a/BuildMacOSUniversalBinary.py +++ b/BuildMacOSUniversalBinary.py @@ -296,7 +296,7 @@ def build(config): + python_to_cmake_bool(config["autoupdate"]), '-DDISTRIBUTOR=' + config['distributor'], # Distributable bundles need to be postprocessed to embed dependencies - "-DSKIP_POSTPROCESS_BUNDLE=OFF", + "-DPOSTPROCESS_BUNDLE=ON", # Always use libraries from Externals to prevent any libraries # installed by Homebrew from leaking in to the app "-DUSE_SYSTEM_LIBS=OFF", diff --git a/CMakeLists.txt b/CMakeLists.txt index bbd80fd46d50..c6690a886e20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,7 +140,7 @@ if(APPLE) enable_language(OBJC) enable_language(OBJCXX) option(MACOS_USE_DEFAULT_SEARCH_PATH "Don't prioritize system library paths" OFF) - option(SKIP_POSTPROCESS_BUNDLE "Skip postprocessing bundle for redistributability" ON) + option(POSTPROCESS_BUNDLE "Postprocess bundle for redistributability" OFF) # Enable adhoc code signing by default (otherwise makefile builds on ARM will not work) option(MACOS_CODE_SIGNING "Enable codesigning" ON) option(USE_BUNDLED_MOLTENVK "Build MoltenVK from Externals with Dolphin-specific patches" ON) diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 93c85a399728..b4d81654faa2 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -661,7 +661,7 @@ if(APPLE) endif() endif() - if(NOT SKIP_POSTPROCESS_BUNDLE) + if(POSTPROCESS_BUNDLE) # Update library references to make the bundle portable include(DolphinPostprocessBundle) dolphin_postprocess_bundle(dolphin-emu) diff --git a/Source/Core/MacUpdater/CMakeLists.txt b/Source/Core/MacUpdater/CMakeLists.txt index da6d052fa5c2..3909e1bcf0ff 100644 --- a/Source/Core/MacUpdater/CMakeLists.txt +++ b/Source/Core/MacUpdater/CMakeLists.txt @@ -54,7 +54,7 @@ endforeach() include(DolphinInjectVersionInfo) dolphin_inject_version_info(MacUpdater) -if(NOT SKIP_POSTPROCESS_BUNDLE) +if(POSTPROCESS_BUNDLE) # Update library references to make the bundle portable include(DolphinPostprocessBundle) dolphin_postprocess_bundle(MacUpdater) From be95035cc47fe747c567a3907e9086da89437d67 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Wed, 12 Nov 2025 17:22:41 -0600 Subject: [PATCH 010/267] Core: Eliminate FreeLookConfig by putting the "active config" within FreeLookCamera. --- Source/Core/Core/CMakeLists.txt | 2 - Source/Core/Core/Config/FreeLookSettings.cpp | 5 -- Source/Core/Core/Config/FreeLookSettings.h | 9 ++- Source/Core/Core/FreeLookConfig.cpp | 64 -------------------- Source/Core/Core/FreeLookConfig.h | 41 ------------- Source/Core/Core/FreeLookManager.cpp | 8 +-- Source/Core/DolphinLib.props | 2 - Source/Core/VideoCommon/FreeLookCamera.cpp | 30 ++++----- Source/Core/VideoCommon/FreeLookCamera.h | 10 ++- Source/Core/VideoCommon/VideoConfig.cpp | 3 +- 10 files changed, 29 insertions(+), 145 deletions(-) delete mode 100644 Source/Core/Core/FreeLookConfig.cpp delete mode 100644 Source/Core/Core/FreeLookConfig.h diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index c898c8f693e7..366700536f65 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -123,8 +123,6 @@ add_library(core FifoPlayer/FifoPlayer.h FifoPlayer/FifoRecorder.cpp FifoPlayer/FifoRecorder.h - FreeLookConfig.cpp - FreeLookConfig.h FreeLookManager.cpp FreeLookManager.h GeckoCode.cpp diff --git a/Source/Core/Core/Config/FreeLookSettings.cpp b/Source/Core/Core/Config/FreeLookSettings.cpp index d66400bbe7c3..405a6029498b 100644 --- a/Source/Core/Core/Config/FreeLookSettings.cpp +++ b/Source/Core/Core/Config/FreeLookSettings.cpp @@ -3,11 +3,6 @@ #include "Core/Config/FreeLookSettings.h" -#include - -#include "Common/Config/Config.h" -#include "Core/FreeLookConfig.h" - namespace Config { // Configuration Information diff --git a/Source/Core/Core/Config/FreeLookSettings.h b/Source/Core/Core/Config/FreeLookSettings.h index 367173a0a4c0..3d1375940b05 100644 --- a/Source/Core/Core/Config/FreeLookSettings.h +++ b/Source/Core/Core/Config/FreeLookSettings.h @@ -3,11 +3,16 @@ #pragma once -#include "Common/Config/Config.h" +#include "Common/Config/ConfigInfo.h" namespace FreeLook { -enum class ControlType : int; +enum class ControlType : int +{ + SixAxis, + FPS, + Orbital +}; } namespace Config diff --git a/Source/Core/Core/FreeLookConfig.cpp b/Source/Core/Core/FreeLookConfig.cpp deleted file mode 100644 index 56aadb9af2ab..000000000000 --- a/Source/Core/Core/FreeLookConfig.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2020 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "Core/FreeLookConfig.h" - -#include - -#include "Core/AchievementManager.h" -#include "Core/CPUThreadConfigCallback.h" -#include "Core/Config/AchievementSettings.h" -#include "Core/Config/FreeLookSettings.h" -#include "Core/ConfigManager.h" -#include "Core/Core.h" - -namespace FreeLook -{ -static Config s_config; -static Config s_active_config; -static std::optional - s_config_changed_callback_id = std::nullopt; - -Config& GetConfig() -{ - return s_config; -} - -const Config& GetActiveConfig() -{ - return s_active_config; -} - -void UpdateActiveConfig() -{ - s_active_config = s_config; -} - -Config::Config() -{ - camera_config.control_type = ControlType::SixAxis; - enabled = false; -} - -void Config::Refresh() -{ - if (!s_config_changed_callback_id.has_value()) - { - s_config_changed_callback_id = - CPUThreadConfigCallback::AddConfigChangedCallback([] { s_config.Refresh(); }); - } - - camera_config.control_type = ::Config::Get(::Config::FL1_CONTROL_TYPE); - enabled = ::Config::Get(::Config::FREE_LOOK_ENABLED) && - !AchievementManager::GetInstance().IsHardcoreModeActive(); -} - -void Config::Shutdown() -{ - if (!s_config_changed_callback_id.has_value()) - return; - - CPUThreadConfigCallback::RemoveConfigChangedCallback(*s_config_changed_callback_id); - s_config_changed_callback_id.reset(); -} -} // namespace FreeLook diff --git a/Source/Core/Core/FreeLookConfig.h b/Source/Core/Core/FreeLookConfig.h deleted file mode 100644 index 5819d81269c9..000000000000 --- a/Source/Core/Core/FreeLookConfig.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2020 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -// IMPORTANT: UI etc should modify the value returned by FreeLook::GetConfig(). -// Free Look code should read from the value returned by FreeLook::GetActiveConfig(). -// The reason for this is to get rid of race conditions etc when the -// configuration changes in the middle of a frame. - -#pragma once - -namespace FreeLook -{ -enum class ControlType : int -{ - SixAxis, - FPS, - Orbital -}; - -struct CameraConfig -{ - ControlType control_type; -}; - -// NEVER inherit from this class. -struct Config final -{ - Config(); - void Refresh(); - void Shutdown(); - - CameraConfig camera_config; - bool enabled; -}; - -Config& GetConfig(); -const Config& GetActiveConfig(); - -// Called every frame. -void UpdateActiveConfig(); -} // namespace FreeLook diff --git a/Source/Core/Core/FreeLookManager.cpp b/Source/Core/Core/FreeLookManager.cpp index 58b71b708f3e..9dc23e893440 100644 --- a/Source/Core/Core/FreeLookManager.cpp +++ b/Source/Core/Core/FreeLookManager.cpp @@ -7,14 +7,11 @@ #include #include "Common/Common.h" -#include "Common/CommonTypes.h" #include "Common/Config/Config.h" #include "Common/ScopeGuard.h" #include "Core/Config/FreeLookSettings.h" -#include "Core/ConfigManager.h" #include "Core/Core.h" -#include "Core/FreeLookConfig.h" #include "InputCommon/ControlReference/ControlReference.h" #include "InputCommon/ControllerEmu/ControlGroup/Buttons.h" @@ -22,7 +19,6 @@ #include "InputCommon/InputConfig.h" #include "VideoCommon/FreeLookCamera.h" -#include "VideoCommon/OnScreenDisplay.h" namespace { @@ -326,8 +322,6 @@ void Shutdown() { s_config.UnregisterHotplugCallback(); s_config.ClearControllers(); - - GetConfig().Shutdown(); } void Initialize() @@ -339,7 +333,7 @@ void Initialize() s_config.RegisterHotplugCallback(); - FreeLook::GetConfig().Refresh(); + g_freelook_camera.RefreshConfig(); s_config.LoadConfig(); } diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 17e44675ac2c..f1bbf2b56741 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -250,7 +250,6 @@ - @@ -933,7 +932,6 @@ - diff --git a/Source/Core/VideoCommon/FreeLookCamera.cpp b/Source/Core/VideoCommon/FreeLookCamera.cpp index 2bc7d11bb920..ba6be77d6ce7 100644 --- a/Source/Core/VideoCommon/FreeLookCamera.cpp +++ b/Source/Core/VideoCommon/FreeLookCamera.cpp @@ -4,18 +4,13 @@ #include "VideoCommon/FreeLookCamera.h" #include -#include #include -#include "Common/MathUtil.h" - #include "Common/ChunkFile.h" -#include "Core/ConfigManager.h" +#include "Common/Config/Config.h" #include "Core/Core.h" -#include "VideoCommon/VideoCommon.h" - FreeLookCamera g_freelook_camera; namespace @@ -260,21 +255,18 @@ float CameraControllerInput::GetSpeed() const FreeLookCamera::FreeLookCamera() { - SetControlType(FreeLook::ControlType::SixAxis); + RefreshConfig(); } -void FreeLookCamera::SetControlType(FreeLook::ControlType type) +void FreeLookCamera::RefreshConfig() { - if (m_current_type && *m_current_type == type) - { + m_is_enabled = Config::Get(Config::FREE_LOOK_ENABLED); + const auto type = Config::Get(Config::FL1_CONTROL_TYPE); + + if (m_current_type == type) return; - } - if (type == FreeLook::ControlType::SixAxis) - { - m_camera_controller = std::make_unique(); - } - else if (type == FreeLook::ControlType::Orbital) + if (type == FreeLook::ControlType::Orbital) { m_camera_controller = std::make_unique(); } @@ -282,6 +274,10 @@ void FreeLookCamera::SetControlType(FreeLook::ControlType type) { m_camera_controller = std::make_unique(); } + else + { + m_camera_controller = std::make_unique(); + } m_current_type = type; } @@ -330,7 +326,7 @@ void FreeLookCamera::DoState(PointerWrap& p) bool FreeLookCamera::IsActive() const { - return FreeLook::GetActiveConfig().enabled; + return m_is_enabled; } CameraController* FreeLookCamera::GetController() const diff --git a/Source/Core/VideoCommon/FreeLookCamera.h b/Source/Core/VideoCommon/FreeLookCamera.h index f1ae46ce4d2a..91c296ad16e1 100644 --- a/Source/Core/VideoCommon/FreeLookCamera.h +++ b/Source/Core/VideoCommon/FreeLookCamera.h @@ -7,7 +7,7 @@ #include #include "Common/Matrix.h" -#include "Core/FreeLookConfig.h" +#include "Core/Config/FreeLookSettings.h" class PointerWrap; @@ -79,7 +79,9 @@ class FreeLookCamera { public: FreeLookCamera(); - void SetControlType(FreeLook::ControlType type); + + void RefreshConfig(); + Common::Matrix44 GetView() const; Common::Vec2 GetFieldOfViewMultiplier() const; @@ -90,8 +92,10 @@ class FreeLookCamera CameraController* GetController() const; private: - std::optional m_current_type; std::unique_ptr m_camera_controller; + + bool m_is_enabled{}; + std::optional m_current_type; }; extern FreeLookCamera g_freelook_camera; diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index a15331569d89..d2cacd727624 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -305,10 +305,9 @@ void CheckForConfigChanges() const auto old_hdr = g_ActiveConfig.bHDR; UpdateActiveConfig(); - FreeLook::UpdateActiveConfig(); g_vertex_manager->OnConfigChange(); - g_freelook_camera.SetControlType(FreeLook::GetActiveConfig().camera_config.control_type); + g_freelook_camera.RefreshConfig(); if (g_ActiveConfig.bGraphicMods && !old_graphics_mods_enabled) { From 00959738fe72934e9de4e2404fb17ba3abaaebf1 Mon Sep 17 00:00:00 2001 From: Simonx22 Date: Tue, 18 Nov 2025 16:10:57 -0500 Subject: [PATCH 011/267] Android: Use Android's HandlerThread in ControllerInterface instead of our own implementation --- .../input/model/ControllerInterface.kt | 25 ++++---- .../dolphinemu/utils/LooperThread.java | 58 ------------------- 2 files changed, 15 insertions(+), 68 deletions(-) delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/LooperThread.java diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.kt index e09e0dec9969..9cf9b0e7a7b5 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.kt @@ -6,6 +6,7 @@ import android.content.Context import android.hardware.input.InputManager import android.os.Build import android.os.Handler +import android.os.HandlerThread import android.os.Looper import android.os.VibrationEffect import android.os.Vibrator @@ -17,7 +18,6 @@ import androidx.annotation.Keep import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import org.dolphinemu.dolphinemu.DolphinApplication -import org.dolphinemu.dolphinemu.utils.LooperThread import java.util.concurrent.atomic.AtomicBoolean /** @@ -26,9 +26,9 @@ import java.util.concurrent.atomic.AtomicBoolean */ object ControllerInterface { private var inputDeviceListener: InputDeviceListener? = null - private lateinit var looperThread: LooperThread + private var handlerThread: HandlerThread? = null - private var inputStateUpdatePending = AtomicBoolean(false) + private val inputStateUpdatePending = AtomicBoolean(false) private val inputStateVersion = MutableLiveData(0) private val devicesVersion = MutableLiveData(0) @@ -132,15 +132,18 @@ object ControllerInterface { @Keep @JvmStatic private fun registerInputDeviceListener() { - looperThread = LooperThread("Hotplug thread") - looperThread.start() - if (inputDeviceListener == null) { + handlerThread = HandlerThread("Hotplug thread").apply { start() } + val thread = requireNotNull(handlerThread) { "HandlerThread is not available" } + val im = DolphinApplication.getAppContext() - .getSystemService(Context.INPUT_SERVICE) as InputManager? + .getSystemService(Context.INPUT_SERVICE) as InputManager + val looper = requireNotNull(thread.looper) { + "HandlerThread looper is not available" + } inputDeviceListener = InputDeviceListener() - im!!.registerInputDeviceListener(inputDeviceListener, Handler(looperThread.looper)) + im.registerInputDeviceListener(inputDeviceListener, Handler(looper)) } } @@ -149,10 +152,12 @@ object ControllerInterface { private fun unregisterInputDeviceListener() { if (inputDeviceListener != null) { val im = DolphinApplication.getAppContext() - .getSystemService(Context.INPUT_SERVICE) as InputManager? + .getSystemService(Context.INPUT_SERVICE) as InputManager - im!!.unregisterInputDeviceListener(inputDeviceListener) + im.unregisterInputDeviceListener(inputDeviceListener) inputDeviceListener = null + handlerThread?.quitSafely() + handlerThread = null } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/LooperThread.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/LooperThread.java deleted file mode 100644 index 8a67ec7e890b..000000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/LooperThread.java +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.utils; - -import android.os.Looper; - -public class LooperThread extends Thread -{ - private Looper mLooper; - - public LooperThread() - { - super(); - } - - public LooperThread(String name) - { - super(name); - } - - @Override - public void run() - { - Looper.prepare(); - - synchronized (this) - { - mLooper = Looper.myLooper(); - notifyAll(); - } - - Looper.loop(); - } - - public Looper getLooper() - { - if (!isAlive()) - { - throw new IllegalStateException(); - } - - synchronized (this) - { - while (mLooper == null) - { - try - { - wait(); - } - catch (InterruptedException ignored) - { - } - } - } - - return mLooper; - } -} From 19f1d329c9216b4fbf055d9cfbec7426fee90f24 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Wed, 19 Nov 2025 02:16:58 -0600 Subject: [PATCH 012/267] Core: Remove unused HostMessageID enum members. --- Source/Core/Core/Core.cpp | 1 - Source/Core/Core/Host.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 58da62b4e886..a920d513d77a 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -322,7 +322,6 @@ static void CPUSetInitialExecutionState(bool force_paused = false) bool paused = SConfig::GetInstance().bBootToPause || force_paused; SetState(system, paused ? State::Paused : State::Running, true, true); Host_UpdateDisasmDialog(); - Host_Message(HostMessageID::WMUserCreate); }); } diff --git a/Source/Core/Core/Host.h b/Source/Core/Core/Host.h index a05508bae2c9..2c19e99f4c9d 100644 --- a/Source/Core/Core/Host.h +++ b/Source/Core/Core/Host.h @@ -43,8 +43,6 @@ enum class HostMessageID { // Begin at 10 in case there is already messages with wParam = 0, 1, 2 and so on WMUserStop = 10, - WMUserCreate, - WMUserSetCursor, WMUserJobDispatch, }; From 9f0a5c2a371e178711956aec97aa4df447b66d7d Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Wed, 19 Nov 2025 02:45:39 -0600 Subject: [PATCH 013/267] Core: Allow CPUManager::SetStepping to be called from the CPU thread so a call doesn't need to be routed through the host thread on boot. --- Source/Core/Core/Core.cpp | 19 ++++++++----------- Source/Core/Core/Core.h | 3 +-- Source/Core/Core/HW/CPU.cpp | 8 +++++--- Source/Core/Core/HW/CPU.h | 2 +- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index a920d513d77a..04ce3c75b84b 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -314,15 +314,12 @@ void UndeclareAsGPUThread() } // For the CPU Thread only. -static void CPUSetInitialExecutionState(bool force_paused = false) +static void CPUSetInitialExecutionState(Core::System& system, bool force_paused = false) { // The CPU starts in stepping state, and will wait until a new state is set before executing. - // SetState isn't safe to call from the CPU thread, so we ask the host thread to call it. - QueueHostJob([force_paused](Core::System& system) { - bool paused = SConfig::GetInstance().bBootToPause || force_paused; - SetState(system, paused ? State::Paused : State::Running, true, true); - Host_UpdateDisasmDialog(); - }); + const bool paused = SConfig::GetInstance().bBootToPause || force_paused; + SetState(system, paused ? State::Paused : State::Running, true, true); + Host_UpdateDisasmDialog(); } // Create the CPU thread, which is a CPU + Video thread in Single Core mode. @@ -371,7 +368,7 @@ static void CpuThread(Core::System& system, const std::optional& sa if (!gdb_socket.empty() && !AchievementManager::GetInstance().IsHardcoreModeActive()) { GDBStub::InitLocal(gdb_socket.data()); - CPUSetInitialExecutionState(true); + CPUSetInitialExecutionState(system, true); } else #endif @@ -380,11 +377,11 @@ static void CpuThread(Core::System& system, const std::optional& sa if (gdb_port > 0 && !AchievementManager::GetInstance().IsHardcoreModeActive()) { GDBStub::Init(gdb_port); - CPUSetInitialExecutionState(true); + CPUSetInitialExecutionState(system, true); } else { - CPUSetInitialExecutionState(); + CPUSetInitialExecutionState(system); } } } @@ -430,7 +427,7 @@ static void FifoPlayerThread(Core::System& system, const std::optional Date: Wed, 19 Nov 2025 16:53:10 -0500 Subject: [PATCH 014/267] Android: Convert Log to Kotlin --- .../org/dolphinemu/dolphinemu/utils/Log.java | 55 ------------------- .../org/dolphinemu/dolphinemu/utils/Log.kt | 49 +++++++++++++++++ 2 files changed, 49 insertions(+), 55 deletions(-) delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Log.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Log.kt diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Log.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Log.java deleted file mode 100644 index 2f695278724d..000000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Log.java +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.utils; - -import org.dolphinemu.dolphinemu.BuildConfig; - -/** - * Contains methods that call through to {@link android.util.Log}, but - * with the same TAG automatically provided. Also no-ops VERBOSE and DEBUG log - * levels in release builds. - */ -public final class Log -{ - private static final String TAG = "Dolphin"; - - private Log() - { - } - - public static void verbose(String message) - { - if (BuildConfig.DEBUG) - { - android.util.Log.v(TAG, message); - } - } - - public static void debug(String message) - { - if (BuildConfig.DEBUG) - { - android.util.Log.d(TAG, message); - } - } - - public static void info(String message) - { - android.util.Log.i(TAG, message); - } - - public static void warning(String message) - { - android.util.Log.w(TAG, message); - } - - public static void error(String message) - { - android.util.Log.e(TAG, message); - } - - public static void wtf(String message) - { - android.util.Log.wtf(TAG, message); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Log.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Log.kt new file mode 100644 index 000000000000..28a661ffd43f --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Log.kt @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.utils + +import org.dolphinemu.dolphinemu.BuildConfig +import android.util.Log as AndroidLog + +/** + * Contains methods that call through to [android.util.Log], but + * with the same TAG automatically provided. Also no-ops VERBOSE and DEBUG log + * levels in release builds. + */ +object Log { + private const val TAG = "Dolphin" + + @JvmStatic + fun verbose(message: String) { + if (BuildConfig.DEBUG) { + AndroidLog.v(TAG, message) + } + } + + @JvmStatic + fun debug(message: String) { + if (BuildConfig.DEBUG) { + AndroidLog.d(TAG, message) + } + } + + @JvmStatic + fun info(message: String) { + AndroidLog.i(TAG, message) + } + + @JvmStatic + fun warning(message: String) { + AndroidLog.w(TAG, message) + } + + @JvmStatic + fun error(message: String) { + AndroidLog.e(TAG, message) + } + + @JvmStatic + fun wtf(message: String) { + AndroidLog.wtf(TAG, message) + } +} From a4599a1adda5c1d445b70d0dfe70b50fe3888662 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Thu, 13 Nov 2025 21:44:29 -0600 Subject: [PATCH 015/267] VideoCommon: avoid assuming global state exists for 'EndUtilityDrawing', use last stored viewport/scissor rect instead --- Source/Core/VideoCommon/AbstractGfx.cpp | 16 +++++++++++++--- Source/Core/VideoCommon/AbstractGfx.h | 15 +++++++++++++++ Source/Core/VideoCommon/BPFunctions.cpp | 8 ++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/Source/Core/VideoCommon/AbstractGfx.cpp b/Source/Core/VideoCommon/AbstractGfx.cpp index 0e7e05e0f00e..3e31468f783a 100644 --- a/Source/Core/VideoCommon/AbstractGfx.cpp +++ b/Source/Core/VideoCommon/AbstractGfx.cpp @@ -34,10 +34,15 @@ void AbstractGfx::BeginUtilityDrawing() void AbstractGfx::EndUtilityDrawing() { - // Reset framebuffer/scissor/viewport. Pipeline will be reset at next draw. + // Reset framebuffer. Pipeline will be reset at next draw. g_framebuffer_manager->BindEFBFramebuffer(); - BPFunctions::SetScissorAndViewport(g_framebuffer_manager.get(), bpmem.scissorTL, bpmem.scissorBR, - bpmem.scissorOffset, xfmem.viewport); + + // Reset our viewport and scissor to the last stored value + SetViewport(m_viewport_and_scissor.viewport_x, m_viewport_and_scissor.viewport_y, + m_viewport_and_scissor.viewport_width, m_viewport_and_scissor.viewport_height, + m_viewport_and_scissor.viewport_near_depth, + m_viewport_and_scissor.viewport_far_depth); + SetScissorRect(m_viewport_and_scissor.scissor_rect); } void AbstractGfx::SetFramebuffer(AbstractFramebuffer* framebuffer) @@ -87,6 +92,11 @@ void AbstractGfx::ClearRegion(const MathUtil::Rectangle& target_rc, bool co EndUtilityDrawing(); } +void AbstractGfx::StoreViewportAndScissor(const ViewportAndScissor& viewport_and_scissor) +{ + m_viewport_and_scissor = viewport_and_scissor; +} + void AbstractGfx::SetViewportAndScissor(const MathUtil::Rectangle& rect, float min_depth, float max_depth) { diff --git a/Source/Core/VideoCommon/AbstractGfx.h b/Source/Core/VideoCommon/AbstractGfx.h index d9d14e1a1204..b1528b3bb12d 100644 --- a/Source/Core/VideoCommon/AbstractGfx.h +++ b/Source/Core/VideoCommon/AbstractGfx.h @@ -126,6 +126,20 @@ class AbstractGfx AbstractFramebuffer* GetCurrentFramebuffer() const { return m_current_framebuffer; } + struct ViewportAndScissor + { + MathUtil::Rectangle scissor_rect; + float viewport_x; + float viewport_y; + float viewport_width; + float viewport_height; + float viewport_near_depth; + float viewport_far_depth; + }; + + // Stores the last viewport and scissor, the stored data is restored in 'EndUtilityDrawing' + void StoreViewportAndScissor(const ViewportAndScissor& viewport_and_scissor); + // Sets viewport and scissor to the specified rectangle. rect is assumed to be in framebuffer // coordinates, i.e. lower-left origin in OpenGL. void SetViewportAndScissor(const MathUtil::Rectangle& rect, float min_depth = 0.0f, @@ -177,6 +191,7 @@ class AbstractGfx private: Common::EventHook m_config_changed; + ViewportAndScissor m_viewport_and_scissor; }; extern std::unique_ptr g_gfx; diff --git a/Source/Core/VideoCommon/BPFunctions.cpp b/Source/Core/VideoCommon/BPFunctions.cpp index 660d85c59897..134a14f8d471 100644 --- a/Source/Core/VideoCommon/BPFunctions.cpp +++ b/Source/Core/VideoCommon/BPFunctions.cpp @@ -265,6 +265,14 @@ void SetScissorAndViewport(FramebufferManager* frame_buffer_manager, ScissorPos y = static_cast(g_gfx->GetCurrentFramebuffer()->GetHeight()) - y - height; g_gfx->SetViewport(x, y, width, height, near_depth, far_depth); + + g_gfx->StoreViewportAndScissor(AbstractGfx::ViewportAndScissor{.scissor_rect = converted_rc, + .viewport_x = x, + .viewport_y = y, + .viewport_width = width, + .viewport_height = height, + .viewport_near_depth = near_depth, + .viewport_far_depth = far_depth}); } void SetDepthMode() From 4a89300929b470cacc0391719b9c29ac740a33f2 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Thu, 20 Nov 2025 03:12:59 -0600 Subject: [PATCH 016/267] CachedInterpreter: Replace reinterpret_cast with std::bit_cast to resolve -Wcast-function-type-mismatch warnings. --- .../Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp | 4 ++-- .../PowerPC/CachedInterpreter/CachedInterpreterEmitter.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp index a8733b91b604..e8cde761d8ab 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp +++ b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp @@ -68,12 +68,12 @@ void CachedInterpreter::ExecuteOneBlock() const auto callback = *reinterpret_cast(normal_entry); const u8* payload = normal_entry + sizeof(callback); // Direct dispatch to the most commonly used callbacks for better performance - if (callback == reinterpret_cast(CallbackCast(Interpret))) [[likely]] + if (callback == AnyCallbackCast(Interpret)) [[likely]] { Interpret(ppc_state, *reinterpret_cast(payload)); normal_entry = payload + sizeof(InterpretOperands); } - else if (callback == reinterpret_cast(CallbackCast(Interpret))) + else if (callback == AnyCallbackCast(Interpret)) { Interpret(ppc_state, *reinterpret_cast(payload)); normal_entry = payload + sizeof(InterpretOperands); diff --git a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreterEmitter.h b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreterEmitter.h index 7b1554ffc10f..9a07cc61d593 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreterEmitter.h +++ b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreterEmitter.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include #include @@ -33,7 +34,7 @@ class CachedInterpreterEmitter template static AnyCallback AnyCallbackCast(Callback callback) { - return reinterpret_cast(callback); + return std::bit_cast(callback); } static consteval AnyCallback AnyCallbackCast(AnyCallback callback) { return callback; } @@ -45,7 +46,7 @@ class CachedInterpreterEmitter template static AnyDisassemble AnyDisassembleCast(Disassemble disassemble) { - return reinterpret_cast(disassemble); + return std::bit_cast(disassemble); } static consteval AnyDisassemble AnyDisassembleCast(AnyDisassemble disassemble) { From 6e13a7d7e97adfc807c260fa80e4fdf91191d50a Mon Sep 17 00:00:00 2001 From: iwubcode Date: Thu, 20 Nov 2025 23:51:34 -0600 Subject: [PATCH 017/267] VideoCommon: fix MaterialAsset so that boolean parameters are written to memory as integers, matching the format internally expected by shaders --- Source/Core/VideoCommon/Assets/MaterialAsset.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/Core/VideoCommon/Assets/MaterialAsset.cpp b/Source/Core/VideoCommon/Assets/MaterialAsset.cpp index 5f5c97a9f1bd..200bccf333f4 100644 --- a/Source/Core/VideoCommon/Assets/MaterialAsset.cpp +++ b/Source/Core/VideoCommon/Assets/MaterialAsset.cpp @@ -197,7 +197,12 @@ void MaterialProperty::WriteToMemory(u8*& buffer, const MaterialProperty& proper [&](const std::array& value) { write_memory(value.data(), sizeof(float) * 2); }, [&](const std::array& value) { write_memory(value.data(), sizeof(float) * 3); }, [&](const std::array& value) { write_memory(value.data(), sizeof(float) * 4); }, - [&](bool value) { write_memory(&value, sizeof(bool)); }}, + + // Bool has the size of an int in the shader + [&](bool value) { + u32 val = static_cast(value); + write_memory(&val, sizeof(u32)); + }}, property.m_value); } From 75c66e35c68a791ab5415b1a120cc07321ad2e79 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Thu, 20 Nov 2025 22:12:09 -0600 Subject: [PATCH 018/267] VideoCommon: add method to async shader compiler to clear pending/completed work (used on shutdown), this will in turn clear up any resources that the worker items may have held onto --- Source/Core/VideoCommon/AsyncShaderCompiler.cpp | 13 +++++++++++++ Source/Core/VideoCommon/AsyncShaderCompiler.h | 3 +++ .../GraphicsModSystem/Runtime/CustomShaderCache.cpp | 6 ++++++ Source/Core/VideoCommon/ShaderCache.cpp | 3 +++ 4 files changed, 25 insertions(+) diff --git a/Source/Core/VideoCommon/AsyncShaderCompiler.cpp b/Source/Core/VideoCommon/AsyncShaderCompiler.cpp index c69354628d20..e312525eb950 100644 --- a/Source/Core/VideoCommon/AsyncShaderCompiler.cpp +++ b/Source/Core/VideoCommon/AsyncShaderCompiler.cpp @@ -68,6 +68,19 @@ bool AsyncShaderCompiler::HasCompletedWork() return !m_completed_work.empty(); } +void AsyncShaderCompiler::ClearAllWork() +{ + { + std::lock_guard guard(m_pending_work_lock); + m_pending_work.clear(); + } + + { + std::lock_guard guard(m_completed_work_lock); + m_completed_work.clear(); + } +} + bool AsyncShaderCompiler::WaitUntilCompletion( const std::function& progress_callback) { diff --git a/Source/Core/VideoCommon/AsyncShaderCompiler.h b/Source/Core/VideoCommon/AsyncShaderCompiler.h index 8773891d6198..ffcca0c4ec17 100644 --- a/Source/Core/VideoCommon/AsyncShaderCompiler.h +++ b/Source/Core/VideoCommon/AsyncShaderCompiler.h @@ -49,6 +49,9 @@ class AsyncShaderCompiler bool HasPendingWork(); bool HasCompletedWork(); + // Clears both pending and completed work + void ClearAllWork(); + // Calls progress_callback periodically, with completed_items, and total_items. // Returns false if interrupted. bool WaitUntilCompletion(const std::function& progress_callback); diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.cpp index a3c98ee9d7c3..0c4cf4322718 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.cpp +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomShaderCache.cpp @@ -24,10 +24,16 @@ CustomShaderCache::CustomShaderCache() CustomShaderCache::~CustomShaderCache() { if (m_async_shader_compiler) + { m_async_shader_compiler->StopWorkerThreads(); + m_async_shader_compiler->ClearAllWork(); + } if (m_async_uber_shader_compiler) + { m_async_uber_shader_compiler->StopWorkerThreads(); + m_async_uber_shader_compiler->ClearAllWork(); + } } void CustomShaderCache::RetrieveAsyncShaders() diff --git a/Source/Core/VideoCommon/ShaderCache.cpp b/Source/Core/VideoCommon/ShaderCache.cpp index a3d07368f605..03dc21c93740 100644 --- a/Source/Core/VideoCommon/ShaderCache.cpp +++ b/Source/Core/VideoCommon/ShaderCache.cpp @@ -109,7 +109,10 @@ void ShaderCache::Shutdown() // This may leave shaders uncommitted to the cache, but it's better than blocking shutdown // until everything has finished compiling. if (m_async_shader_compiler) + { m_async_shader_compiler->StopWorkerThreads(); + m_async_shader_compiler->ClearAllWork(); + } ClosePipelineUIDCache(); } From 506e3782891da702725b625c103edc61d4279d71 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Fri, 21 Nov 2025 00:34:37 -0600 Subject: [PATCH 019/267] VideoCommon: remove template parameter from lock guards in AsyncShaderCompiler, let type deduction do its thing and improve readability --- .../Core/VideoCommon/AsyncShaderCompiler.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Source/Core/VideoCommon/AsyncShaderCompiler.cpp b/Source/Core/VideoCommon/AsyncShaderCompiler.cpp index e312525eb950..83eaa2e23e83 100644 --- a/Source/Core/VideoCommon/AsyncShaderCompiler.cpp +++ b/Source/Core/VideoCommon/AsyncShaderCompiler.cpp @@ -35,7 +35,7 @@ void AsyncShaderCompiler::QueueWorkItem(WorkItemPtr item, u32 priority) } else { - std::lock_guard guard(m_pending_work_lock); + std::lock_guard guard(m_pending_work_lock); m_pending_work.emplace(priority, std::move(item)); m_worker_thread_wake.notify_one(); } @@ -45,7 +45,7 @@ void AsyncShaderCompiler::RetrieveWorkItems() { std::deque completed_work; { - std::lock_guard guard(m_completed_work_lock); + std::lock_guard guard(m_completed_work_lock); m_completed_work.swap(completed_work); } @@ -58,25 +58,25 @@ void AsyncShaderCompiler::RetrieveWorkItems() bool AsyncShaderCompiler::HasPendingWork() { - std::lock_guard guard(m_pending_work_lock); + std::lock_guard guard(m_pending_work_lock); return !m_pending_work.empty() || m_busy_workers.load() != 0; } bool AsyncShaderCompiler::HasCompletedWork() { - std::lock_guard guard(m_completed_work_lock); + std::lock_guard guard(m_completed_work_lock); return !m_completed_work.empty(); } void AsyncShaderCompiler::ClearAllWork() { { - std::lock_guard guard(m_pending_work_lock); + std::lock_guard guard(m_pending_work_lock); m_pending_work.clear(); } { - std::lock_guard guard(m_completed_work_lock); + std::lock_guard guard(m_completed_work_lock); m_completed_work.clear(); } } @@ -102,8 +102,8 @@ bool AsyncShaderCompiler::WaitUntilCompletion( size_t total_items; { // Safe to hold both locks here, since nowhere else does. - std::lock_guard pending_guard(m_pending_work_lock); - std::lock_guard completed_guard(m_completed_work_lock); + std::lock_guard pending_guard(m_pending_work_lock); + std::lock_guard completed_guard(m_completed_work_lock); total_items = m_completed_work.size() + m_pending_work.size() + m_busy_workers.load() + 1; } @@ -112,7 +112,7 @@ bool AsyncShaderCompiler::WaitUntilCompletion( { size_t remaining_items; { - std::lock_guard pending_guard(m_pending_work_lock); + std::lock_guard pending_guard(m_pending_work_lock); if (m_pending_work.empty() && !m_busy_workers.load()) return true; remaining_items = m_pending_work.size(); @@ -177,7 +177,7 @@ void AsyncShaderCompiler::StopWorkerThreads() // Signal worker threads to stop, and wake all of them. { - std::lock_guard guard(m_pending_work_lock); + std::lock_guard guard(m_pending_work_lock); m_exit_flag.Set(); m_worker_thread_wake.notify_all(); } @@ -226,7 +226,7 @@ void AsyncShaderCompiler::WorkerThreadEntryPoint(void* param) void AsyncShaderCompiler::WorkerThreadRun() { - std::unique_lock pending_lock(m_pending_work_lock); + std::unique_lock pending_lock(m_pending_work_lock); while (!m_exit_flag.IsSet()) { m_worker_thread_wake.wait(pending_lock); @@ -241,7 +241,7 @@ void AsyncShaderCompiler::WorkerThreadRun() if (item->Compile()) { - std::lock_guard completed_guard(m_completed_work_lock); + std::lock_guard completed_guard(m_completed_work_lock); m_completed_work.push_back(std::move(item)); } From 58b3c14c2345fc4a867cb672f3619d4a8ee84af4 Mon Sep 17 00:00:00 2001 From: oltolm Date: Wed, 19 Nov 2025 23:17:31 +0100 Subject: [PATCH 020/267] AudioCommon / VideoBackends / WinUpdater - cleanup WRL code --- Source/Core/AudioCommon/WASAPIStream.cpp | 29 +++++++------- Source/Core/VideoBackends/D3D/D3DBase.cpp | 38 +++++++++---------- Source/Core/VideoBackends/D3D/D3DState.cpp | 10 ++--- Source/Core/VideoBackends/D3D/DXTexture.cpp | 20 +++++----- .../Core/VideoBackends/D3D12/DX12Context.cpp | 6 +-- .../VideoBackends/D3DCommon/D3DCommon.cpp | 14 +++---- .../VideoBackends/D3DCommon/SwapChain.cpp | 4 +- Source/Core/WinUpdater/WinUI.cpp | 2 +- 8 files changed, 61 insertions(+), 62 deletions(-) diff --git a/Source/Core/AudioCommon/WASAPIStream.cpp b/Source/Core/AudioCommon/WASAPIStream.cpp index ec40ca7a09aa..0eabb910cd98 100644 --- a/Source/Core/AudioCommon/WASAPIStream.cpp +++ b/Source/Core/AudioCommon/WASAPIStream.cpp @@ -6,6 +6,7 @@ #ifdef _WIN32 // clang-format off +#include #include #include #include @@ -91,13 +92,13 @@ static void ForEachNamedDevice(const std::function, std:: ComPtr enumerator; result = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(enumerator.GetAddressOf())); + IID_PPV_ARGS(&enumerator)); if (!HandleWinAPI("Failed to create MMDeviceEnumerator", result)) return; ComPtr devices; - result = enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, devices.GetAddressOf()); + result = enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices); if (!HandleWinAPI("Failed to get available devices", result)) return; @@ -108,13 +109,13 @@ static void ForEachNamedDevice(const std::function, std:: for (u32 i = 0; i < count; i++) { ComPtr device; - devices->Item(i, device.GetAddressOf()); + devices->Item(i, &device); if (!HandleWinAPI("Failed to get device " + std::to_string(i), result)) continue; ComPtr device_properties; - result = device->OpenPropertyStore(STGM_READ, device_properties.GetAddressOf()); + result = device->OpenPropertyStore(STGM_READ, &device_properties); if (!HandleWinAPI("Failed to initialize IPropertyStore", result)) continue; @@ -158,9 +159,8 @@ ComPtr WASAPIStream::GetDeviceByName(std::string_view name) bool WASAPIStream::Init() { ASSERT(m_enumerator == nullptr); - HRESULT const result = - CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(m_enumerator.GetAddressOf())); + HRESULT const result = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, + CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_enumerator)); if (!HandleWinAPI("Failed to create MMDeviceEnumerator", result)) return false; @@ -178,7 +178,7 @@ bool WASAPIStream::SetRunning(bool running) if (Config::Get(Config::MAIN_WASAPI_DEVICE) == "default") { - result = m_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, device.GetAddressOf()); + result = m_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device); } else { @@ -189,7 +189,7 @@ bool WASAPIStream::SetRunning(bool running) { ERROR_LOG_FMT(AUDIO, "Can't find device '{}', falling back to default", Config::Get(Config::MAIN_WASAPI_DEVICE)); - result = m_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, device.GetAddressOf()); + result = m_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device); } } @@ -199,7 +199,7 @@ bool WASAPIStream::SetRunning(bool running) // Show a friendly name in the log ComPtr device_properties; - result = device->OpenPropertyStore(STGM_READ, device_properties.GetAddressOf()); + result = device->OpenPropertyStore(STGM_READ, &device_properties); if (!HandleWinAPI("Failed to initialize IPropertyStore", result)) return false; @@ -212,8 +212,7 @@ bool WASAPIStream::SetRunning(bool running) ComPtr audio_client; // Get IAudioDevice - result = device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, nullptr, - reinterpret_cast(audio_client.GetAddressOf())); + result = device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, nullptr, &audio_client); if (!HandleWinAPI("Failed to activate IAudioClient", result)) return false; @@ -249,8 +248,8 @@ bool WASAPIStream::SetRunning(bool running) return false; // Get IAudioDevice - result = device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, nullptr, - reinterpret_cast(audio_client.ReleaseAndGetAddressOf())); + result = + device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, nullptr, &audio_client); if (!HandleWinAPI("Failed to reactivate IAudioClient", result)) return false; @@ -276,7 +275,7 @@ bool WASAPIStream::SetRunning(bool running) ComPtr audio_renderer; - result = audio_client->GetService(IID_PPV_ARGS(audio_renderer.GetAddressOf())); + result = audio_client->GetService(IID_PPV_ARGS(&audio_renderer)); if (!HandleWinAPI("Failed to get IAudioRenderClient from IAudioClient", result)) return false; diff --git a/Source/Core/VideoBackends/D3D/D3DBase.cpp b/Source/Core/VideoBackends/D3D/D3DBase.cpp index 34c3a97ce316..0e897e0b000c 100644 --- a/Source/Core/VideoBackends/D3D/D3DBase.cpp +++ b/Source/Core/VideoBackends/D3D/D3DBase.cpp @@ -64,7 +64,7 @@ bool Create(u32 adapter_index, bool enable_debug_layer) } ComPtr adapter; - HRESULT hr = dxgi_factory->EnumAdapters(adapter_index, adapter.GetAddressOf()); + HRESULT hr = dxgi_factory->EnumAdapters(adapter_index, &adapter); if (FAILED(hr)) { WARN_LOG_FMT(VIDEO, "Adapter {} not found, using default: {}", adapter_index, DX11HRWrap(hr)); @@ -75,10 +75,10 @@ bool Create(u32 adapter_index, bool enable_debug_layer) // version of the DirectX SDK. If it does, simply fallback to a non-debug device. if (enable_debug_layer) { - hr = d3d11_create_device( - adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_DEBUG, - s_supported_feature_levels.data(), static_cast(s_supported_feature_levels.size()), - D3D11_SDK_VERSION, device.GetAddressOf(), &feature_level, context.GetAddressOf()); + hr = d3d11_create_device(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, + D3D11_CREATE_DEVICE_DEBUG, s_supported_feature_levels.data(), + static_cast(s_supported_feature_levels.size()), + D3D11_SDK_VERSION, &device, &feature_level, &context); // Debugbreak on D3D error if (SUCCEEDED(hr) && SUCCEEDED(hr = device.As(&s_debug))) @@ -105,10 +105,10 @@ bool Create(u32 adapter_index, bool enable_debug_layer) if (!enable_debug_layer || FAILED(hr)) { - hr = d3d11_create_device( - adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, s_supported_feature_levels.data(), - static_cast(s_supported_feature_levels.size()), D3D11_SDK_VERSION, - device.GetAddressOf(), &feature_level, context.GetAddressOf()); + hr = d3d11_create_device(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, + s_supported_feature_levels.data(), + static_cast(s_supported_feature_levels.size()), + D3D11_SDK_VERSION, &device, &feature_level, &context); } if (FAILED(hr)) @@ -181,7 +181,7 @@ std::vector GetAAModes(u32 adapter_index) return {}; ComPtr adapter; - temp_dxgi_factory->EnumAdapters(adapter_index, adapter.GetAddressOf()); + temp_dxgi_factory->EnumAdapters(adapter_index, &adapter); PFN_D3D11_CREATE_DEVICE d3d11_create_device; if (!temp_lib.Open("d3d11.dll") || @@ -190,10 +190,10 @@ std::vector GetAAModes(u32 adapter_index) return {}; } - HRESULT hr = d3d11_create_device( - adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, s_supported_feature_levels.data(), - static_cast(s_supported_feature_levels.size()), D3D11_SDK_VERSION, - temp_device.GetAddressOf(), &temp_feature_level, nullptr); + HRESULT hr = d3d11_create_device(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, + s_supported_feature_levels.data(), + static_cast(s_supported_feature_levels.size()), + D3D11_SDK_VERSION, &temp_device, &temp_feature_level, nullptr); if (FAILED(hr)) return {}; } @@ -243,7 +243,7 @@ bool SupportsLogicOp(u32 adapter_index) return false; ComPtr adapter; - temp_dxgi_factory->EnumAdapters(adapter_index, adapter.GetAddressOf()); + temp_dxgi_factory->EnumAdapters(adapter_index, &adapter); PFN_D3D11_CREATE_DEVICE d3d11_create_device; if (!temp_lib.Open("d3d11.dll") || @@ -252,10 +252,10 @@ bool SupportsLogicOp(u32 adapter_index) return false; } - HRESULT hr = d3d11_create_device( - adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, s_supported_feature_levels.data(), - static_cast(s_supported_feature_levels.size()), D3D11_SDK_VERSION, - temp_device.GetAddressOf(), nullptr, nullptr); + HRESULT hr = d3d11_create_device(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, + s_supported_feature_levels.data(), + static_cast(s_supported_feature_levels.size()), + D3D11_SDK_VERSION, &temp_device, nullptr, nullptr); if (FAILED(hr)) return false; diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index 7ee1e4332a1c..bbbb25fc194c 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -353,7 +353,7 @@ ID3D11SamplerState* StateCache::Get(SamplerState state) } ComPtr res; - HRESULT hr = D3D::device->CreateSamplerState(&sampdc, res.GetAddressOf()); + HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res); ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating D3D sampler state failed: {}", DX11HRWrap(hr)); return m_sampler.emplace(state, std::move(res)).first->second.Get(); } @@ -387,7 +387,7 @@ ID3D11BlendState* StateCache::Get(BlendingState state) tdesc.LogicOp = logic_ops[u32(state.logic_mode.Value())]; ComPtr res; - HRESULT hr = D3D::device1->CreateBlendState1(&desc, res.GetAddressOf()); + HRESULT hr = D3D::device1->CreateBlendState1(&desc, &res); if (SUCCEEDED(hr)) { return m_blend.emplace(state.hex, std::move(res)).first->second.Get(); @@ -430,7 +430,7 @@ ID3D11BlendState* StateCache::Get(BlendingState state) tdesc.BlendOpAlpha = state.subtract_alpha ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD; ComPtr res; - HRESULT hr = D3D::device->CreateBlendState(&desc, res.GetAddressOf()); + HRESULT hr = D3D::device->CreateBlendState(&desc, &res); ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating D3D blend state failed: {}", DX11HRWrap(hr)); return m_blend.emplace(state.hex, std::move(res)).first->second.Get(); } @@ -451,7 +451,7 @@ ID3D11RasterizerState* StateCache::Get(RasterizationState state) desc.ScissorEnable = TRUE; ComPtr res; - HRESULT hr = D3D::device->CreateRasterizerState(&desc, res.GetAddressOf()); + HRESULT hr = D3D::device->CreateRasterizerState(&desc, &res); ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating D3D rasterizer state failed: {}", DX11HRWrap(hr)); return m_raster.emplace(state.hex, std::move(res)).first->second.Get(); } @@ -493,7 +493,7 @@ ID3D11DepthStencilState* StateCache::Get(DepthState state) } ComPtr res; - HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, res.GetAddressOf()); + HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, &res); ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating D3D depth stencil state failed: {}", DX11HRWrap(hr)); return m_depth.emplace(state.hex, std::move(res)).first->second.Get(); } diff --git a/Source/Core/VideoBackends/D3D/DXTexture.cpp b/Source/Core/VideoBackends/D3D/DXTexture.cpp index eac31fd64dd9..57e886e2fe1c 100644 --- a/Source/Core/VideoBackends/D3D/DXTexture.cpp +++ b/Source/Core/VideoBackends/D3D/DXTexture.cpp @@ -50,7 +50,7 @@ std::unique_ptr DXTexture::Create(const TextureConfig& config, std::s D3D11_USAGE_DEFAULT, 0, config.samples, 0, config.type == AbstractTextureType::Texture_CubeMap ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0); ComPtr d3d_texture; - HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, d3d_texture.GetAddressOf()); + HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &d3d_texture); if (FAILED(hr)) { PanicAlertFmt("Failed to create {}x{}x{} D3D backing texture: {}", config.width, config.height, @@ -119,7 +119,7 @@ bool DXTexture::CreateSRV() m_texture.Get(), dimension, D3DCommon::GetSRVFormatForAbstractFormat(m_config.format), 0, m_config.levels, 0, m_config.layers); DEBUG_ASSERT(!m_srv); - HRESULT hr = D3D::device->CreateShaderResourceView(m_texture.Get(), &desc, m_srv.GetAddressOf()); + HRESULT hr = D3D::device->CreateShaderResourceView(m_texture.Get(), &desc, &m_srv); if (FAILED(hr)) { PanicAlertFmt("Failed to create {}x{}x{} D3D SRV: {}", m_config.width, m_config.height, @@ -136,7 +136,7 @@ bool DXTexture::CreateUAV() m_texture.Get(), D3D11_UAV_DIMENSION_TEXTURE2DARRAY, D3DCommon::GetSRVFormatForAbstractFormat(m_config.format), 0, 0, m_config.layers); DEBUG_ASSERT(!m_uav); - HRESULT hr = D3D::device->CreateUnorderedAccessView(m_texture.Get(), &desc, m_uav.GetAddressOf()); + HRESULT hr = D3D::device->CreateUnorderedAccessView(m_texture.Get(), &desc, &m_uav); if (FAILED(hr)) { PanicAlertFmt("Failed to create {}x{}x{} D3D UAV: {}", m_config.width, m_config.height, @@ -233,7 +233,7 @@ std::unique_ptr DXStagingTexture::Create(StagingTextureType ty config.width, config.height, 1, 1, bind_flags, usage, cpu_flags); ComPtr texture; - HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, texture.GetAddressOf()); + HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &texture); ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create staging texture: {}", DX11HRWrap(hr)); if (FAILED(hr)) return nullptr; @@ -444,8 +444,8 @@ DXFramebuffer::Create(DXTexture* color_attachment, DXTexture* depth_attachment, D3D11_RTV_DIMENSION_TEXTURE2DARRAY, D3DCommon::GetRTVFormatForAbstractFormat(color_attachment->GetFormat(), false), 0, 0, color_attachment->GetLayers()); - HRESULT hr = D3D::device->CreateRenderTargetView(color_attachment->GetD3DTexture(), &desc, - rtv.GetAddressOf()); + HRESULT hr = + D3D::device->CreateRenderTargetView(color_attachment->GetD3DTexture(), &desc, &rtv); ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create render target view for framebuffer: {}", DX11HRWrap(hr)); if (FAILED(hr)) @@ -458,7 +458,7 @@ DXFramebuffer::Create(DXTexture* color_attachment, DXTexture* depth_attachment, { desc.Format = integer_format; hr = D3D::device->CreateRenderTargetView(color_attachment->GetD3DTexture(), &desc, - integer_rtv.GetAddressOf()); + &integer_rtv); ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create integer render target view for framebuffer: {}", DX11HRWrap(hr)); } @@ -475,7 +475,7 @@ DXFramebuffer::Create(DXTexture* color_attachment, DXTexture* depth_attachment, 0, 0, 1); HRESULT hr = D3D::device->CreateRenderTargetView( static_cast(additional_color_attachment)->GetD3DTexture(), &desc, - additional_rtv.GetAddressOf()); + &additional_rtv); ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Create render target view for framebuffer: {}", DX11HRWrap(hr)); if (FAILED(hr)) @@ -491,8 +491,8 @@ DXFramebuffer::Create(DXTexture* color_attachment, DXTexture* depth_attachment, D3D11_DSV_DIMENSION_TEXTURE2DARRAY, D3DCommon::GetDSVFormatForAbstractFormat(depth_attachment->GetFormat()), 0, 0, depth_attachment->GetLayers(), 0); - HRESULT hr = D3D::device->CreateDepthStencilView(depth_attachment->GetD3DTexture(), &desc, - dsv.GetAddressOf()); + HRESULT hr = + D3D::device->CreateDepthStencilView(depth_attachment->GetD3DTexture(), &desc, &dsv); ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create depth stencil view for framebuffer: {}", DX11HRWrap(hr)); if (FAILED(hr)) diff --git a/Source/Core/VideoBackends/D3D12/DX12Context.cpp b/Source/Core/VideoBackends/D3D12/DX12Context.cpp index 2fa9fa8aa87b..346bda84b495 100644 --- a/Source/Core/VideoBackends/D3D12/DX12Context.cpp +++ b/Source/Core/VideoBackends/D3D12/DX12Context.cpp @@ -447,14 +447,14 @@ bool DXContext::CreateCommandLists() for (u32 i = 0; i < NUM_COMMAND_LISTS; i++) { CommandListResources& res = m_command_lists[i]; - HRESULT hr = m_device->CreateCommandAllocator( - D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(res.command_allocator.GetAddressOf())); + HRESULT hr = m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, + IID_PPV_ARGS(&res.command_allocator)); ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create command allocator: {}", DX12HRWrap(hr)); if (FAILED(hr)) return false; hr = m_device->CreateCommandList(1, D3D12_COMMAND_LIST_TYPE_DIRECT, res.command_allocator.Get(), - nullptr, IID_PPV_ARGS(res.command_list.GetAddressOf())); + nullptr, IID_PPV_ARGS(&res.command_list)); ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create command list: {}", DX12HRWrap(hr)); if (FAILED(hr)) { diff --git a/Source/Core/VideoBackends/D3DCommon/D3DCommon.cpp b/Source/Core/VideoBackends/D3DCommon/D3DCommon.cpp index 0658f1df8ced..d987107123da 100644 --- a/Source/Core/VideoBackends/D3DCommon/D3DCommon.cpp +++ b/Source/Core/VideoBackends/D3DCommon/D3DCommon.cpp @@ -81,13 +81,13 @@ Microsoft::WRL::ComPtr CreateDXGIFactory(bool debug_device) // Use Win8.1 version if available. if (create_dxgi_factory2 && SUCCEEDED(create_dxgi_factory2(debug_device ? DXGI_CREATE_FACTORY_DEBUG : 0, - IID_PPV_ARGS(factory.GetAddressOf())))) + IID_PPV_ARGS(&factory)))) { return factory; } // Fallback to original version, without debug support. - HRESULT hr = create_dxgi_factory(IID_PPV_ARGS(factory.ReleaseAndGetAddressOf())); + HRESULT hr = create_dxgi_factory(IID_PPV_ARGS(&factory)); if (FAILED(hr)) { PanicAlertFmt("CreateDXGIFactory() failed: {}", Common::HRWrap(hr)); @@ -100,14 +100,14 @@ Microsoft::WRL::ComPtr CreateDXGIFactory(bool debug_device) std::vector GetAdapterNames() { Microsoft::WRL::ComPtr factory; - HRESULT hr = create_dxgi_factory(IID_PPV_ARGS(factory.GetAddressOf())); + HRESULT hr = create_dxgi_factory(IID_PPV_ARGS(&factory)); if (FAILED(hr)) return {}; std::vector adapters; Microsoft::WRL::ComPtr adapter; - while (factory->EnumAdapters(static_cast(adapters.size()), - adapter.ReleaseAndGetAddressOf()) != DXGI_ERROR_NOT_FOUND) + while (factory->EnumAdapters(static_cast(adapters.size()), &adapter) != + DXGI_ERROR_NOT_FOUND) { std::string name; DXGI_ADAPTER_DESC desc; @@ -297,12 +297,12 @@ void SetDebugObjectName(IUnknown* resource, std::string_view name) Microsoft::WRL::ComPtr child11; Microsoft::WRL::ComPtr child12; - if (SUCCEEDED(resource->QueryInterface(IID_PPV_ARGS(child11.GetAddressOf())))) + if (SUCCEEDED(resource->QueryInterface(IID_PPV_ARGS(&child11)))) { child11->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast(name.length()), name.data()); } - else if (SUCCEEDED(resource->QueryInterface(IID_PPV_ARGS(child12.GetAddressOf())))) + else if (SUCCEEDED(resource->QueryInterface(IID_PPV_ARGS(&child12)))) { child12->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast(name.length()), name.data()); diff --git a/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp b/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp index d0f98b35234d..ff40ad418043 100644 --- a/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp +++ b/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp @@ -155,7 +155,7 @@ bool SwapChain::CreateSwapChain(bool stereo, bool hdr) // Only try to activate HDR here, to avoid failing when creating the swapchain // (we can't know if the format is supported upfront) Microsoft::WRL::ComPtr swap_chain4; - hr = m_swap_chain->QueryInterface(IID_PPV_ARGS(&swap_chain4)); + hr = m_swap_chain.As(&swap_chain4); if (SUCCEEDED(hr)) { UINT color_space_support = 0; @@ -214,7 +214,7 @@ bool SwapChain::ResizeSwapChain() WARN_LOG_FMT(VIDEO, "ResizeBuffers() failed: {}", Common::HRWrap(hr)); Microsoft::WRL::ComPtr swap_chain4; - hr = m_swap_chain->QueryInterface(IID_PPV_ARGS(&swap_chain4)); + hr = m_swap_chain.As(&swap_chain4); if (SUCCEEDED(hr)) hr = swap_chain4->SetColorSpace1(m_hdr ? DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 : DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709); diff --git a/Source/Core/WinUpdater/WinUI.cpp b/Source/Core/WinUpdater/WinUI.cpp index 0a328480167a..6ff7461ce0ee 100644 --- a/Source/Core/WinUpdater/WinUI.cpp +++ b/Source/Core/WinUpdater/WinUI.cpp @@ -78,7 +78,7 @@ bool InitWindow() return false; if (SUCCEEDED(CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(taskbar_list.GetAddressOf())))) + IID_PPV_ARGS(&taskbar_list)))) { if (FAILED(taskbar_list->HrInit())) { From 127e068e51a13a9bf69a576dc9d192f2c0287874 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Fri, 21 Nov 2025 19:24:48 -0600 Subject: [PATCH 021/267] Common/Result: Swap order of template parameters to match C++26's std::expected, make all member functions constexpr, and add moving "unexpected" conversion constructor for consistency. --- Source/Core/Common/Result.h | 32 ++++++++++++-------- Source/Core/Core/CheatGeneration.cpp | 2 +- Source/Core/Core/CheatGeneration.h | 2 +- Source/Core/Core/CheatSearch.cpp | 22 +++++++------- Source/Core/Core/CheatSearch.h | 4 +-- Source/Core/Core/IOS/FS/FileSystem.h | 2 +- Source/Core/DiscIO/MultithreadedCompressor.h | 4 +-- 7 files changed, 36 insertions(+), 32 deletions(-) diff --git a/Source/Core/Common/Result.h b/Source/Core/Common/Result.h index 78d675360bf6..db80362da18e 100644 --- a/Source/Core/Common/Result.h +++ b/Source/Core/Common/Result.h @@ -7,24 +7,30 @@ namespace Common { -template +template class Result final { public: - Result(ResultCode code) : m_variant{code} {} - Result(const T& t) : m_variant{t} {} - Result(T&& t) : m_variant{std::move(t)} {} - explicit operator bool() const { return Succeeded(); } - bool Succeeded() const { return std::holds_alternative(m_variant); } - // Must only be called when Succeeded() returns false. - ResultCode Error() const { return std::get(m_variant); } + constexpr Result(const Expected& value) : m_variant{value} {} + constexpr Result(Expected&& value) : m_variant{std::move(value)} {} + + constexpr Result(const Unexpected& value) : m_variant{value} {} + constexpr Result(Unexpected&& value) : m_variant{std::move(value)} {} + + constexpr explicit operator bool() const { return Succeeded(); } + constexpr bool Succeeded() const { return std::holds_alternative(m_variant); } + // Must only be called when Succeeded() returns true. - const T& operator*() const { return std::get(m_variant); } - const T* operator->() const { return &std::get(m_variant); } - T& operator*() { return std::get(m_variant); } - T* operator->() { return &std::get(m_variant); } + constexpr const Expected& operator*() const { return std::get(m_variant); } + constexpr const Expected* operator->() const { return &std::get(m_variant); } + constexpr Expected& operator*() { return std::get(m_variant); } + constexpr Expected* operator->() { return &std::get(m_variant); } + + // Must only be called when Succeeded() returns false. + constexpr Unexpected& Error() { return std::get(m_variant); } + constexpr const Unexpected& Error() const { return std::get(m_variant); } private: - std::variant m_variant; + std::variant m_variant; }; } // namespace Common diff --git a/Source/Core/Core/CheatGeneration.cpp b/Source/Core/Core/CheatGeneration.cpp index e6120a0e5851..4154b1cfa3f1 100644 --- a/Source/Core/Core/CheatGeneration.cpp +++ b/Source/Core/Core/CheatGeneration.cpp @@ -52,7 +52,7 @@ static std::vector ResultToAREntries(u32 addr, const Chea return codes; } -Common::Result +Common::Result Cheats::GenerateActionReplayCode(const Cheats::CheatSearchSessionBase& session, size_t index) { if (index >= session.GetResultCount()) diff --git a/Source/Core/Core/CheatGeneration.h b/Source/Core/Core/CheatGeneration.h index f6fda3a2217a..1dfd91a814f6 100644 --- a/Source/Core/Core/CheatGeneration.h +++ b/Source/Core/Core/CheatGeneration.h @@ -18,6 +18,6 @@ enum class GenerateActionReplayCodeErrorCode InvalidAddress, }; -Common::Result +Common::Result GenerateActionReplayCode(const Cheats::CheatSearchSessionBase& session, size_t index); } // namespace Cheats diff --git a/Source/Core/Core/CheatSearch.cpp b/Source/Core/Core/CheatSearch.cpp index 40868e5efc9f..bc01afa404b8 100644 --- a/Source/Core/Core/CheatSearch.cpp +++ b/Source/Core/Core/CheatSearch.cpp @@ -109,11 +109,11 @@ TryReadValueFromEmulatedMemory(const Core::CPUThreadGuard& guard, u32 addr, } template -Common::Result>> -Cheats::NewSearch(const Core::CPUThreadGuard& guard, - const std::vector& memory_ranges, - PowerPC::RequestedAddressSpace address_space, bool aligned, - const std::function& validator) +auto Cheats::NewSearch(const Core::CPUThreadGuard& guard, + const std::vector& memory_ranges, + PowerPC::RequestedAddressSpace address_space, bool aligned, + const std::function& validator) + -> Common::Result>, SearchErrorCode> { if (AchievementManager::GetInstance().IsHardcoreModeActive()) return Cheats::SearchErrorCode::DisabledInHardcoreMode; @@ -162,11 +162,11 @@ Cheats::NewSearch(const Core::CPUThreadGuard& guard, } template -Common::Result>> -Cheats::NextSearch(const Core::CPUThreadGuard& guard, - const std::vector>& previous_results, - PowerPC::RequestedAddressSpace address_space, - const std::function& validator) +auto Cheats::NextSearch( + const Core::CPUThreadGuard& guard, const std::vector>& previous_results, + PowerPC::RequestedAddressSpace address_space, + const std::function& validator) + -> Common::Result>, SearchErrorCode> { if (AchievementManager::GetInstance().IsHardcoreModeActive()) return Cheats::SearchErrorCode::DisabledInHardcoreMode; @@ -335,7 +335,7 @@ Cheats::SearchErrorCode Cheats::CheatSearchSession::RunSearch(const Core::CPU { if (AchievementManager::GetInstance().IsHardcoreModeActive()) return Cheats::SearchErrorCode::DisabledInHardcoreMode; - Common::Result>> result = + Common::Result>, SearchErrorCode> result = Cheats::SearchErrorCode::InvalidParameters; if (m_filter_type == FilterType::CompareAgainstSpecificValue) { diff --git a/Source/Core/Core/CheatSearch.h b/Source/Core/Core/CheatSearch.h index 6c6d5090471a..d0e56e6c369d 100644 --- a/Source/Core/Core/CheatSearch.h +++ b/Source/Core/Core/CheatSearch.h @@ -116,7 +116,7 @@ std::vector GetValueAsByteVector(const SearchValue& value); // Do a new search across the given memory region in the given address space, only keeping values // for which the given validator returns true. template -Common::Result>> +Common::Result>, SearchErrorCode> NewSearch(const Core::CPUThreadGuard& guard, const std::vector& memory_ranges, PowerPC::RequestedAddressSpace address_space, bool aligned, const std::function& validator); @@ -124,7 +124,7 @@ NewSearch(const Core::CPUThreadGuard& guard, const std::vector& mem // Refresh the values for the given results in the given address space, only keeping values for // which the given validator returns true. template -Common::Result>> +Common::Result>, SearchErrorCode> NextSearch(const Core::CPUThreadGuard& guard, const std::vector>& previous_results, PowerPC::RequestedAddressSpace address_space, const std::function& validator); diff --git a/Source/Core/Core/IOS/FS/FileSystem.h b/Source/Core/Core/IOS/FS/FileSystem.h index 0010f99cfbd3..8e8e36dc5285 100644 --- a/Source/Core/Core/IOS/FS/FileSystem.h +++ b/Source/Core/Core/IOS/FS/FileSystem.h @@ -49,7 +49,7 @@ enum class ResultCode }; template -using Result = Common::Result; +using Result = Common::Result; using Uid = u32; using Gid = u16; diff --git a/Source/Core/DiscIO/MultithreadedCompressor.h b/Source/Core/DiscIO/MultithreadedCompressor.h index 736d177de536..6019d5472b58 100644 --- a/Source/Core/DiscIO/MultithreadedCompressor.h +++ b/Source/Core/DiscIO/MultithreadedCompressor.h @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include "Common/Assert.h" #include "Common/Event.h" @@ -27,7 +25,7 @@ enum class ConversionResultCode }; template -using ConversionResult = Common::Result; +using ConversionResult = Common::Result; // This class starts a number of compression threads and one output thread. // The set_up_compress_thread_state function is called at the start of each compression thread. From dd5f8312627a5bf4b5a0f311437baa681ecdfbbd Mon Sep 17 00:00:00 2001 From: Simonx22 Date: Fri, 21 Nov 2025 21:47:09 -0500 Subject: [PATCH 022/267] Android: Remove CompletableFuture We only use this class in one in one single function since its introduction with 12aa1071cbb30269cd6526cfbbcd3c4143d584ac in 2021. If we do need it elsewhere we can always bring it back. --- .../dolphinemu/ui/main/MainPresenter.kt | 19 ++-- .../dolphinemu/utils/CompletableFuture.java | 97 ------------------- 2 files changed, 10 insertions(+), 106 deletions(-) delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/CompletableFuture.java diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.kt index cea17578d403..77a7dcaa8a61 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.kt @@ -26,7 +26,6 @@ import org.dolphinemu.dolphinemu.model.GameFileCache import org.dolphinemu.dolphinemu.services.GameFileCacheManager import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner import org.dolphinemu.dolphinemu.utils.BooleanSupplier -import org.dolphinemu.dolphinemu.utils.CompletableFuture import org.dolphinemu.dolphinemu.utils.ContentHandler import org.dolphinemu.dolphinemu.utils.DirectoryInitialization import org.dolphinemu.dolphinemu.utils.FileBrowserHelper @@ -34,7 +33,8 @@ import org.dolphinemu.dolphinemu.utils.PermissionsHandler import org.dolphinemu.dolphinemu.utils.ThreadUtil import org.dolphinemu.dolphinemu.utils.WiiUtils import java.util.Arrays -import java.util.concurrent.ExecutionException +import java.util.concurrent.CountDownLatch +import java.util.concurrent.atomic.AtomicReference class MainPresenter(private val mainView: MainView, private val activity: FragmentActivity) { private var dirToAdd: String? = null @@ -265,33 +265,34 @@ class MainPresenter(private val mainView: MainView, private val activity: Fragme } fun importWiiSave(path: String?) { - val canOverwriteFuture = CompletableFuture() ThreadUtil.runOnThreadAndShowResult( activity, R.string.import_in_progress, 0, { val canOverwrite = BooleanSupplier { + val latch = CountDownLatch(1) + val decision = AtomicReference() activity.runOnUiThread { MaterialAlertDialogBuilder(activity) .setMessage(R.string.wii_save_exists) .setCancelable(false) .setPositiveButton(R.string.yes) { _: DialogInterface?, _: Int -> - canOverwriteFuture.complete(true) + decision.set(true) + latch.countDown() } .setNegativeButton(R.string.no) { _: DialogInterface?, _: Int -> - canOverwriteFuture.complete(false) + decision.set(false) + latch.countDown() } .show() } try { - return@BooleanSupplier canOverwriteFuture.get() - } catch (e: ExecutionException) { - // Shouldn't happen - throw RuntimeException(e) + latch.await() } catch (e: InterruptedException) { throw RuntimeException(e) } + decision.get() ?: false } val message: Int = when (WiiUtils.importWiiSave(path!!, canOverwrite)) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/CompletableFuture.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/CompletableFuture.java deleted file mode 100644 index 1b3c4505349b..000000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/CompletableFuture.java +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.utils; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -/** - * Simplified re-implementation of a subset of {@link java.util.concurrent.CompletableFuture}. - * Replace this class with that class once we have full Java 8 support (once we require API 24). - */ -public class CompletableFuture implements Future -{ - private final Lock lock = new ReentrantLock(); - private final Condition done = lock.newCondition(); - - private boolean isDone = false; - private T result = null; - - @Override - public boolean cancel(boolean mayInterruptIfRunning) - { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isCancelled() - { - return false; - } - - @Override - public boolean isDone() - { - return isDone; - } - - @Override - public T get() throws ExecutionException, InterruptedException - { - lock.lock(); - try - { - while (!isDone) - done.await(); - - return result; - } - finally - { - lock.unlock(); - } - } - - @Override - public T get(long timeout, TimeUnit unit) - throws ExecutionException, InterruptedException, TimeoutException - { - lock.lock(); - try - { - while (!isDone) - { - if (!done.await(timeout, unit)) - throw new TimeoutException(); - } - - return result; - } - finally - { - lock.unlock(); - } - } - - public boolean complete(T value) - { - lock.lock(); - try - { - boolean wasDone = isDone; - result = value; - isDone = true; - done.signalAll(); - return !wasDone; - } - finally - { - lock.unlock(); - } - } -} From 01d2d0eea1511a19751e91e83d582a3a5d8989f6 Mon Sep 17 00:00:00 2001 From: Simonx22 Date: Tue, 18 Nov 2025 16:11:11 -0500 Subject: [PATCH 023/267] Android: Format ControllerInterface --- .../features/input/model/ControllerInterface.kt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.kt index 9cf9b0e7a7b5..360800d656ca 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/ControllerInterface.kt @@ -81,9 +81,7 @@ object ControllerInterface { } private external fun dispatchSensorEventNative( - deviceQualifier: String, - axisName: String, - value: Float + deviceQualifier: String, axisName: String, value: Float ): Boolean /** @@ -94,9 +92,7 @@ object ControllerInterface { * @param suspended Whether the sensor is now suspended. */ external fun notifySensorSuspendedState( - deviceQualifier: String, - axisNames: Array, - suspended: Boolean + deviceQualifier: String, axisNames: Array, suspended: Boolean ) /** @@ -177,8 +173,9 @@ object ControllerInterface { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val vibratorManager = DolphinApplication.getAppContext() .getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager? - if (vibratorManager != null) + if (vibratorManager != null) { return DolphinVibratorManagerPassthrough(vibratorManager) + } } val vibrator = DolphinApplication.getAppContext() .getSystemService(Context.VIBRATOR_SERVICE) as Vibrator From e78ece126e4d586f1816a8fd4dcf46a36ba71d03 Mon Sep 17 00:00:00 2001 From: Simonx22 Date: Fri, 21 Nov 2025 21:47:40 -0500 Subject: [PATCH 024/267] Android: Format MainPresenter --- .../dolphinemu/ui/main/MainPresenter.kt | 193 ++++++++---------- 1 file changed, 89 insertions(+), 104 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.kt index 77a7dcaa8a61..893d6a16d4d7 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.kt @@ -104,8 +104,9 @@ class MainPresenter(private val mainView: MainView, private val activity: Fragme fun onCreate() { // Ask the user to grant write permission if relevant and not already granted - if (DirectoryInitialization.isWaitingForWriteAccess(activity)) + if (DirectoryInitialization.isWaitingForWriteAccess(activity)) { PermissionsHandler.requestWritePermission(activity) + } val versionName = BuildConfig.VERSION_NAME mainView.setVersionString(versionName) @@ -118,85 +119,83 @@ class MainPresenter(private val mainView: MainView, private val activity: Fragme } fun launchFileListActivity() { - val intent = - if (DirectoryInitialization.preferOldFolderPicker(activity)) { - FileBrowserHelper.createDirectoryPickerIntent( - activity, - FileBrowserHelper.GAME_EXTENSIONS, - ) - } else { - Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) - } + val intent = if (DirectoryInitialization.preferOldFolderPicker(activity)) { + FileBrowserHelper.createDirectoryPickerIntent( + activity, + FileBrowserHelper.GAME_EXTENSIONS, + ) + } else { + Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) + } requestDirectory.launch(intent) } - fun handleOptionSelection(itemId: Int, activity: ComponentActivity): Boolean = - when (itemId) { - R.id.menu_settings -> { - mainView.launchSettingsActivity(MenuTag.SETTINGS) - true - } - - R.id.menu_grid_options -> { - mainView.showGridOptions() - true - } + fun handleOptionSelection(itemId: Int, activity: ComponentActivity): Boolean = when (itemId) { + R.id.menu_settings -> { + mainView.launchSettingsActivity(MenuTag.SETTINGS) + true + } - R.id.menu_refresh -> { - mainView.setRefreshing(true) - GameFileCacheManager.startRescan() - true - } + R.id.menu_grid_options -> { + mainView.showGridOptions() + true + } - R.id.button_add_directory -> { - AfterDirectoryInitializationRunner().runWithLifecycle(activity) { launchFileListActivity() } - true - } + R.id.menu_refresh -> { + mainView.setRefreshing(true) + GameFileCacheManager.startRescan() + true + } - R.id.menu_open_file -> { - requestGameFile.launch("*/*") - true - } + R.id.button_add_directory -> { + AfterDirectoryInitializationRunner().runWithLifecycle(activity) { launchFileListActivity() } + true + } - R.id.menu_load_wii_system_menu -> { - launchWiiSystemMenu() - true - } + R.id.menu_open_file -> { + requestGameFile.launch("*/*") + true + } - R.id.menu_online_system_update -> { - AfterDirectoryInitializationRunner().runWithLifecycle(activity) { launchOnlineUpdate() } - true - } + R.id.menu_load_wii_system_menu -> { + launchWiiSystemMenu() + true + } - R.id.menu_install_wad -> { - AfterDirectoryInitializationRunner().runWithLifecycle( - activity - ) { requestWadFile.launch("*/*") } - true - } + R.id.menu_online_system_update -> { + AfterDirectoryInitializationRunner().runWithLifecycle(activity) { launchOnlineUpdate() } + true + } - R.id.menu_import_wii_save -> { - AfterDirectoryInitializationRunner().runWithLifecycle( - activity - ) { requestWiiSaveFile.launch("*/*") } - true - } + R.id.menu_install_wad -> { + AfterDirectoryInitializationRunner().runWithLifecycle( + activity + ) { requestWadFile.launch("*/*") } + true + } - R.id.menu_import_nand_backup -> { - AfterDirectoryInitializationRunner().runWithLifecycle( - activity - ) { requestNandBinFile.launch("*/*") } - true - } + R.id.menu_import_wii_save -> { + AfterDirectoryInitializationRunner().runWithLifecycle( + activity + ) { requestWiiSaveFile.launch("*/*") } + true + } - R.id.menu_about -> { - showAboutDialog() - false - } + R.id.menu_import_nand_backup -> { + AfterDirectoryInitializationRunner().runWithLifecycle( + activity + ) { requestNandBinFile.launch("*/*") } + true + } - else -> false + R.id.menu_about -> { + showAboutDialog() + false } + else -> false + } + fun onResume() { if (dirToAdd != null) { GameFileCache.addGameFolder(dirToAdd!!) @@ -226,24 +225,25 @@ class MainPresenter(private val mainView: MainView, private val activity: Fragme val recursive = BooleanSetting.MAIN_RECURSIVE_ISO_PATHS.boolean val childNames = ContentHandler.getChildNames(uri, recursive) if (Arrays.stream(childNames).noneMatch { - FileBrowserHelper.GAME_EXTENSIONS - .contains(FileBrowserHelper.getExtension(it, false)) - }) { - MaterialAlertDialogBuilder(activity) - .setMessage( - activity.getString( - R.string.wrong_file_extension_in_directory, - FileBrowserHelper.setToSortedDelimitedString(FileBrowserHelper.GAME_EXTENSIONS) + FileBrowserHelper.GAME_EXTENSIONS.contains( + FileBrowserHelper.getExtension( + it, false ) ) - .setPositiveButton(android.R.string.ok, null) - .show() + }) { + MaterialAlertDialogBuilder(activity).setMessage( + activity.getString( + R.string.wrong_file_extension_in_directory, + FileBrowserHelper.setToSortedDelimitedString(FileBrowserHelper.GAME_EXTENSIONS) + ) + ).setPositiveButton(android.R.string.ok, null).show() } val contentResolver = activity.contentResolver val canonicalizedUri = contentResolver.canonicalize(uri) - if (canonicalizedUri != null) + if (canonicalizedUri != null) { uri = canonicalizedUri + } val takeFlags = result.flags and Intent.FLAG_GRANT_READ_URI_PERMISSION activity.contentResolver.takePersistableUriPermission(uri, takeFlags) @@ -253,10 +253,7 @@ class MainPresenter(private val mainView: MainView, private val activity: Fragme fun installWAD(path: String?) { ThreadUtil.runOnThreadAndShowResult( - activity, - R.string.import_in_progress, - 0, - { + activity, R.string.import_in_progress, 0, { val success = WiiUtils.installWAD(path!!) val message = if (success) R.string.wad_install_success else R.string.wad_install_failure @@ -266,26 +263,20 @@ class MainPresenter(private val mainView: MainView, private val activity: Fragme fun importWiiSave(path: String?) { ThreadUtil.runOnThreadAndShowResult( - activity, - R.string.import_in_progress, - 0, - { + activity, R.string.import_in_progress, 0, { val canOverwrite = BooleanSupplier { val latch = CountDownLatch(1) val decision = AtomicReference() activity.runOnUiThread { - MaterialAlertDialogBuilder(activity) - .setMessage(R.string.wii_save_exists) + MaterialAlertDialogBuilder(activity).setMessage(R.string.wii_save_exists) .setCancelable(false) .setPositiveButton(R.string.yes) { _: DialogInterface?, _: Int -> decision.set(true) latch.countDown() - } - .setNegativeButton(R.string.no) { _: DialogInterface?, _: Int -> + }.setNegativeButton(R.string.no) { _: DialogInterface?, _: Int -> decision.set(false) latch.countDown() - } - .show() + }.show() } try { latch.await() @@ -307,23 +298,18 @@ class MainPresenter(private val mainView: MainView, private val activity: Fragme } fun importNANDBin(path: String?) { - MaterialAlertDialogBuilder(activity) - .setMessage(R.string.nand_import_warning) + MaterialAlertDialogBuilder(activity).setMessage(R.string.nand_import_warning) .setNegativeButton(R.string.no) { dialog: DialogInterface, _: Int -> dialog.dismiss() } .setPositiveButton(R.string.yes) { dialog: DialogInterface, _: Int -> dialog.dismiss() ThreadUtil.runOnThreadAndShowResult( - activity, - R.string.import_in_progress, - R.string.do_not_close_app, - { + activity, R.string.import_in_progress, R.string.do_not_close_app, { // ImportNANDBin unfortunately doesn't provide any result value... // It does however show a panic alert if something goes wrong. WiiUtils.importNANDBin(path!!) null }) - } - .show() + }.show() } private fun launchOnlineUpdate() { @@ -333,8 +319,7 @@ class MainPresenter(private val mainView: MainView, private val activity: Fragme launchUpdateProgressBarFragment(activity) } else { SystemMenuNotInstalledDialogFragment().show( - activity.supportFragmentManager, - SystemMenuNotInstalledDialogFragment.TAG + activity.supportFragmentManager, SystemMenuNotInstalledDialogFragment.TAG ) } } @@ -345,8 +330,7 @@ class MainPresenter(private val mainView: MainView, private val activity: Fragme EmulationActivity.launchSystemMenu(activity) } else { SystemMenuNotInstalledDialogFragment().show( - activity.supportFragmentManager, - SystemMenuNotInstalledDialogFragment.TAG + activity.supportFragmentManager, SystemMenuNotInstalledDialogFragment.TAG ) } } @@ -373,8 +357,9 @@ class MainPresenter(private val mainView: MainView, private val activity: Fragme private fun launchUpdateProgressBarFragment(activity: FragmentActivity) { val progressBarFragment = SystemUpdateProgressBarDialogFragment() - progressBarFragment - .show(activity.supportFragmentManager, SystemUpdateProgressBarDialogFragment.TAG) + progressBarFragment.show( + activity.supportFragmentManager, SystemUpdateProgressBarDialogFragment.TAG + ) progressBarFragment.isCancelable = false } } From f9a5051bae25fd298aafb020224f2ced174d47fb Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sat, 22 Nov 2025 03:39:50 -0600 Subject: [PATCH 025/267] GCAdapter: Calculate poll rate for display in UI. It's currently updated every 50 reads. --- Source/Core/InputCommon/GCAdapter.cpp | 27 +++++++++++++++++++++++++++ Source/Core/InputCommon/GCAdapter.h | 3 +++ 2 files changed, 30 insertions(+) diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index df212e8f4e89..5ec245a56dd4 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -163,6 +163,8 @@ static std::optional s_config_callback_id = std static bool s_is_adapter_wanted = false; static std::array s_config_rumble_enabled{}; +static std::atomic s_adapter_poll_rate{}; + static void ReadThreadFunc() { Common::SetCurrentThreadName("GCAdapter Read Thread"); @@ -199,6 +201,11 @@ static void ReadThreadFunc() // Reset rumble once on initial reading ResetRumble(); + // Measure poll rate for display in UI. + constexpr int POLL_RATE_MEASUREMENT_SAMPLE_COUNT = 50; + auto poll_rate_measurement_start_time = Clock::now(); + int poll_rate_measurement_count = 0; + while (s_read_adapter_thread_running.IsSet()) { #if GCADAPTER_USE_LIBUSB_IMPLEMENTATION @@ -242,6 +249,19 @@ static void ReadThreadFunc() } #endif + // Update poll rate measurement. + if (++poll_rate_measurement_count == POLL_RATE_MEASUREMENT_SAMPLE_COUNT) + { + const auto now = Clock::now(); + + const auto poll_rate = + POLL_RATE_MEASUREMENT_SAMPLE_COUNT / DT_s(now - poll_rate_measurement_start_time).count(); + s_adapter_poll_rate.store(poll_rate, std::memory_order_relaxed); + + poll_rate_measurement_start_time = now; + poll_rate_measurement_count = 0; + } + Common::YieldCPU(); } @@ -259,6 +279,8 @@ static void ReadThreadFunc() s_detected = false; #endif + s_adapter_poll_rate.store(0.0, std::memory_order_relaxed); + NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GCAdapter read thread stopped"); } @@ -1013,4 +1035,9 @@ bool IsDetected(const char** error_message) #endif } +double GetCurrentPollRate() +{ + return s_adapter_poll_rate.load(std::memory_order_relaxed); +} + } // namespace GCAdapter diff --git a/Source/Core/InputCommon/GCAdapter.h b/Source/Core/InputCommon/GCAdapter.h index e6f62e035b40..50e24ae9402b 100644 --- a/Source/Core/InputCommon/GCAdapter.h +++ b/Source/Core/InputCommon/GCAdapter.h @@ -28,4 +28,7 @@ bool DeviceConnected(int chan); void ResetDeviceType(int chan); bool UseAdapter(); +// Callable from any thread. Returns 0 when the adapter is not detected. +double GetCurrentPollRate(); + } // namespace GCAdapter From 80da48f631952a82c387c261f7cd94f31fea4cb5 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sun, 23 Nov 2025 02:05:38 -0600 Subject: [PATCH 026/267] DolphinQt: Add "Poll Rate" display to GCAdapter config window. The window now refreshes every 500ms. SetAdapterCallback is no longer used. --- .../Config/Mapping/GCPadWiiUConfigDialog.cpp | 20 +++++++++++-------- .../Config/Mapping/GCPadWiiUConfigDialog.h | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.cpp b/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.cpp index 82b39d28e38d..08fa295741c9 100644 --- a/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.cpp @@ -6,10 +6,10 @@ #include #include #include +#include #include #include "Core/Config/MainSettings.h" -#include "Core/ConfigManager.h" #include "DolphinQt/QtUtils/QueueOnObject.h" #include "InputCommon/GCAdapter.h" @@ -23,27 +23,25 @@ GCPadWiiUConfigDialog::GCPadWiiUConfigDialog(int port, QWidget* parent) ConnectWidgets(); } -GCPadWiiUConfigDialog::~GCPadWiiUConfigDialog() -{ - GCAdapter::SetAdapterCallback(nullptr); -} - void GCPadWiiUConfigDialog::CreateLayout() { setWindowTitle(tr("GameCube Controller Adapter at Port %1").arg(m_port + 1)); m_layout = new QVBoxLayout(); m_status_label = new QLabel(); + m_poll_rate_label = new QLabel; m_rumble = new QCheckBox(tr("Enable Rumble")); m_simulate_bongos = new QCheckBox(tr("Simulate DK Bongos")); m_button_box = new QDialogButtonBox(QDialogButtonBox::Ok); UpdateAdapterStatus(); - auto callback = [this] { QueueOnObject(this, &GCPadWiiUConfigDialog::UpdateAdapterStatus); }; - GCAdapter::SetAdapterCallback(callback); + auto* const timer = new QTimer{this}; + connect(timer, &QTimer::timeout, this, &GCPadWiiUConfigDialog::UpdateAdapterStatus); + timer->start(std::chrono::milliseconds{500}); m_layout->addWidget(m_status_label); + m_layout->addWidget(m_poll_rate_label); m_layout->addWidget(m_rumble); m_layout->addWidget(m_simulate_bongos); m_layout->addWidget(m_button_box); @@ -79,6 +77,12 @@ void GCPadWiiUConfigDialog::UpdateAdapterStatus() m_status_label->setText(status_text); + const auto poll_rate = GCAdapter::GetCurrentPollRate(); + if (poll_rate != 0) + m_poll_rate_label->setText(tr("Poll Rate: %1 Hz").arg(poll_rate, 0, 'f', 2)); + else + m_poll_rate_label->clear(); + m_rumble->setEnabled(detected); m_simulate_bongos->setEnabled(detected); } diff --git a/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h b/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h index f18510d3c54a..d71d23761880 100644 --- a/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h +++ b/Source/Core/DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h @@ -15,7 +15,6 @@ class GCPadWiiUConfigDialog final : public QDialog Q_OBJECT public: explicit GCPadWiiUConfigDialog(int port, QWidget* parent = nullptr); - ~GCPadWiiUConfigDialog() override; private: void LoadSettings(); @@ -31,6 +30,7 @@ class GCPadWiiUConfigDialog final : public QDialog QVBoxLayout* m_layout; QLabel* m_status_label; + QLabel* m_poll_rate_label; QDialogButtonBox* m_button_box; // Checkboxes From 419f90107dfe363aa77167331e4812e689ad9606 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Sat, 20 Sep 2025 10:08:31 +0200 Subject: [PATCH 027/267] JitArm64_Integer: Merge subfx and subfcx The optimizations for subfcx introduced in #13852 also apply to subfx. Rather than duplicating the logic, we merge the handlers, like we did in #10120 for x86. --- Source/Core/Core/PowerPC/JitArm64/Jit.h | 1 - .../PowerPC/JitArm64/JitArm64_Integer.cpp | 47 ++++++++----------- .../Core/PowerPC/JitArm64/JitArm64_Tables.cpp | 4 +- 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index e98f950d42fd..5fd25d51d2f7 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -114,7 +114,6 @@ class JitArm64 : public JitBase, public Arm64Gen::ARM64CodeBlock, public CommonA void rlwimix(UGeckoInstruction inst); void subfex(UGeckoInstruction inst); void subfzex(UGeckoInstruction inst); - void subfcx(UGeckoInstruction inst); void subfic(UGeckoInstruction inst); void addex(UGeckoInstruction inst); void divwux(UGeckoInstruction inst); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index cd8b00d49f3d..e82db407563d 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -18,15 +18,18 @@ using namespace Arm64Gen; using namespace JitCommon; -#define CARRY_IF_NEEDED(inst_without_carry, inst_with_carry, ...) \ +#define CARRY_IF_NEEDED_COND(carry, inst_without_carry, inst_with_carry, ...) \ do \ { \ - if (js.op->wantsCA) \ + if ((carry) && js.op->wantsCA) \ inst_with_carry(__VA_ARGS__); \ else \ inst_without_carry(__VA_ARGS__); \ } while (0) +#define CARRY_IF_NEEDED(inst_without_carry, inst_with_carry, ...) \ + CARRY_IF_NEEDED_COND(true, inst_without_carry, inst_with_carry, __VA_ARGS__) + void JitArm64::ComputeRC0(ARM64Reg reg) { gpr.BindCRToRegister(0, false); @@ -1114,20 +1117,6 @@ void JitArm64::addzex(UGeckoInstruction inst) ComputeRC0(gpr.R(d)); } -void JitArm64::subfx(UGeckoInstruction inst) -{ - INSTRUCTION_START - JITDISABLE(bJITIntegerOff); - FALLBACK_IF(inst.OE); - - int a = inst.RA, b = inst.RB, d = inst.RD; - - gpr.BindToRegister(d, d == a || d == b); - SUB(gpr.R(d), gpr.R(b), gpr.R(a)); - if (inst.Rc) - ComputeRC0(gpr.R(d)); -} - void JitArm64::subfex(UGeckoInstruction inst) { INSTRUCTION_START @@ -1259,13 +1248,14 @@ void JitArm64::subfex(UGeckoInstruction inst) ComputeRC0(gpr.R(d)); } -void JitArm64::subfcx(UGeckoInstruction inst) +void JitArm64::subfx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITIntegerOff); FALLBACK_IF(inst.OE); - int a = inst.RA, b = inst.RB, d = inst.RD; + const int a = inst.RA, b = inst.RB, d = inst.RD; + const bool carry = !(inst.SUBOP10 & (1 << 5)); if (gpr.IsImm(a)) { @@ -1278,7 +1268,8 @@ void JitArm64::subfcx(UGeckoInstruction inst) gpr.BindToRegister(d, false); MOV(gpr.R(d), gpr.R(b)); } - ComputeCarry(true); + if (carry) + ComputeCarry(true); if (inst.Rc) ComputeRC0(gpr.R(d)); return; @@ -1289,8 +1280,10 @@ void JitArm64::subfcx(UGeckoInstruction inst) if (low_12 || high_12) { gpr.BindToRegister(d, d == b); - CARRY_IF_NEEDED(SUB, SUBS, gpr.R(d), gpr.R(b), high_12 ? imm >> 12 : imm, high_12); - ComputeCarry(); + CARRY_IF_NEEDED_COND(carry, SUB, SUBS, gpr.R(d), gpr.R(b), high_12 ? imm >> 12 : imm, + high_12); + if (carry) + ComputeCarry(); if (inst.Rc) ComputeRC0(gpr.R(d)); return; @@ -1300,8 +1293,9 @@ void JitArm64::subfcx(UGeckoInstruction inst) if (gpr.IsImm(b, 0)) { gpr.BindToRegister(d, d == a); - CARRY_IF_NEEDED(NEG, NEGS, gpr.R(d), gpr.R(a)); - ComputeCarry(); + CARRY_IF_NEEDED_COND(carry, NEG, NEGS, gpr.R(d), gpr.R(a)); + if (carry) + ComputeCarry(); if (inst.Rc) ComputeRC0(gpr.R(d)); return; @@ -1310,10 +1304,9 @@ void JitArm64::subfcx(UGeckoInstruction inst) gpr.BindToRegister(d, d == a || d == b); // d = b - a - CARRY_IF_NEEDED(SUB, SUBS, gpr.R(d), gpr.R(b), gpr.R(a)); - - ComputeCarry(); - + CARRY_IF_NEEDED_COND(carry, SUB, SUBS, gpr.R(d), gpr.R(b), gpr.R(a)); + if (carry) + ComputeCarry(); if (inst.Rc) ComputeRC0(gpr.R(d)); } diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp index eb97db9b91e5..17b2030e25ef 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp @@ -172,8 +172,8 @@ constexpr std::array s_table31{{ {616, &JitArm64::negx}, // negox {40, &JitArm64::subfx}, // subfx {552, &JitArm64::subfx}, // subfox - {8, &JitArm64::subfcx}, // subfcx - {520, &JitArm64::subfcx}, // subfcox + {8, &JitArm64::subfx}, // subfcx + {520, &JitArm64::subfx}, // subfcox {136, &JitArm64::subfex}, // subfex {648, &JitArm64::subfex}, // subfeox {232, &JitArm64::subfex}, // subfmex From a18cf5693ef87aac87e7407b1865c66c84288398 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Sat, 20 Sep 2025 10:08:43 +0200 Subject: [PATCH 028/267] JitArm64: Remove some unused includes --- Source/Core/Core/PowerPC/JitArm64/Jit.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index 5fd25d51d2f7..78288adb131c 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -6,13 +6,11 @@ #include #include #include -#include #include #include "Common/Arm64Emitter.h" -#include "Core/PowerPC/CPUCoreBase.h" #include "Core/PowerPC/JitArm64/JitArm64Cache.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" #include "Core/PowerPC/JitArmCommon/BackPatch.h" From fbb864a0b5cd68318ec2f18b32bb9b4e6fd377b3 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sat, 1 Nov 2025 17:26:20 -0500 Subject: [PATCH 029/267] MemArena/LazyMemoryRegion: Add EnsureMemoryPagesWritable function to ensure a region of bytes is writable without the caller needing to be aware of the windows-only BLOCK_SIZE value. --- Source/Core/Common/MemArena.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Source/Core/Common/MemArena.h b/Source/Core/Common/MemArena.h index d9d472079cd6..dd07f7039893 100644 --- a/Source/Core/Common/MemArena.h +++ b/Source/Core/Common/MemArena.h @@ -187,6 +187,14 @@ class LazyMemoryRegion final #endif } + void EnsureMemoryPagesWritable(size_t offset, size_t size) + { +#ifdef _WIN32 + for (const auto end_offset = offset + size; offset < end_offset; offset += BLOCK_SIZE) + EnsureMemoryPageWritable(offset); +#endif + } + private: void* m_memory = nullptr; size_t m_size = 0; From d7c3513eae507344b750bf7c67e04961d2751ce1 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Wed, 29 Oct 2025 02:12:36 -0500 Subject: [PATCH 030/267] DiscIO: Add CachedBlobReader which takes another BlobReader and reads it into memory in the background. --- Source/Core/DiscIO/CMakeLists.txt | 2 + Source/Core/DiscIO/CachedBlob.cpp | 239 ++++++++++++++++++++++++++++++ Source/Core/DiscIO/CachedBlob.h | 16 ++ Source/Core/DolphinLib.props | 2 + 4 files changed, 259 insertions(+) create mode 100644 Source/Core/DiscIO/CachedBlob.cpp create mode 100644 Source/Core/DiscIO/CachedBlob.h diff --git a/Source/Core/DiscIO/CMakeLists.txt b/Source/Core/DiscIO/CMakeLists.txt index 884f3de4f2dc..e2664f4a1a3a 100644 --- a/Source/Core/DiscIO/CMakeLists.txt +++ b/Source/Core/DiscIO/CMakeLists.txt @@ -3,6 +3,8 @@ add_library(discio Blob.h CISOBlob.cpp CISOBlob.h + CachedBlob.cpp + CachedBlob.h CompressedBlob.cpp CompressedBlob.h DirectoryBlob.cpp diff --git a/Source/Core/DiscIO/CachedBlob.cpp b/Source/Core/DiscIO/CachedBlob.cpp new file mode 100644 index 000000000000..98ed8ba31f34 --- /dev/null +++ b/Source/Core/DiscIO/CachedBlob.cpp @@ -0,0 +1,239 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "DiscIO/CachedBlob.h" + +#include +#include +#include + +#include "Common/CommonTypes.h" +#include "Common/Logging/Log.h" +#include "Common/MemArena.h" + +#include "DiscIO/DiscScrubber.h" +#include "DiscIO/Volume.h" + +namespace DiscIO +{ +class CacheFiller final +{ +public: + explicit CacheFiller(std::unique_ptr reader, bool attempt_to_scrub) + : m_thread{&CacheFiller::ThreadFunc, this, std::move(reader), attempt_to_scrub} + { + } + + ~CacheFiller() + { + m_stop_thread.store(true, std::memory_order_relaxed); + m_thread.join(); + } + + bool Read(u64 offset, u64 size, u8* out_ptr) + { + if (size == 0) + { + // Just return early to safely handle a read of zero if that were to happen. + // This avoids a m_memory_region_data initialization race. + return true; + } + + switch (GetCacheState(offset, size)) + { + case CacheState::Cached: + std::memcpy(out_ptr, m_memory_region_data + offset, size); + return true; + + case CacheState::Scrubbed: + WARN_LOG_FMT(DISCIO, + "CachedBlobReader: Read({}, {}) hits a scrubbed cluster which is not cached.", + offset, size); + return false; + + default: + return false; + } + } + +private: + enum class CacheState + { + Cached, + NotCached, + Scrubbed, + }; + + CacheState GetCacheState(u64 offset, u64 size) + { + const auto cache_pos = m_cache_filled_pos.load(std::memory_order_acquire); + + const auto end_pos = offset + size; + if (end_pos > cache_pos) + return CacheState::NotCached; + + for (u64 i = offset; i < end_pos; i += DiscScrubber::CLUSTER_SIZE) + { + if (m_scrubber.CanBlockBeScrubbed(i)) + return CacheState::Scrubbed; + } + + return CacheState::Cached; + } + + void ThreadFunc(std::unique_ptr reader, bool attempt_to_scrub) + { + static constexpr auto PERIODIC_LOG_TIME = std::chrono::seconds{1}; + + const auto start_time = Clock::now(); + const u64 total_size = reader->GetDataSize(); + + m_memory_region_data = static_cast(m_memory_region.Create(total_size)); + if (m_memory_region_data == nullptr) + { + ERROR_LOG_FMT(DISCIO, "CachedBlobReader: Failed to create memory region."); + return; + } + + // Returns CLUSTER_SIZE or smaller at the end of the file. + const auto get_read_size = [&](u64 pos) { + return std::min(total_size - pos, DiscScrubber::CLUSTER_SIZE); + }; + + // Used for periodic progress logging. + u64 total_bytes_to_commit = total_size; + + if (attempt_to_scrub) + { + const auto volume = CreateVolume(reader->CopyReader()); + if (volume != nullptr && m_scrubber.SetupScrub(*volume)) + { + for (u64 i = 0; i < total_size; i += DiscScrubber::CLUSTER_SIZE) + { + if (m_scrubber.CanBlockBeScrubbed(i)) + total_bytes_to_commit -= get_read_size(i); + } + } + else + { + WARN_LOG_FMT(DISCIO, "CachedBlobReader: Failed to scrub. The entire file will be cached."); + } + } + + auto next_log_time = start_time + PERIODIC_LOG_TIME; + u64 read_offset = 0; + u64 committed_count = 0; + + while (true) + { + if (m_stop_thread.load(std::memory_order_relaxed)) + { + INFO_LOG_FMT(DISCIO, "CachedBlobReader: Stopped"); + break; + } + + const auto read_size = get_read_size(read_offset); + if (read_size == 0) + { + const auto total_time = DT_s{Clock::now() - start_time}.count(); + + static constexpr auto mib_scale = double(1 << 20); + + NOTICE_LOG_FMT( + DISCIO, "CachedBlobReader: Completed. Cached {:.2f} of {:.2f} MiB in {:.2f} seconds.", + committed_count / mib_scale, total_size / mib_scale, total_time); + break; + } + + if (!m_scrubber.CanBlockBeScrubbed(read_offset)) + { + m_memory_region.EnsureMemoryPagesWritable(read_offset, read_size); + + if (!reader->Read(read_offset, read_size, m_memory_region_data + read_offset)) + { + ERROR_LOG_FMT(DISCIO, "CachedBlobReader: Read({}, {}) failed.", read_offset, read_size); + break; + } + + committed_count += read_size; + } + + read_offset += read_size; + m_cache_filled_pos.store(read_offset, std::memory_order_release); + + if (const auto now = Clock::now(); now >= next_log_time) + { + INFO_LOG_FMT(DISCIO, "CachedBlobReader: Progress: {}%", + committed_count * 100 / total_bytes_to_commit); + next_log_time = now + PERIODIC_LOG_TIME; + } + } + } + + // The thread has read non-scrubbed bytes into memory up to this point. + std::atomic m_cache_filled_pos{}; + + Common::LazyMemoryRegion m_memory_region; + u8* m_memory_region_data{}; + + DiscScrubber m_scrubber; + + std::atomic_bool m_stop_thread{}; + std::thread m_thread; +}; + +class CachedBlobReader final : public BlobReader +{ +public: + explicit CachedBlobReader(std::unique_ptr reader, bool attempt_to_scrub) + : m_cache_filler{std::make_shared(reader->CopyReader(), attempt_to_scrub)}, + m_reader{std::move(reader)} + + { + INFO_LOG_FMT(DISCIO, "CachedBlobReader: Created"); + } + + CachedBlobReader(std::shared_ptr cache_filler, std::unique_ptr reader) + : m_cache_filler{std::move(cache_filler)}, m_reader{std::move(reader)} + { + INFO_LOG_FMT(DISCIO, "CachedBlobReader: Copied"); + } + + std::unique_ptr CopyReader() const override + { + return std::make_unique(m_cache_filler, m_reader->CopyReader()); + } + + BlobType GetBlobType() const override { return m_reader->GetBlobType(); } + u64 GetRawSize() const override { return GetDataSize(); } + u64 GetDataSize() const override { return m_reader->GetDataSize(); } + DataSizeType GetDataSizeType() const override { return m_reader->GetDataSizeType(); } + + u64 GetBlockSize() const override { return 0; } + bool HasFastRandomAccessInBlock() const override { return true; } + std::string GetCompressionMethod() const override { return {}; } + std::optional GetCompressionLevel() const override { return std::nullopt; } + + bool Read(u64 offset, u64 size, u8* out_ptr) override + { + return m_cache_filler->Read(offset, size, out_ptr) || m_reader->Read(offset, size, out_ptr); + } + +private: + // A shared object does the cache filling for sensible CopyReader behavior. + const std::shared_ptr m_cache_filler; + + const std::unique_ptr m_reader; +}; + +std::unique_ptr CreateCachedBlobReader(std::unique_ptr reader) +{ + return std::make_unique(std::move(reader), false); +} + +std::unique_ptr CreateScrubbingCachedBlobReader(std::unique_ptr reader) +{ + return std::make_unique(std::move(reader), true); +} + +} // namespace DiscIO diff --git a/Source/Core/DiscIO/CachedBlob.h b/Source/Core/DiscIO/CachedBlob.h new file mode 100644 index 000000000000..f99ad552bbbe --- /dev/null +++ b/Source/Core/DiscIO/CachedBlob.h @@ -0,0 +1,16 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "DiscIO/Blob.h" + +namespace DiscIO +{ + +std::unique_ptr CreateCachedBlobReader(std::unique_ptr reader); +std::unique_ptr CreateScrubbingCachedBlobReader(std::unique_ptr reader); + +} // namespace DiscIO diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index f4a9c04a926a..e13f3da7ccf0 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -484,6 +484,7 @@ + @@ -1168,6 +1169,7 @@ + From e5ad814142257063ca00847c40561ce3d852f4f1 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Wed, 29 Oct 2025 22:57:32 -0500 Subject: [PATCH 031/267] Core/DiscIO: Add a setting to load the running game into memory via CachedBlobReader. --- Source/Core/Core/Boot/Boot.cpp | 6 ++-- Source/Core/Core/Config/MainSettings.cpp | 1 + Source/Core/Core/Config/MainSettings.h | 1 + Source/Core/Core/HW/DVD/DVDInterface.cpp | 3 +- Source/Core/DiscIO/Volume.cpp | 34 ++++++++++++++----- Source/Core/DiscIO/Volume.h | 3 ++ .../Core/DolphinQt/Settings/GeneralPane.cpp | 10 ++++++ Source/Core/DolphinQt/Settings/GeneralPane.h | 1 + 8 files changed, 46 insertions(+), 13 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 755ed0427a37..236cea81b9c9 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -240,7 +240,7 @@ std::unique_ptr BootParameters::GenerateFromFile(std::vector disc = DiscIO::CreateDisc(path); + std::unique_ptr disc = DiscIO::CreateDiscForCore(path); if (disc) { return std::make_unique(Disc{std::move(path), std::move(disc), paths}, @@ -469,7 +469,7 @@ static void SetDefaultDisc(DVD::DVDInterface& dvd_interface) { const std::string default_iso = Config::Get(Config::MAIN_DEFAULT_ISO); if (!default_iso.empty()) - SetDisc(dvd_interface, DiscIO::CreateDisc(default_iso)); + SetDisc(dvd_interface, DiscIO::CreateDiscForCore(default_iso)); } static void CopyDefaultExceptionHandlers(Core::System& system) @@ -629,7 +629,7 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard, if (ipl.disc) { NOTICE_LOG_FMT(BOOT, "Inserting disc: {}", ipl.disc->path); - SetDisc(system.GetDVDInterface(), DiscIO::CreateDisc(ipl.disc->path), + SetDisc(system.GetDVDInterface(), DiscIO::CreateDiscForCore(ipl.disc->path), ipl.disc->auto_disc_change_paths); } else diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index b06fb5b49639..4a22728a8426 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -58,6 +58,7 @@ constexpr bool DEFAULT_CPU_THREAD = true; constexpr bool DEFAULT_CPU_THREAD = false; #endif const Info MAIN_CPU_THREAD{{System::Main, "Core", "CPUThread"}, DEFAULT_CPU_THREAD}; +const Info MAIN_LOAD_GAME_INTO_MEMORY{{System::Main, "Core", "LoadGameIntoMemory"}, false}; const Info MAIN_SYNC_ON_SKIP_IDLE{{System::Main, "Core", "SyncOnSkipIdle"}, true}; const Info MAIN_DEFAULT_ISO{{System::Main, "Core", "DefaultISO"}, ""}; const Info MAIN_ENABLE_CHEATS{{System::Main, "Core", "EnableCheats"}, false}; diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index cc64c80d69c1..17689f7ecacd 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -68,6 +68,7 @@ extern const Info MAIN_CORRECT_TIME_DRIFT; extern const Info MAIN_RUSH_FRAME_PRESENTATION; extern const Info MAIN_SMOOTH_EARLY_PRESENTATION; extern const Info MAIN_CPU_THREAD; +extern const Info MAIN_LOAD_GAME_INTO_MEMORY; extern const Info MAIN_SYNC_ON_SKIP_IDLE; extern const Info MAIN_DEFAULT_ISO; extern const Info MAIN_ENABLE_CHEATS; diff --git a/Source/Core/Core/HW/DVD/DVDInterface.cpp b/Source/Core/Core/HW/DVD/DVDInterface.cpp index 410f5763a551..49cafccb70ad 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp @@ -428,7 +428,8 @@ void DVDInterface::EjectDiscCallback(Core::System& system, u64 userdata, s64 cyc void DVDInterface::InsertDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate) { auto& di = system.GetDVDInterface(); - std::unique_ptr new_disc = DiscIO::CreateDisc(di.m_disc_path_to_insert); + std::unique_ptr new_disc = + DiscIO::CreateDiscForCore(di.m_disc_path_to_insert); if (new_disc) di.SetDisc(std::move(new_disc), {}); diff --git a/Source/Core/DiscIO/Volume.cpp b/Source/Core/DiscIO/Volume.cpp index b6d84254f01f..7e5dcc7976c3 100644 --- a/Source/Core/DiscIO/Volume.cpp +++ b/Source/Core/DiscIO/Volume.cpp @@ -3,7 +3,7 @@ #include "DiscIO/Volume.h" -#include +#include #include #include #include @@ -16,8 +16,11 @@ #include "Common/Crypto/SHA1.h" #include "Common/StringUtil.h" +#include "Core/Config/MainSettings.h" #include "Core/IOS/ES/Formats.h" + #include "DiscIO/Blob.h" +#include "DiscIO/CachedBlob.h" #include "DiscIO/DiscUtils.h" #include "DiscIO/Enums.h" #include "DiscIO/VolumeDisc.h" @@ -84,16 +87,21 @@ std::map Volume::ReadWiiNames(const std::vector return names; } -static std::unique_ptr TryCreateDisc(std::unique_ptr& reader) +template +static std::unique_ptr TryCreateDisc(std::unique_ptr reader, + const T& reader_adapter_factory = {}) { if (!reader) return nullptr; + // `reader_adapter_factory` is used *after* successful magic word read. + // This prevents `CachedBlobReader` from showing warnings when failing to scrub a .dol file. + if (reader->ReadSwapped(0x18) == WII_DISC_MAGIC) - return std::make_unique(std::move(reader)); + return std::make_unique(reader_adapter_factory(std::move(reader))); if (reader->ReadSwapped(0x1C) == GAMECUBE_DISC_MAGIC) - return std::make_unique(std::move(reader)); + return std::make_unique(reader_adapter_factory(std::move(reader))); // No known magic words found return nullptr; @@ -101,7 +109,7 @@ static std::unique_ptr TryCreateDisc(std::unique_ptr& re std::unique_ptr CreateDisc(std::unique_ptr reader) { - return TryCreateDisc(reader); + return TryCreateDisc(std::move(reader)); } std::unique_ptr CreateDisc(const std::string& path) @@ -109,7 +117,15 @@ std::unique_ptr CreateDisc(const std::string& path) return CreateDisc(CreateBlobReader(path)); } -static std::unique_ptr TryCreateWAD(std::unique_ptr& reader) +std::unique_ptr CreateDiscForCore(const std::string& path) +{ + if (Config::Get(Config::MAIN_LOAD_GAME_INTO_MEMORY)) + return TryCreateDisc(CreateBlobReader(path), CreateScrubbingCachedBlobReader); + + return CreateDisc(path); +} + +static std::unique_ptr TryCreateWAD(std::unique_ptr reader) { if (!reader) return nullptr; @@ -126,7 +142,7 @@ static std::unique_ptr TryCreateWAD(std::unique_ptr& read std::unique_ptr CreateWAD(std::unique_ptr reader) { - return TryCreateWAD(reader); + return TryCreateWAD(std::move(reader)); } std::unique_ptr CreateWAD(const std::string& path) @@ -136,11 +152,11 @@ std::unique_ptr CreateWAD(const std::string& path) std::unique_ptr CreateVolume(std::unique_ptr reader) { - std::unique_ptr disc = TryCreateDisc(reader); + std::unique_ptr disc = TryCreateDisc(std::move(reader)); if (disc) return disc; - std::unique_ptr wad = TryCreateWAD(reader); + std::unique_ptr wad = TryCreateWAD(std::move(reader)); if (wad) return wad; diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index a7273b0f0ebb..3f80cd2e3dd4 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -176,6 +176,9 @@ class Volume std::unique_ptr CreateDisc(std::unique_ptr reader); std::unique_ptr CreateDisc(const std::string& path); +// This version enables caching when the "Load Games into Memory" setting is enabled. +std::unique_ptr CreateDiscForCore(const std::string& path); + std::unique_ptr CreateWAD(std::unique_ptr reader); std::unique_ptr CreateWAD(const std::string& path); std::unique_ptr CreateVolume(std::unique_ptr reader); diff --git a/Source/Core/DolphinQt/Settings/GeneralPane.cpp b/Source/Core/DolphinQt/Settings/GeneralPane.cpp index 93e3d0d9c827..661f5f13b235 100644 --- a/Source/Core/DolphinQt/Settings/GeneralPane.cpp +++ b/Source/Core/DolphinQt/Settings/GeneralPane.cpp @@ -90,6 +90,7 @@ void GeneralPane::OnEmulationStateChanged(Core::State state) m_checkbox_dualcore->setEnabled(!running); m_checkbox_cheats->setEnabled(!running); + m_checkbox_load_games_into_memory->setEnabled(!running); m_checkbox_override_region_settings->setEnabled(!running); #ifdef USE_DISCORD_PRESENCE m_checkbox_discord_presence->setEnabled(!running); @@ -147,6 +148,15 @@ void GeneralPane::CreateBasic() m_checkbox_cheats = new ConfigBool(tr("Enable Cheats"), Config::MAIN_ENABLE_CHEATS); basic_group_layout->addWidget(m_checkbox_cheats); + m_checkbox_load_games_into_memory = + new ConfigBool(tr("Load Whole Game Into Memory"), Config::MAIN_LOAD_GAME_INTO_MEMORY); + basic_group_layout->addWidget(m_checkbox_load_games_into_memory); + m_checkbox_load_games_into_memory->SetDescription( + tr("Loads the running game into memory in the background." + "

This may improve performance with slow or high-latency storage." + "
System memory requirements will be much higher with this setting enabled." + "

If unsure, leave this unchecked.")); + m_checkbox_override_region_settings = new ConfigBool(tr("Allow Mismatched Region Settings"), Config::MAIN_OVERRIDE_REGION_SETTINGS); basic_group_layout->addWidget(m_checkbox_override_region_settings); diff --git a/Source/Core/DolphinQt/Settings/GeneralPane.h b/Source/Core/DolphinQt/Settings/GeneralPane.h index 17d80f7c3851..b482172b0950 100644 --- a/Source/Core/DolphinQt/Settings/GeneralPane.h +++ b/Source/Core/DolphinQt/Settings/GeneralPane.h @@ -48,6 +48,7 @@ class GeneralPane final : public QWidget ToolTipComboBox* m_combobox_fallback_region; ConfigBool* m_checkbox_dualcore; ConfigBool* m_checkbox_cheats; + ConfigBool* m_checkbox_load_games_into_memory; ConfigBool* m_checkbox_override_region_settings; ConfigBool* m_checkbox_auto_disc_change; #ifdef USE_DISCORD_PRESENCE From 59d9c1772a0b27ea38fff28ac6c15bba824227be Mon Sep 17 00:00:00 2001 From: iwubcode Date: Fri, 7 Nov 2025 23:17:25 -0600 Subject: [PATCH 032/267] VideoCommon: rename 'IsAnisostropicEnhancementSafe' to 'IsAnisotropicEnhancementSafe' in TextureCacheBase --- Source/Core/VideoCommon/TextureCacheBase.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index f057c4f23d4d..ce2742938144 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -994,7 +994,7 @@ RcTcacheEntry TextureCacheBase::DoPartialTextureUpdates(RcTcacheEntry& entry_to_ // then applying anisotropic filtering is equivalent to forced filtering. Point // mode textures are usually some sort of 2D UI billboard which will end up // misaligned from the correct pixels when filtered anisotropically. -static bool IsAnisostropicEnhancementSafe(const TexMode0& tm0) +static bool IsAnisotropicEnhancementSafe(const TexMode0& tm0) { return !(tm0.min_filter == FilterMode::Near && tm0.mag_filter == FilterMode::Near); } @@ -1028,7 +1028,7 @@ SamplerState TextureCacheBase::GetSamplerState(u32 index, float custom_tex_scale // Anisotropic filtering option. if (g_ActiveConfig.iMaxAnisotropy != AnisotropicFilteringMode::Default && - IsAnisostropicEnhancementSafe(tm0)) + IsAnisotropicEnhancementSafe(tm0)) { state.tm0.anisotropic_filtering = Common::ToUnderlying(g_ActiveConfig.iMaxAnisotropy); } From 2d21a9920577b8c827d056d9a5e03dcf026ae6e1 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Wed, 29 Oct 2025 01:21:30 -0500 Subject: [PATCH 033/267] VideoCommon: separate the concept of a 'resource' from an 'asset'. A resource is potentially multiple assets that are chained together but represent one type of data to the rest of the system. An example is a 'material'. A 'material' is a collection of textures, a custom shader, and some metadata that all comes together to form what the concept of the material is. There will be a 'material' resource. For now, start small by introducing the interface and change our texture loading which used assets from the old resource manager, to an actual resource. --- Source/Core/Core/System.cpp | 2 +- Source/Core/DolphinLib.props | 11 +- .../Core/VideoCommon/Assets/AssetListener.h | 23 ++++ ...sourceManager.cpp => CustomAssetCache.cpp} | 82 ++++-------- ...omResourceManager.h => CustomAssetCache.h} | 104 +++++++-------- .../Assets/DirectFilesystemAssetLibrary.cpp | 2 +- Source/Core/VideoCommon/CMakeLists.txt | 11 +- Source/Core/VideoCommon/HiresTextures.cpp | 3 +- Source/Core/VideoCommon/HiresTextures.h | 11 +- .../Resources/CustomResourceManager.cpp | 124 ++++++++++++++++++ .../Resources/CustomResourceManager.h | 46 +++++++ .../Core/VideoCommon/Resources/Resource.cpp | 81 ++++++++++++ Source/Core/VideoCommon/Resources/Resource.h | 82 ++++++++++++ .../Resources/TextureDataResource.cpp | 48 +++++++ .../Resources/TextureDataResource.h | 33 +++++ Source/Core/VideoCommon/TextureCacheBase.cpp | 11 +- Source/Core/VideoCommon/VideoBackendBase.cpp | 2 +- 17 files changed, 541 insertions(+), 135 deletions(-) create mode 100644 Source/Core/VideoCommon/Assets/AssetListener.h rename Source/Core/VideoCommon/Assets/{CustomResourceManager.cpp => CustomAssetCache.cpp} (61%) rename Source/Core/VideoCommon/Assets/{CustomResourceManager.h => CustomAssetCache.h} (72%) create mode 100644 Source/Core/VideoCommon/Resources/CustomResourceManager.cpp create mode 100644 Source/Core/VideoCommon/Resources/CustomResourceManager.h create mode 100644 Source/Core/VideoCommon/Resources/Resource.cpp create mode 100644 Source/Core/VideoCommon/Resources/Resource.h create mode 100644 Source/Core/VideoCommon/Resources/TextureDataResource.cpp create mode 100644 Source/Core/VideoCommon/Resources/TextureDataResource.h diff --git a/Source/Core/Core/System.cpp b/Source/Core/Core/System.cpp index 22681cac4302..d22c0582583b 100644 --- a/Source/Core/Core/System.cpp +++ b/Source/Core/Core/System.cpp @@ -33,12 +33,12 @@ #include "IOS/USB/Emulated/Infinity.h" #include "IOS/USB/Emulated/Skylanders/Skylander.h" #include "IOS/USB/USBScanner.h" -#include "VideoCommon/Assets/CustomResourceManager.h" #include "VideoCommon/CommandProcessor.h" #include "VideoCommon/Fifo.h" #include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelShaderManager.h" +#include "VideoCommon/Resources/CustomResourceManager.h" #include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/XFStateManager.h" diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index f4a9c04a926a..e8ca03d4bdfb 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -673,10 +673,11 @@ + + - @@ -752,6 +753,9 @@ + + + @@ -1340,8 +1344,8 @@ + - @@ -1402,6 +1406,9 @@ + + + diff --git a/Source/Core/VideoCommon/Assets/AssetListener.h b/Source/Core/VideoCommon/Assets/AssetListener.h new file mode 100644 index 000000000000..d543a2bb14b9 --- /dev/null +++ b/Source/Core/VideoCommon/Assets/AssetListener.h @@ -0,0 +1,23 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace VideoCommon +{ +class AssetListener +{ +public: + AssetListener() = default; + virtual ~AssetListener() = default; + + AssetListener(const AssetListener&) = default; + AssetListener(AssetListener&&) = default; + AssetListener& operator=(const AssetListener&) = default; + AssetListener& operator=(AssetListener&&) = default; + + virtual void NotifyAssetLoadSuccess() = 0; + virtual void NotifyAssetLoadFailed() = 0; + virtual void AssetUnloaded() = 0; +}; +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Assets/CustomResourceManager.cpp b/Source/Core/VideoCommon/Assets/CustomAssetCache.cpp similarity index 61% rename from Source/Core/VideoCommon/Assets/CustomResourceManager.cpp rename to Source/Core/VideoCommon/Assets/CustomAssetCache.cpp index 6f8d3557bb19..606f28d5fe70 100644 --- a/Source/Core/VideoCommon/Assets/CustomResourceManager.cpp +++ b/Source/Core/VideoCommon/Assets/CustomAssetCache.cpp @@ -1,7 +1,7 @@ // Copyright 2025 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "VideoCommon/Assets/CustomResourceManager.h" +#include "VideoCommon/Assets/CustomAssetCache.h" #include "Common/Logging/Log.h" #include "Common/MemoryUtil.h" @@ -14,7 +14,7 @@ namespace VideoCommon { -void CustomResourceManager::Initialize() +void CustomAssetCache::Initialize() { // Use half of available system memory but leave at least 2GiB unused for system stability. constexpr size_t must_keep_unused = 2 * size_t(1024 * 1024 * 1024); @@ -28,19 +28,16 @@ void CustomResourceManager::Initialize() ERROR_LOG_FMT(VIDEO, "Not enough system memory for custom resources."); m_asset_loader.Initialize(); - - m_xfb_event = - GetVideoEvents().after_frame_event.Register([this](Core::System&) { XFBTriggered(); }); } -void CustomResourceManager::Shutdown() +void CustomAssetCache::Shutdown() { Reset(); m_asset_loader.Shutdown(); } -void CustomResourceManager::Reset() +void CustomAssetCache::Reset() { m_asset_loader.Reset(true); @@ -48,66 +45,27 @@ void CustomResourceManager::Reset() m_pending_assets = {}; m_asset_handle_to_data.clear(); m_asset_id_to_handle.clear(); - m_texture_data_asset_cache.clear(); m_dirty_assets.clear(); m_ram_used = 0; } -void CustomResourceManager::MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id) +void CustomAssetCache::MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id) { std::lock_guard guard(m_dirty_mutex); m_dirty_assets.insert(asset_id); } -CustomResourceManager::TextureTimePair CustomResourceManager::GetTextureDataFromAsset( - const CustomAssetLibrary::AssetID& asset_id, - std::shared_ptr library) +void CustomAssetCache::MarkAssetPending(CustomAsset* asset) { - auto& resource = m_texture_data_asset_cache[asset_id]; - if (resource.asset_data != nullptr && - resource.asset_data->load_status == AssetData::LoadStatus::ResourceDataAvailable) - { - m_active_assets.MakeAssetHighestPriority(resource.asset->GetHandle(), resource.asset); - return {resource.texture_data, resource.asset->GetLastLoadedTime()}; - } - - // If there is an error, don't try and load again until the error is fixed - if (resource.asset_data != nullptr && resource.asset_data->has_load_error) - return {}; - - LoadTextureDataAsset(asset_id, std::move(library), &resource); - m_active_assets.MakeAssetHighestPriority(resource.asset->GetHandle(), resource.asset); - - return {}; + m_pending_assets.MakeAssetHighestPriority(asset->GetHandle(), asset); } -void CustomResourceManager::LoadTextureDataAsset( - const CustomAssetLibrary::AssetID& asset_id, - std::shared_ptr library, InternalTextureDataResource* resource) +void CustomAssetCache::MarkAssetActive(CustomAsset* asset) { - if (!resource->asset) - { - resource->asset = - CreateAsset(asset_id, AssetData::AssetType::TextureData, std::move(library)); - resource->asset_data = &m_asset_handle_to_data[resource->asset->GetHandle()]; - } - - auto texture_data = resource->asset->GetData(); - if (!texture_data || resource->asset_data->load_status == AssetData::LoadStatus::PendingReload) - { - // Tell the system we are still interested in loading this asset - const auto asset_handle = resource->asset->GetHandle(); - m_pending_assets.MakeAssetHighestPriority(asset_handle, - m_asset_handle_to_data[asset_handle].asset.get()); - } - else if (resource->asset_data->load_status == AssetData::LoadStatus::LoadFinished) - { - resource->texture_data = std::move(texture_data); - resource->asset_data->load_status = AssetData::LoadStatus::ResourceDataAvailable; - } + m_active_assets.MakeAssetHighestPriority(asset->GetHandle(), asset); } -void CustomResourceManager::XFBTriggered() +void CustomAssetCache::Update() { ProcessDirtyAssets(); ProcessLoadedAssets(); @@ -127,7 +85,7 @@ void CustomResourceManager::XFBTriggered() m_asset_loader.ScheduleAssetsToLoad(m_pending_assets.Elements(), allowed_memory); } -void CustomResourceManager::ProcessDirtyAssets() +void CustomAssetCache::ProcessDirtyAssets() { decltype(m_dirty_assets) dirty_assets; @@ -154,7 +112,7 @@ void CustomResourceManager::ProcessDirtyAssets() } } -void CustomResourceManager::ProcessLoadedAssets() +void CustomAssetCache::ProcessLoadedAssets() { const auto load_results = m_asset_loader.TakeLoadResults(); @@ -189,10 +147,18 @@ void CustomResourceManager::ProcessLoadedAssets() m_active_assets.InsertAsset(handle, asset_data.asset.get()); asset_data.load_status = AssetData::LoadStatus::LoadFinished; } + + for (const auto& listener : asset_data.listeners) + { + if (load_successful) + listener->NotifyAssetLoadSuccess(); + else + listener->NotifyAssetLoadFailed(); + } } } -void CustomResourceManager::RemoveAssetsUntilBelowMemoryLimit() +void CustomAssetCache::RemoveAssetsUntilBelowMemoryLimit() { const u64 threshold_ram = m_max_ram_available * 8 / 10; @@ -209,11 +175,11 @@ void CustomResourceManager::RemoveAssetsUntilBelowMemoryLimit() AssetData& asset_data = m_asset_handle_to_data[asset->GetHandle()]; - // Remove the resource manager's cached entry with its asset data - if (asset_data.type == AssetData::AssetType::TextureData) + for (const auto& listener : asset_data.listeners) { - m_texture_data_asset_cache.erase(asset->GetAssetId()); + listener->AssetUnloaded(); } + // Remove the asset's copy const std::size_t bytes_unloaded = asset_data.asset->Unload(); m_ram_used -= bytes_unloaded; diff --git a/Source/Core/VideoCommon/Assets/CustomResourceManager.h b/Source/Core/VideoCommon/Assets/CustomAssetCache.h similarity index 72% rename from Source/Core/VideoCommon/Assets/CustomResourceManager.h rename to Source/Core/VideoCommon/Assets/CustomAssetCache.h index 6a2b5cbbe303..169c0faaf8a3 100644 --- a/Source/Core/VideoCommon/Assets/CustomResourceManager.h +++ b/Source/Core/VideoCommon/Assets/CustomAssetCache.h @@ -10,108 +10,96 @@ #include #include "Common/CommonTypes.h" -#include "Common/HookableEvent.h" +#include "VideoCommon/Assets/AssetListener.h" #include "VideoCommon/Assets/CustomAsset.h" #include "VideoCommon/Assets/CustomAssetLibrary.h" #include "VideoCommon/Assets/CustomAssetLoader.h" -#include "VideoCommon/Assets/CustomTextureData.h" namespace VideoCommon { -class TextureAsset; - -// The resource manager manages custom resources (textures, shaders, meshes) -// called assets. These assets are loaded using a priority system, +// The asset cache manages custom assets (textures, shaders, meshes). +// These assets are loaded using a priority system, // where assets requested more often gets loaded first. This system // also tracks memory usage and if memory usage goes over a calculated limit, // then assets will be purged with older assets being targeted first. -class CustomResourceManager +class CustomAssetCache { public: - void Initialize(); - void Shutdown(); - - void Reset(); - - // Request that an asset be reloaded - void MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id); - - void XFBTriggered(); - - using TextureTimePair = std::pair, CustomAsset::TimeType>; - - // Returns a pair with the custom texture data and the time it was last loaded - // Callees are not expected to hold onto the shared_ptr as that will prevent - // the resource manager from being able to properly release data - TextureTimePair GetTextureDataFromAsset(const CustomAssetLibrary::AssetID& asset_id, - std::shared_ptr library); - -private: - // A generic interface to describe an assets' type + // A generic interface to describe an asset // and load state struct AssetData { std::unique_ptr asset; + + std::vector listeners; + CustomAsset::TimeType load_request_time = {}; bool has_load_error = false; - enum class AssetType - { - TextureData - }; - AssetType type; - enum class LoadStatus { PendingReload, LoadFinished, - ResourceDataAvailable, Unloaded, }; LoadStatus load_status = LoadStatus::PendingReload; }; - // A structure to represent some raw texture data - // (this data hasn't hit the GPU yet, used for custom textures) - struct InternalTextureDataResource - { - AssetData* asset_data = nullptr; - VideoCommon::TextureAsset* asset = nullptr; - std::shared_ptr texture_data; - }; - - void LoadTextureDataAsset(const CustomAssetLibrary::AssetID& asset_id, - std::shared_ptr library, - InternalTextureDataResource* resource); - - void ProcessDirtyAssets(); - void ProcessLoadedAssets(); - void RemoveAssetsUntilBelowMemoryLimit(); - template - T* CreateAsset(const CustomAssetLibrary::AssetID& asset_id, AssetData::AssetType asset_type, - std::shared_ptr library) + T* CreateAsset(const CustomAssetLibrary::AssetID& asset_id, + std::shared_ptr library, AssetListener* listener) { const auto [it, added] = m_asset_id_to_handle.try_emplace(asset_id, m_asset_handle_to_data.size()); - if (added) { AssetData asset_data; - asset_data.asset = std::make_unique(library, asset_id, it->second); - asset_data.type = asset_type; + asset_data.asset = std::make_unique(std::move(library), asset_id, it->second); asset_data.load_request_time = {}; asset_data.has_load_error = false; m_asset_handle_to_data.insert_or_assign(it->second, std::move(asset_data)); } + auto& asset_data_from_handle = m_asset_handle_to_data[it->second]; + asset_data_from_handle.listeners.push_back(listener); asset_data_from_handle.load_status = AssetData::LoadStatus::PendingReload; return static_cast(asset_data_from_handle.asset.get()); } + AssetData* GetAssetData(const CustomAssetLibrary::AssetID& asset_id) + { + const auto it_handle = m_asset_id_to_handle.find(asset_id); + if (it_handle == m_asset_id_to_handle.end()) + return nullptr; + return &m_asset_handle_to_data[it_handle->second]; + } + + void Initialize(); + void Shutdown(); + + void Reset(); + + // Request that an asset be reloaded + void MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id); + + // Notify the system that we are interested in this asset and + // are waiting for it to be loaded + void MarkAssetPending(CustomAsset* asset); + + // Notify the system we are interested in this asset and + // it has seen activity + void MarkAssetActive(CustomAsset* asset); + + void Update(); + +private: + void ProcessDirtyAssets(); + void ProcessLoadedAssets(); + void RemoveAssetsUntilBelowMemoryLimit(); + // Maintains a priority-sorted list of assets. // Used to figure out which assets to load or unload first. // Most recently used assets get marked with highest priority. @@ -202,14 +190,10 @@ class CustomResourceManager // A calculated amount of memory to avoid exceeding. u64 m_max_ram_available = 0; - std::map m_texture_data_asset_cache; - std::mutex m_dirty_mutex; std::set m_dirty_assets; CustomAssetLoader m_asset_loader; - - Common::EventHook m_xfb_event; }; } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp b/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp index 5e400f3de509..91f3102c58da 100644 --- a/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp +++ b/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp @@ -14,13 +14,13 @@ #include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Core/System.h" -#include "VideoCommon/Assets/CustomResourceManager.h" #include "VideoCommon/Assets/MaterialAsset.h" #include "VideoCommon/Assets/MeshAsset.h" #include "VideoCommon/Assets/ShaderAsset.h" #include "VideoCommon/Assets/TextureAsset.h" #include "VideoCommon/Assets/TextureAssetUtils.h" #include "VideoCommon/RenderState.h" +#include "VideoCommon/Resources/CustomResourceManager.h" namespace VideoCommon { diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index 73b9221c4b52..4830c6711318 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -8,13 +8,14 @@ add_library(videocommon AbstractStagingTexture.h AbstractTexture.cpp AbstractTexture.h + Assets/AssetListener.h Assets/CustomAsset.cpp Assets/CustomAsset.h + Assets/CustomAssetCache.cpp + Assets/CustomAssetCache.h Assets/CustomAssetLibrary.h Assets/CustomAssetLoader.cpp Assets/CustomAssetLoader.h - Assets/CustomResourceManager.cpp - Assets/CustomResourceManager.h Assets/CustomTextureData.cpp Assets/CustomTextureData.h Assets/DirectFilesystemAssetLibrary.cpp @@ -145,6 +146,12 @@ add_library(videocommon Present.h RenderState.cpp RenderState.h + Resources/CustomResourceManager.cpp + Resources/CustomResourceManager.h + Resources/Resource.cpp + Resources/Resource.h + Resources/TextureDataResource.cpp + Resources/TextureDataResource.h ShaderCache.cpp ShaderCache.h ShaderCompileUtils.cpp diff --git a/Source/Core/VideoCommon/HiresTextures.cpp b/Source/Core/VideoCommon/HiresTextures.cpp index 8acc3aff039d..12f59f5ff52d 100644 --- a/Source/Core/VideoCommon/HiresTextures.cpp +++ b/Source/Core/VideoCommon/HiresTextures.cpp @@ -27,6 +27,7 @@ #include "VideoCommon/Assets/CustomAsset.h" #include "VideoCommon/Assets/DirectFilesystemAssetLibrary.h" #include "VideoCommon/OnScreenDisplay.h" +#include "VideoCommon/Resources/CustomResourceManager.h" #include "VideoCommon/VideoConfig.h" constexpr std::string_view s_format_prefix{"tex1_"}; @@ -191,7 +192,7 @@ HiresTexture::HiresTexture(bool has_arbitrary_mipmaps, std::string id) { } -VideoCommon::CustomResourceManager::TextureTimePair HiresTexture::LoadTexture() const +VideoCommon::TextureDataResource* HiresTexture::LoadTexture() const { auto& system = Core::System::GetInstance(); auto& custom_resource_manager = system.GetCustomResourceManager(); diff --git a/Source/Core/VideoCommon/HiresTextures.h b/Source/Core/VideoCommon/HiresTextures.h index e99a3fc966f7..f577aebd786e 100644 --- a/Source/Core/VideoCommon/HiresTextures.h +++ b/Source/Core/VideoCommon/HiresTextures.h @@ -8,12 +8,13 @@ #include #include -#include "Common/CommonTypes.h" -#include "VideoCommon/Assets/CustomResourceManager.h" -#include "VideoCommon/Assets/CustomTextureData.h" -#include "VideoCommon/TextureConfig.h" #include "VideoCommon/TextureInfo.h" +namespace VideoCommon +{ +class TextureDataResource; +} + enum class TextureFormat; std::set GetTextureDirectoriesWithGameId(const std::string& root_directory, @@ -30,7 +31,7 @@ class HiresTexture HiresTexture(bool has_arbitrary_mipmaps, std::string id); bool HasArbitraryMipmaps() const { return m_has_arbitrary_mipmaps; } - VideoCommon::CustomResourceManager::TextureTimePair LoadTexture() const; + VideoCommon::TextureDataResource* LoadTexture() const; const std::string& GetId() const { return m_id; } private: diff --git a/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp b/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp new file mode 100644 index 000000000000..35eeb0393aeb --- /dev/null +++ b/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp @@ -0,0 +1,124 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "VideoCommon/Resources/CustomResourceManager.h" + +#include "VideoCommon/VideoEvents.h" + +namespace VideoCommon +{ +void CustomResourceManager::Initialize() +{ + m_asset_cache.Initialize(); + + m_xfb_event = + AfterFrameEvent::Register([this](Core::System&) { XFBTriggered(); }, "CustomResourceManager"); +} + +void CustomResourceManager::Shutdown() +{ + m_asset_cache.Shutdown(); + Reset(); +} + +void CustomResourceManager::Reset() +{ + m_texture_data_resources.clear(); + + m_asset_cache.Reset(); +} + +void CustomResourceManager::MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id) +{ + m_asset_cache.MarkAssetDirty(asset_id); +} + +void CustomResourceManager::XFBTriggered() +{ + m_asset_cache.Update(); +} + +TextureDataResource* CustomResourceManager::GetTextureDataFromAsset( + const CustomAssetLibrary::AssetID& asset_id, + std::shared_ptr library) +{ + const auto [it, added] = m_texture_data_resources.try_emplace(asset_id, nullptr); + if (added) + { + it->second = std::make_unique(CreateResourceContext(asset_id, library)); + } + ProcessResource(it->second.get()); + return it->second.get(); +} + +Resource::ResourceContext CustomResourceManager::CreateResourceContext( + const CustomAssetLibrary::AssetID& asset_id, + const std::shared_ptr& library) +{ + return Resource::ResourceContext{asset_id, library, &m_asset_cache, this}; +} + +void CustomResourceManager::ProcessResource(Resource* resource) +{ + resource->MarkAsActive(); + + const auto data_processed = resource->IsDataProcessed(); + if (data_processed == Resource::TaskComplete::Yes || + data_processed == Resource::TaskComplete::Error) + { + resource->MarkAsActive(); + if (data_processed == Resource::TaskComplete::Error) + return; + } + + // Early out if we're already at our end state + if (resource->GetState() == Resource::State::DataAvailable) + return; + + ProcessResourceState(resource); +} + +void CustomResourceManager::ProcessResourceState(Resource* resource) +{ + Resource::State next_state = resource->GetState(); + Resource::TaskComplete task_complete = Resource::TaskComplete::No; + switch (resource->GetState()) + { + case Resource::State::ReloadData: + resource->ResetData(); + task_complete = Resource::TaskComplete::Yes; + next_state = Resource::State::CollectingPrimaryData; + break; + case Resource::State::CollectingPrimaryData: + task_complete = resource->CollectPrimaryData(); + next_state = Resource::State::CollectingDependencyData; + if (task_complete == Resource::TaskComplete::No) + resource->MarkAsPending(); + break; + case Resource::State::CollectingDependencyData: + task_complete = resource->CollectDependencyData(); + next_state = Resource::State::ProcessingData; + break; + case Resource::State::ProcessingData: + task_complete = resource->ProcessData(); + next_state = Resource::State::DataAvailable; + }; + + if (task_complete == Resource::TaskComplete::Yes) + { + resource->m_state = next_state; + if (next_state == Resource::State::DataAvailable) + { + resource->m_data_processed = task_complete; + } + else + { + ProcessResourceState(resource); + } + } + else if (task_complete == Resource::TaskComplete::Error) + { + resource->m_data_processed = task_complete; + } +} +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/CustomResourceManager.h b/Source/Core/VideoCommon/Resources/CustomResourceManager.h new file mode 100644 index 000000000000..512bd77712e3 --- /dev/null +++ b/Source/Core/VideoCommon/Resources/CustomResourceManager.h @@ -0,0 +1,46 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#include "Common/HookableEvent.h" + +#include "VideoCommon/Assets/CustomAssetCache.h" +#include "VideoCommon/Resources/TextureDataResource.h" + +namespace VideoCommon +{ +class CustomResourceManager +{ +public: + void Initialize(); + void Shutdown(); + + void Reset(); + + // Request that an asset be reloaded + void MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id); + + void XFBTriggered(); + + TextureDataResource* + GetTextureDataFromAsset(const CustomAssetLibrary::AssetID& asset_id, + std::shared_ptr library); + +private: + Resource::ResourceContext + CreateResourceContext(const CustomAssetLibrary::AssetID& asset_id, + const std::shared_ptr& library); + void ProcessResource(Resource* resource); + void ProcessResourceState(Resource* resource); + CustomAssetCache m_asset_cache; + + std::map> + m_texture_data_resources; + + Common::EventHook m_xfb_event; +}; +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/Resource.cpp b/Source/Core/VideoCommon/Resources/Resource.cpp new file mode 100644 index 000000000000..52d1d8b01cbc --- /dev/null +++ b/Source/Core/VideoCommon/Resources/Resource.cpp @@ -0,0 +1,81 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "VideoCommon/Resources/Resource.h" + +namespace VideoCommon +{ +Resource::Resource(ResourceContext resource_context) + : m_resource_context(std::move(resource_context)) +{ +} + +void Resource::NotifyAssetChanged(bool has_error) +{ + m_data_processed = has_error ? TaskComplete::Error : TaskComplete::No; + m_state = State::ReloadData; + + for (Resource* reference : m_references) + { + reference->NotifyAssetChanged(has_error); + } +} + +void Resource::NotifyAssetUnloaded() +{ + OnUnloadRequested(); + + for (Resource* reference : m_references) + { + reference->NotifyAssetUnloaded(); + } +} + +void Resource::AddReference(Resource* reference) +{ + m_references.insert(reference); +} + +void Resource::RemoveReference(Resource* reference) +{ + m_references.erase(reference); +} + +void Resource::NotifyAssetLoadSuccess() +{ + NotifyAssetChanged(false); +} + +void Resource::NotifyAssetLoadFailed() +{ + NotifyAssetChanged(true); +} + +void Resource::AssetUnloaded() +{ + NotifyAssetUnloaded(); +} + +void Resource::OnUnloadRequested() +{ +} + +void Resource::ResetData() +{ +} + +Resource::TaskComplete Resource::CollectPrimaryData() +{ + return TaskComplete::Yes; +} + +Resource::TaskComplete Resource::CollectDependencyData() +{ + return TaskComplete::Yes; +} + +Resource::TaskComplete Resource::ProcessData() +{ + return TaskComplete::Yes; +} +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/Resource.h b/Source/Core/VideoCommon/Resources/Resource.h new file mode 100644 index 000000000000..f9656fe2fa6c --- /dev/null +++ b/Source/Core/VideoCommon/Resources/Resource.h @@ -0,0 +1,82 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "VideoCommon/Assets/AssetListener.h" +#include "VideoCommon/Assets/CustomAssetLibrary.h" + +#include +#include + +class AbstractTexture; +namespace VideoCommon +{ +class CustomAssetCache; +class CustomResourceManager; + +// A resource is an abstract object that maintains +// relationships between assets (ex: a material that references a texture), +// as well as a standard way of calculating the final data (ex: a material's AbstractPipeline) +class Resource : public AssetListener +{ +public: + // Everything the resource needs to manage itself + struct ResourceContext + { + CustomAssetLibrary::AssetID primary_asset_id; + std::shared_ptr asset_library; + CustomAssetCache* asset_cache; + CustomResourceManager* resource_manager; + }; + explicit Resource(ResourceContext resource_context); + + enum class TaskComplete + { + Yes, + No, + Error, + }; + + enum class State + { + ReloadData, + CollectingPrimaryData, + CollectingDependencyData, + ProcessingData, + DataAvailable, + }; + + TaskComplete IsDataProcessed() const { return m_data_processed; } + State GetState() const { return m_state; } + + void AddReference(Resource* reference); + void RemoveReference(Resource* reference); + + virtual void MarkAsActive() = 0; + virtual void MarkAsPending() = 0; + +protected: + ResourceContext m_resource_context; + +private: + void NotifyAssetChanged(bool has_error); + void NotifyAssetUnloaded(); + + void NotifyAssetLoadSuccess() final; + void NotifyAssetLoadFailed() final; + void AssetUnloaded() final; + virtual void OnUnloadRequested(); + + friend class CustomResourceManager; + virtual void ResetData(); + virtual TaskComplete CollectPrimaryData(); + virtual TaskComplete CollectDependencyData(); + virtual TaskComplete ProcessData(); + + TaskComplete m_data_processed = TaskComplete::No; + State m_state = State::ReloadData; + + std::unordered_set m_references; +}; +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/TextureDataResource.cpp b/Source/Core/VideoCommon/Resources/TextureDataResource.cpp new file mode 100644 index 000000000000..d72ae8d39dcd --- /dev/null +++ b/Source/Core/VideoCommon/Resources/TextureDataResource.cpp @@ -0,0 +1,48 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "VideoCommon/Resources/TextureDataResource.h" + +#include "VideoCommon/Assets/CustomAssetCache.h" + +namespace VideoCommon +{ +TextureDataResource::TextureDataResource(Resource::ResourceContext resource_context) + : Resource(std::move(resource_context)) +{ + m_texture_asset = m_resource_context.asset_cache->CreateAsset( + m_resource_context.primary_asset_id, m_resource_context.asset_library, this); +} + +std::shared_ptr TextureDataResource::GetData() const +{ + return m_current_texture_data; +} + +CustomAsset::TimeType TextureDataResource::GetLoadTime() const +{ + return m_current_time; +} + +Resource::TaskComplete TextureDataResource::CollectPrimaryData() +{ + const auto last_load_time = m_texture_asset->GetLastLoadedTime(); + const auto asset = m_texture_asset->GetData(); + if (!asset) + return Resource::TaskComplete::No; + + m_current_texture_data = asset; + m_current_time = last_load_time; + return Resource::TaskComplete::Yes; +} + +void TextureDataResource::MarkAsActive() +{ + m_resource_context.asset_cache->MarkAssetActive(m_texture_asset); +} + +void TextureDataResource::MarkAsPending() +{ + m_resource_context.asset_cache->MarkAssetPending(m_texture_asset); +} +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/TextureDataResource.h b/Source/Core/VideoCommon/Resources/TextureDataResource.h new file mode 100644 index 000000000000..edb529d40749 --- /dev/null +++ b/Source/Core/VideoCommon/Resources/TextureDataResource.h @@ -0,0 +1,33 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "VideoCommon/Resources/Resource.h" + +#include "VideoCommon/Assets/CustomTextureData.h" +#include "VideoCommon/Assets/TextureAsset.h" + +namespace VideoCommon +{ +class TextureDataResource final : public Resource +{ +public: + explicit TextureDataResource(Resource::ResourceContext resource_context); + + std::shared_ptr GetData() const; + CustomAsset::TimeType GetLoadTime() const; + + void MarkAsActive() override; + void MarkAsPending() override; + +private: + TaskComplete CollectPrimaryData() override; + + // Note: asset cache owns the asset, we access as a reference + TextureAsset* m_texture_asset = nullptr; + + std::shared_ptr m_current_texture_data; + CustomAsset::TimeType m_current_time = {}; +}; +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index ce2742938144..6ae8b4f96f76 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -4,6 +4,7 @@ #include "VideoCommon/TextureCacheBase.h" #include +#include #include #include #include @@ -37,7 +38,6 @@ #include "VideoCommon/AbstractFramebuffer.h" #include "VideoCommon/AbstractGfx.h" #include "VideoCommon/AbstractStagingTexture.h" -#include "VideoCommon/Assets/CustomResourceManager.h" #include "VideoCommon/Assets/CustomTextureData.h" #include "VideoCommon/Assets/TextureAssetUtils.h" #include "VideoCommon/BPMemory.h" @@ -48,6 +48,7 @@ #include "VideoCommon/OpcodeDecoding.h" #include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/Present.h" +#include "VideoCommon/Resources/CustomResourceManager.h" #include "VideoCommon/ShaderCache.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/TMEM.h" @@ -266,9 +267,9 @@ bool TextureCacheBase::DidLinkedAssetsChange(const TCacheEntry& entry) if (!entry.hires_texture) return false; - const auto [texture_data, load_time] = entry.hires_texture->LoadTexture(); + const auto* resource = entry.hires_texture->LoadTexture(); - return load_time > entry.last_load_time; + return resource->GetLoadTime() > entry.last_load_time; } RcTcacheEntry TextureCacheBase::ApplyPaletteToEntry(RcTcacheEntry& entry, const u8* palette, @@ -1569,7 +1570,9 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp if (hires_texture) { has_arbitrary_mipmaps = hires_texture->HasArbitraryMipmaps(); - std::tie(custom_texture_data, load_time) = hires_texture->LoadTexture(); + const auto resource = hires_texture->LoadTexture(); + load_time = resource->GetLoadTime(); + custom_texture_data = resource->GetData(); if (custom_texture_data && !VideoCommon::ValidateTextureData( hires_texture->GetId(), *custom_texture_data, texture_info.GetRawWidth(), texture_info.GetRawHeight())) diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp index 23d9d6e7f42a..7eeefb718782 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/VideoBackendBase.cpp @@ -43,7 +43,6 @@ #endif #include "VideoCommon/AbstractGfx.h" -#include "VideoCommon/Assets/CustomResourceManager.h" #include "VideoCommon/AsyncRequests.h" #include "VideoCommon/BPStructs.h" #include "VideoCommon/BoundingBox.h" @@ -59,6 +58,7 @@ #include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/Present.h" +#include "VideoCommon/Resources/CustomResourceManager.h" #include "VideoCommon/TMEM.h" #include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/VertexLoaderManager.h" From 989ecca23539cc6714daad3625445e30cd3b153a Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sun, 2 Nov 2025 14:39:33 -0600 Subject: [PATCH 034/267] VideoCommon: add a texture pool for resource management --- Source/Core/DolphinLib.props | 2 + Source/Core/VideoCommon/CMakeLists.txt | 2 + .../VideoCommon/Resources/TexturePool.cpp | 43 +++++++++++++++++++ .../Core/VideoCommon/Resources/TexturePool.h | 25 +++++++++++ 4 files changed, 72 insertions(+) create mode 100644 Source/Core/VideoCommon/Resources/TexturePool.cpp create mode 100644 Source/Core/VideoCommon/Resources/TexturePool.h diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index e8ca03d4bdfb..0ce79918aa57 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -756,6 +756,7 @@ + @@ -1409,6 +1410,7 @@ + diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index 4830c6711318..1b0906ca198c 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -152,6 +152,8 @@ add_library(videocommon Resources/Resource.h Resources/TextureDataResource.cpp Resources/TextureDataResource.h + Resources/TexturePool.cpp + Resources/TexturePool.h ShaderCache.cpp ShaderCache.h ShaderCompileUtils.cpp diff --git a/Source/Core/VideoCommon/Resources/TexturePool.cpp b/Source/Core/VideoCommon/Resources/TexturePool.cpp new file mode 100644 index 000000000000..ce76dc5b24bf --- /dev/null +++ b/Source/Core/VideoCommon/Resources/TexturePool.cpp @@ -0,0 +1,43 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "VideoCommon/Resources/TexturePool.h" + +#include "Common/Logging/Log.h" + +#include "VideoCommon/AbstractGfx.h" +#include "VideoCommon/AbstractTexture.h" + +namespace VideoCommon +{ +void TexturePool::Reset() +{ + m_cache.clear(); +} + +std::unique_ptr TexturePool::AllocateTexture(const TextureConfig& config) +{ + const auto iter = m_cache.find(config); + if (iter != m_cache.end()) + { + auto entry = std::move(iter->second); + m_cache.erase(iter); + return entry; + } + + std::unique_ptr texture = g_gfx->CreateTexture(config); + if (!texture) + { + ERROR_LOG_FMT(VIDEO, "Failed to allocate a {}x{}x{} texture", config.width, config.height, + config.layers); + return {}; + } + return texture; +} + +void TexturePool::ReleaseTexture(std::unique_ptr texture) +{ + auto config = texture->GetConfig(); + (void)m_cache.emplace(config, std::move(texture)); +} +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/TexturePool.h b/Source/Core/VideoCommon/Resources/TexturePool.h new file mode 100644 index 000000000000..6040a3ae760e --- /dev/null +++ b/Source/Core/VideoCommon/Resources/TexturePool.h @@ -0,0 +1,25 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#include "VideoCommon/AbstractTexture.h" +#include "VideoCommon/TextureConfig.h" + +namespace VideoCommon +{ +class TexturePool +{ +public: + void Reset(); + + std::unique_ptr AllocateTexture(const TextureConfig& config); + void ReleaseTexture(std::unique_ptr texture); + +private: + std::unordered_multimap> m_cache; +}; +} // namespace VideoCommon From 8016e2cfbd9b6cc5d9e59cb95c35c9ef1259044b Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sun, 2 Nov 2025 14:47:32 -0600 Subject: [PATCH 035/267] VideoCommon: move ApplyDriverBugs for the normal pipeline out into a utility function, add a way to hash the pipeline (using the vertex declaration instead of the native vertex format) --- Source/Core/DolphinLib.props | 2 + Source/Core/VideoCommon/CMakeLists.txt | 2 + Source/Core/VideoCommon/PipelineUtils.cpp | 172 ++++++++++++++++++++++ Source/Core/VideoCommon/PipelineUtils.h | 22 +++ Source/Core/VideoCommon/ShaderCache.cpp | 134 +---------------- 5 files changed, 200 insertions(+), 132 deletions(-) create mode 100644 Source/Core/VideoCommon/PipelineUtils.cpp create mode 100644 Source/Core/VideoCommon/PipelineUtils.h diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 0ce79918aa57..13e9ff7a0c94 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -747,6 +747,7 @@ + @@ -1401,6 +1402,7 @@ + diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index 1b0906ca198c..1a81b1a5f7ff 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -134,6 +134,8 @@ add_library(videocommon PerformanceMetrics.h PerformanceTracker.cpp PerformanceTracker.h + PipelineUtils.cpp + PipelineUtils.h PixelEngine.cpp PixelEngine.h PixelShaderGen.cpp diff --git a/Source/Core/VideoCommon/PipelineUtils.cpp b/Source/Core/VideoCommon/PipelineUtils.cpp new file mode 100644 index 000000000000..a63f7f00e822 --- /dev/null +++ b/Source/Core/VideoCommon/PipelineUtils.cpp @@ -0,0 +1,172 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "VideoCommon/PipelineUtils.h" + +#include "Common/Assert.h" +#include "Common/Logging/Log.h" + +#include "VideoCommon/BPMemory.h" +#include "VideoCommon/ConstantManager.h" +#include "VideoCommon/DriverDetails.h" +#include "VideoCommon/GeometryShaderGen.h" +#include "VideoCommon/PixelShaderGen.h" +#include "VideoCommon/RenderState.h" +#include "VideoCommon/ShaderGenCommon.h" +#include "VideoCommon/VertexShaderGen.h" +#include "VideoCommon/VideoConfig.h" + +namespace VideoCommon +{ +/// Edits the UID based on driver bugs and other special configurations +GXPipelineUid ApplyDriverBugs(const GXPipelineUid& in) +{ + GXPipelineUid out; + // TODO: static_assert(std::is_trivially_copyable_v); + // GXPipelineUid is not trivially copyable because RasterizationState and BlendingState aren't + // either, but we can pretend it is for now. This will be improved after PR #10848 is finished. + memcpy(static_cast(&out), static_cast(&in), sizeof(out)); // copy padding + pixel_shader_uid_data* ps = out.ps_uid.GetUidData(); + BlendingState& blend = out.blending_state; + + if (ps->ztest == EmulatedZ::ForcedEarly && !out.depth_state.update_enable) + { + // No need to force early depth test if you're not writing z + ps->ztest = EmulatedZ::Early; + } + + // If framebuffer fetch is available, we can emulate logic ops in the fragment shader + // and don't need the below blend approximation + if (blend.logic_op_enable && !g_backend_info.bSupportsLogicOp && + !g_backend_info.bSupportsFramebufferFetch) + { + if (!blend.LogicOpApproximationIsExact()) + WARN_LOG_FMT(VIDEO, + "Approximating logic op with blending, this will produce incorrect rendering."); + if (blend.LogicOpApproximationWantsShaderHelp()) + { + ps->emulate_logic_op_with_blend = true; + ps->logic_op_mode = static_cast(blend.logic_mode.Value()); + } + blend.ApproximateLogicOpWithBlending(); + } + + const bool benefits_from_ps_dual_source_off = + (!g_backend_info.bSupportsDualSourceBlend && g_backend_info.bSupportsFramebufferFetch) || + DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DUAL_SOURCE_BLENDING); + if (benefits_from_ps_dual_source_off && !blend.RequiresDualSrc()) + { + // Only use dual-source blending when required on drivers that don't support it very well. + ps->no_dual_src = true; + blend.use_dual_src = false; + } + + if (g_backend_info.bSupportsFramebufferFetch) + { + bool fbfetch_blend = false; + if ((DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DISCARD_WITH_EARLY_Z) || + !g_backend_info.bSupportsEarlyZ) && + ps->ztest == EmulatedZ::ForcedEarly) + { + ps->ztest = EmulatedZ::EarlyWithFBFetch; + fbfetch_blend |= static_cast(out.blending_state.blend_enable); + ps->no_dual_src = true; + } + fbfetch_blend |= blend.logic_op_enable && !g_backend_info.bSupportsLogicOp; + fbfetch_blend |= blend.use_dual_src && !g_backend_info.bSupportsDualSourceBlend; + if (fbfetch_blend) + { + ps->no_dual_src = true; + if (blend.logic_op_enable) + { + ps->logic_op_enable = true; + ps->logic_op_mode = static_cast(blend.logic_mode.Value()); + blend.logic_op_enable = false; + } + if (blend.blend_enable) + { + ps->blend_enable = true; + ps->blend_src_factor = blend.src_factor; + ps->blend_src_factor_alpha = blend.src_factor_alpha; + ps->blend_dst_factor = blend.dst_factor; + ps->blend_dst_factor_alpha = blend.dst_factor_alpha; + ps->blend_subtract = blend.subtract; + ps->blend_subtract_alpha = blend.subtract_alpha; + blend.blend_enable = false; + } + } + } + + // force dual src off if we can't support it + if (!g_backend_info.bSupportsDualSourceBlend) + { + ps->no_dual_src = true; + blend.use_dual_src = false; + } + + if (ps->ztest == EmulatedZ::ForcedEarly && !g_backend_info.bSupportsEarlyZ) + { + // These things should be false + ASSERT(!ps->zfreeze); + // ZCOMPLOC HACK: + // The only way to emulate alpha test + early-z is to force early-z in the shader. + // As this isn't available on all drivers and as we can't emulate this feature otherwise, + // we are only able to choose which one we want to respect more. + // Tests seem to have proven that writing depth even when the alpha test fails is more + // important that a reliable alpha test, so we just force the alpha test to always succeed. + // At least this seems to be less buggy. + ps->ztest = EmulatedZ::EarlyWithZComplocHack; + } + + if (g_ActiveConfig.UseVSForLinePointExpand() && + (out.rasterization_state.primitive == PrimitiveType::Points || + out.rasterization_state.primitive == PrimitiveType::Lines)) + { + // All primitives are expanded to triangles in the vertex shader + vertex_shader_uid_data* vs = out.vs_uid.GetUidData(); + const PortableVertexDeclaration& decl = out.vertex_format->GetVertexDeclaration(); + vs->position_has_3_elems = decl.position.components >= 3; + vs->texcoord_elem_count = 0; + for (int i = 0; i < 8; i++) + { + if (decl.texcoords[i].enable) + { + ASSERT(decl.texcoords[i].components <= 3); + vs->texcoord_elem_count |= decl.texcoords[i].components << (i * 2); + } + } + out.vertex_format = nullptr; + if (out.rasterization_state.primitive == PrimitiveType::Points) + vs->vs_expand = VSExpand::Point; + else + vs->vs_expand = VSExpand::Line; + PrimitiveType prim = g_backend_info.bSupportsPrimitiveRestart ? PrimitiveType::TriangleStrip : + PrimitiveType::Triangles; + out.rasterization_state.primitive = prim; + out.gs_uid.GetUidData()->primitive_type = static_cast(prim); + } + + return out; +} + +std::size_t PipelineToHash(const GXPipelineUid& in) +{ + XXH3_state_t pipeline_hash_state; + XXH3_INITSTATE(&pipeline_hash_state); + XXH3_64bits_reset_withSeed(&pipeline_hash_state, static_cast(1)); + UpdateHashWithPipeline(in, &pipeline_hash_state); + return XXH3_64bits_digest(&pipeline_hash_state); +} + +void UpdateHashWithPipeline(const GXPipelineUid& in, XXH3_state_t* hash_state) +{ + XXH3_64bits_update(hash_state, &in.vertex_format->GetVertexDeclaration(), + sizeof(PortableVertexDeclaration)); + XXH3_64bits_update(hash_state, &in.blending_state, sizeof(BlendingState)); + XXH3_64bits_update(hash_state, &in.depth_state, sizeof(DepthState)); + XXH3_64bits_update(hash_state, &in.rasterization_state, sizeof(RasterizationState)); + XXH3_64bits_update(hash_state, &in.gs_uid, sizeof(GeometryShaderUid)); + XXH3_64bits_update(hash_state, &in.ps_uid, sizeof(PixelShaderUid)); + XXH3_64bits_update(hash_state, &in.vs_uid, sizeof(VertexShaderUid)); +} +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/PipelineUtils.h b/Source/Core/VideoCommon/PipelineUtils.h new file mode 100644 index 000000000000..4a9b7b169609 --- /dev/null +++ b/Source/Core/VideoCommon/PipelineUtils.h @@ -0,0 +1,22 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "VideoCommon/GXPipelineTypes.h" + +namespace VideoCommon +{ +GXPipelineUid ApplyDriverBugs(const GXPipelineUid& in); + +// Returns a hash of the pipeline, hashing the +// vertex declarations instead of the native vertex format +// object +std::size_t PipelineToHash(const GXPipelineUid& in); + +// Updates an existing hash with the hash of the pipeline +void UpdateHashWithPipeline(const GXPipelineUid& in, XXH3_state_t* hash_state); + +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/ShaderCache.cpp b/Source/Core/VideoCommon/ShaderCache.cpp index a3d07368f605..e67a23a78548 100644 --- a/Source/Core/VideoCommon/ShaderCache.cpp +++ b/Source/Core/VideoCommon/ShaderCache.cpp @@ -15,6 +15,7 @@ #include "VideoCommon/DriverDetails.h" #include "VideoCommon/FramebufferManager.h" #include "VideoCommon/FramebufferShaderGen.h" +#include "VideoCommon/PipelineUtils.h" #include "VideoCommon/Present.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/VertexLoaderManager.h" @@ -604,141 +605,10 @@ AbstractPipelineConfig ShaderCache::GetGXPipelineConfig( return config; } -/// Edits the UID based on driver bugs and other special configurations -static GXPipelineUid ApplyDriverBugs(const GXPipelineUid& in) -{ - GXPipelineUid out; - // TODO: static_assert(std::is_trivially_copyable_v); - // GXPipelineUid is not trivially copyable because RasterizationState and BlendingState aren't - // either, but we can pretend it is for now. This will be improved after PR #10848 is finished. - memcpy(static_cast(&out), static_cast(&in), sizeof(out)); // copy padding - pixel_shader_uid_data* ps = out.ps_uid.GetUidData(); - BlendingState& blend = out.blending_state; - - if (ps->ztest == EmulatedZ::ForcedEarly && !out.depth_state.update_enable) - { - // No need to force early depth test if you're not writing z - ps->ztest = EmulatedZ::Early; - } - - // If framebuffer fetch is available, we can emulate logic ops in the fragment shader - // and don't need the below blend approximation - if (blend.logic_op_enable && !g_backend_info.bSupportsLogicOp && - !g_backend_info.bSupportsFramebufferFetch) - { - if (!blend.LogicOpApproximationIsExact()) - WARN_LOG_FMT(VIDEO, - "Approximating logic op with blending, this will produce incorrect rendering."); - if (blend.LogicOpApproximationWantsShaderHelp()) - { - ps->emulate_logic_op_with_blend = true; - ps->logic_op_mode = static_cast(blend.logic_mode.Value()); - } - blend.ApproximateLogicOpWithBlending(); - } - - const bool benefits_from_ps_dual_source_off = - (!g_backend_info.bSupportsDualSourceBlend && g_backend_info.bSupportsFramebufferFetch) || - DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DUAL_SOURCE_BLENDING); - if (benefits_from_ps_dual_source_off && !blend.RequiresDualSrc()) - { - // Only use dual-source blending when required on drivers that don't support it very well. - ps->no_dual_src = true; - blend.use_dual_src = false; - } - - if (g_backend_info.bSupportsFramebufferFetch) - { - bool fbfetch_blend = false; - if ((DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DISCARD_WITH_EARLY_Z) || - !g_backend_info.bSupportsEarlyZ) && - ps->ztest == EmulatedZ::ForcedEarly) - { - ps->ztest = EmulatedZ::EarlyWithFBFetch; - fbfetch_blend |= static_cast(out.blending_state.blend_enable); - ps->no_dual_src = true; - } - fbfetch_blend |= blend.logic_op_enable && !g_backend_info.bSupportsLogicOp; - fbfetch_blend |= blend.use_dual_src && !g_backend_info.bSupportsDualSourceBlend; - if (fbfetch_blend) - { - ps->no_dual_src = true; - if (blend.logic_op_enable) - { - ps->logic_op_enable = true; - ps->logic_op_mode = static_cast(blend.logic_mode.Value()); - blend.logic_op_enable = false; - } - if (blend.blend_enable) - { - ps->blend_enable = true; - ps->blend_src_factor = blend.src_factor; - ps->blend_src_factor_alpha = blend.src_factor_alpha; - ps->blend_dst_factor = blend.dst_factor; - ps->blend_dst_factor_alpha = blend.dst_factor_alpha; - ps->blend_subtract = blend.subtract; - ps->blend_subtract_alpha = blend.subtract_alpha; - blend.blend_enable = false; - } - } - } - - // force dual src off if we can't support it - if (!g_backend_info.bSupportsDualSourceBlend) - { - ps->no_dual_src = true; - blend.use_dual_src = false; - } - - if (ps->ztest == EmulatedZ::ForcedEarly && !g_backend_info.bSupportsEarlyZ) - { - // These things should be false - ASSERT(!ps->zfreeze); - // ZCOMPLOC HACK: - // The only way to emulate alpha test + early-z is to force early-z in the shader. - // As this isn't available on all drivers and as we can't emulate this feature otherwise, - // we are only able to choose which one we want to respect more. - // Tests seem to have proven that writing depth even when the alpha test fails is more - // important that a reliable alpha test, so we just force the alpha test to always succeed. - // At least this seems to be less buggy. - ps->ztest = EmulatedZ::EarlyWithZComplocHack; - } - - if (g_ActiveConfig.UseVSForLinePointExpand() && - (out.rasterization_state.primitive == PrimitiveType::Points || - out.rasterization_state.primitive == PrimitiveType::Lines)) - { - // All primitives are expanded to triangles in the vertex shader - vertex_shader_uid_data* vs = out.vs_uid.GetUidData(); - const PortableVertexDeclaration& decl = out.vertex_format->GetVertexDeclaration(); - vs->position_has_3_elems = decl.position.components >= 3; - vs->texcoord_elem_count = 0; - for (int i = 0; i < 8; i++) - { - if (decl.texcoords[i].enable) - { - ASSERT(decl.texcoords[i].components <= 3); - vs->texcoord_elem_count |= decl.texcoords[i].components << (i * 2); - } - } - out.vertex_format = nullptr; - if (out.rasterization_state.primitive == PrimitiveType::Points) - vs->vs_expand = VSExpand::Point; - else - vs->vs_expand = VSExpand::Line; - PrimitiveType prim = g_backend_info.bSupportsPrimitiveRestart ? PrimitiveType::TriangleStrip : - PrimitiveType::Triangles; - out.rasterization_state.primitive = prim; - out.gs_uid.GetUidData()->primitive_type = static_cast(prim); - } - - return out; -} - std::optional ShaderCache::GetGXPipelineConfig(const GXPipelineUid& config_in) { - GXPipelineUid config = ApplyDriverBugs(config_in); + GXPipelineUid config = VideoCommon::ApplyDriverBugs(config_in); const AbstractShader* vs; auto vs_iter = m_vs_cache.shader_map.find(config.vs_uid); if (vs_iter != m_vs_cache.shader_map.end() && !vs_iter->second.pending) From 93a6cc80b4b41c73510b0250251df981b079bc3a Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sun, 2 Nov 2025 14:54:53 -0600 Subject: [PATCH 036/267] VideoCommon: add some helper functions for resource logic that generates invalid textures for when a texture isn't provided for a custom asset --- Source/Core/DolphinLib.props | 2 + Source/Core/VideoCommon/CMakeLists.txt | 2 + .../VideoCommon/Resources/InvalidTextures.cpp | 58 +++++++++++++++++++ .../VideoCommon/Resources/InvalidTextures.h | 16 +++++ 4 files changed, 78 insertions(+) create mode 100644 Source/Core/VideoCommon/Resources/InvalidTextures.cpp create mode 100644 Source/Core/VideoCommon/Resources/InvalidTextures.h diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 13e9ff7a0c94..9737ceeac8c1 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -755,6 +755,7 @@ + @@ -1410,6 +1411,7 @@ + diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index 1a81b1a5f7ff..d3b68ba95cc5 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -150,6 +150,8 @@ add_library(videocommon RenderState.h Resources/CustomResourceManager.cpp Resources/CustomResourceManager.h + Resources/InvalidTextures.cpp + Resources/InvalidTextures.h Resources/Resource.cpp Resources/Resource.h Resources/TextureDataResource.cpp diff --git a/Source/Core/VideoCommon/Resources/InvalidTextures.cpp b/Source/Core/VideoCommon/Resources/InvalidTextures.cpp new file mode 100644 index 000000000000..b27630660e93 --- /dev/null +++ b/Source/Core/VideoCommon/Resources/InvalidTextures.cpp @@ -0,0 +1,58 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "VideoCommon/Resources/InvalidTextures.h" + +#include "VideoCommon/AbstractGfx.h" +#include "VideoCommon/TextureConfig.h" + +namespace VideoCommon +{ +std::unique_ptr CreateInvalidTransparentTexture() +{ + const TextureConfig tex_config{ + 1, 1, 1, 1, 1, AbstractTextureFormat::RGBA8, 0, AbstractTextureType::Texture_2D}; + auto texture = g_gfx->CreateTexture(tex_config, "Invalid Transparent Texture"); + const std::array pixel{0, 0, 0, 0}; + texture->Load(0, 1, 1, 1, pixel.data(), pixel.size()); + return texture; +} + +std::unique_ptr CreateInvalidColorTexture() +{ + const TextureConfig tex_config{ + 1, 1, 1, 1, 1, AbstractTextureFormat::RGBA8, 0, AbstractTextureType::Texture_2D}; + auto texture = g_gfx->CreateTexture(tex_config, "Invalid Color Texture"); + const std::array pixel{255, 0, 255, 255}; + texture->Load(0, 1, 1, 1, pixel.data(), pixel.size()); + return texture; +} + +std::unique_ptr CreateInvalidCubemapTexture() +{ +#ifdef __APPLE__ + // TODO: figure out cube map oddness on Apple (specifically Metal) + return nullptr; +#else + const TextureConfig tex_config{ + 1, 1, 1, 6, 1, AbstractTextureFormat::RGBA8, 0, AbstractTextureType::Texture_CubeMap}; + auto texture = g_gfx->CreateTexture(tex_config, "Invalid Cubemap Texture"); + const std::array pixel{255, 0, 255, 255}; + for (u32 i = 0; i < tex_config.layers; i++) + { + texture->Load(0, tex_config.width, tex_config.height, 1, pixel.data(), pixel.size(), i); + } + return texture; +#endif +} + +std::unique_ptr CreateInvalidArrayTexture() +{ + const TextureConfig tex_config{ + 1, 1, 1, 1, 1, AbstractTextureFormat::RGBA8, 0, AbstractTextureType::Texture_2DArray}; + auto texture = g_gfx->CreateTexture(tex_config, "Invalid Array Texture"); + const std::array pixel{255, 0, 255, 255}; + texture->Load(0, 1, 1, 1, pixel.data(), pixel.size()); + return texture; +} +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/InvalidTextures.h b/Source/Core/VideoCommon/Resources/InvalidTextures.h new file mode 100644 index 000000000000..532f7e010265 --- /dev/null +++ b/Source/Core/VideoCommon/Resources/InvalidTextures.h @@ -0,0 +1,16 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "VideoCommon/AbstractTexture.h" + +namespace VideoCommon +{ +std::unique_ptr CreateInvalidTransparentTexture(); +std::unique_ptr CreateInvalidColorTexture(); +std::unique_ptr CreateInvalidCubemapTexture(); +std::unique_ptr CreateInvalidArrayTexture(); +} // namespace VideoCommon From 23c637c029d8827363d7dd68bd40b8a6b6f041cc Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sun, 2 Nov 2025 15:12:02 -0600 Subject: [PATCH 037/267] VideoCommon: add custom includer to custom shaders, this will allow us to ship built-in custom shaders in the future --- .../Assets/DirectFilesystemAssetLibrary.cpp | 7 +++++++ Source/Core/VideoCommon/Assets/ShaderAsset.h | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp b/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp index 91f3102c58da..1945ca0aa704 100644 --- a/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp +++ b/Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp @@ -8,6 +8,7 @@ #include +#include "Common/CommonPaths.h" #include "Common/FileUtil.h" #include "Common/IOFile.h" #include "Common/JsonUtil.h" @@ -150,6 +151,12 @@ DirectFilesystemAssetLibrary::LoadRasterSurfaceShader(const AssetID& asset_id, if (!RasterSurfaceShaderData::FromJson(asset_id, root_obj, data)) return {}; + const std::string graphics_mod_builtin = + File::GetSysDirectory() + GRAPHICSMOD_DIR + "/Builtin" + "/Shaders"; + + data->shader_includer = std::make_unique( + PathToString(pixel_shader->second.parent_path()), graphics_mod_builtin); + return LoadInfo{approx_mem_size}; } diff --git a/Source/Core/VideoCommon/Assets/ShaderAsset.h b/Source/Core/VideoCommon/Assets/ShaderAsset.h index 81631fa0b34c..0204f65bb39f 100644 --- a/Source/Core/VideoCommon/Assets/ShaderAsset.h +++ b/Source/Core/VideoCommon/Assets/ShaderAsset.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include "VideoCommon/Assets/CustomAsset.h" +#include "VideoCommon/ShaderCompileUtils.h" #include "VideoCommon/TextureConfig.h" class ShaderCode; @@ -45,6 +47,13 @@ struct ShaderProperty struct RasterSurfaceShaderData { + RasterSurfaceShaderData() = default; + RasterSurfaceShaderData(const RasterSurfaceShaderData&) = delete; + RasterSurfaceShaderData(RasterSurfaceShaderData&&) = default; + ~RasterSurfaceShaderData() = default; + RasterSurfaceShaderData& operator=(const RasterSurfaceShaderData&) = delete; + RasterSurfaceShaderData& operator=(RasterSurfaceShaderData&&) = default; + static bool FromJson(const CustomAssetLibrary::AssetID& asset_id, const picojson::object& json, RasterSurfaceShaderData* data); static void ToJson(picojson::object& obj, const RasterSurfaceShaderData& data); @@ -65,6 +74,8 @@ struct RasterSurfaceShaderData bool operator==(const SamplerData&) const = default; }; std::vector samplers; + + std::unique_ptr shader_includer; }; class RasterSurfaceShaderAsset final : public CustomLoadableAsset From 5c00f0707442d41158207b802b26a008b0c61356 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sun, 2 Nov 2025 15:14:14 -0600 Subject: [PATCH 038/267] VideoCommon: update resource manager with a material/shader/and texture(+sampler) resource to show the complexities that warrant the resource manager system --- Source/Core/DolphinLib.props | 6 + Source/Core/VideoCommon/CMakeLists.txt | 6 + .../Resources/CustomResourceManager.cpp | 137 ++++++- .../Resources/CustomResourceManager.h | 40 +- .../Resources/MaterialResource.cpp | 385 ++++++++++++++++++ .../VideoCommon/Resources/MaterialResource.h | 99 +++++ Source/Core/VideoCommon/Resources/Resource.h | 11 + .../VideoCommon/Resources/ShaderResource.cpp | 311 ++++++++++++++ .../VideoCommon/Resources/ShaderResource.h | 67 +++ .../Resources/TextureAndSamplerResource.cpp | 103 +++++ .../Resources/TextureAndSamplerResource.h | 49 +++ 11 files changed, 1199 insertions(+), 15 deletions(-) create mode 100644 Source/Core/VideoCommon/Resources/MaterialResource.cpp create mode 100644 Source/Core/VideoCommon/Resources/MaterialResource.h create mode 100644 Source/Core/VideoCommon/Resources/ShaderResource.cpp create mode 100644 Source/Core/VideoCommon/Resources/ShaderResource.h create mode 100644 Source/Core/VideoCommon/Resources/TextureAndSamplerResource.cpp create mode 100644 Source/Core/VideoCommon/Resources/TextureAndSamplerResource.h diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 9737ceeac8c1..8d59805dee90 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -756,7 +756,10 @@ + + + @@ -1412,7 +1415,10 @@ + + + diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index d3b68ba95cc5..69a0968e4d88 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -152,8 +152,14 @@ add_library(videocommon Resources/CustomResourceManager.h Resources/InvalidTextures.cpp Resources/InvalidTextures.h + Resources/MaterialResource.cpp + Resources/MaterialResource.h Resources/Resource.cpp Resources/Resource.h + Resources/ShaderResource.cpp + Resources/ShaderResource.h + Resources/TextureAndSamplerResource.cpp + Resources/TextureAndSamplerResource.h Resources/TextureDataResource.cpp Resources/TextureDataResource.h Resources/TexturePool.cpp diff --git a/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp b/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp index 35eeb0393aeb..8148ccd899d7 100644 --- a/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp +++ b/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp @@ -3,6 +3,11 @@ #include "VideoCommon/Resources/CustomResourceManager.h" +#include "Common/Logging/Log.h" + +#include "VideoCommon/AbstractGfx.h" +#include "VideoCommon/PipelineUtils.h" +#include "VideoCommon/Resources/InvalidTextures.h" #include "VideoCommon/VideoEvents.h" namespace VideoCommon @@ -10,22 +15,46 @@ namespace VideoCommon void CustomResourceManager::Initialize() { m_asset_cache.Initialize(); + m_worker_thread.Reset("resource-worker"); + m_host_config.bits = ShaderHostConfig::GetCurrent().bits; + m_async_shader_compiler = g_gfx->CreateAsyncShaderCompiler(); + + m_async_shader_compiler->StartWorkerThreads(1); // TODO expose to config m_xfb_event = - AfterFrameEvent::Register([this](Core::System&) { XFBTriggered(); }, "CustomResourceManager"); + GetVideoEvents().after_frame_event.Register([this](Core::System&) { XFBTriggered(); }); + + m_invalid_array_texture = CreateInvalidArrayTexture(); + m_invalid_color_texture = CreateInvalidColorTexture(); + m_invalid_cubemap_texture = CreateInvalidCubemapTexture(); + m_invalid_transparent_texture = CreateInvalidTransparentTexture(); } void CustomResourceManager::Shutdown() { + if (m_async_shader_compiler) + m_async_shader_compiler->StopWorkerThreads(); + m_asset_cache.Shutdown(); + m_worker_thread.Shutdown(); Reset(); } void CustomResourceManager::Reset() { + m_material_resources.clear(); + m_shader_resources.clear(); m_texture_data_resources.clear(); + m_texture_sampler_resources.clear(); + + m_invalid_transparent_texture.reset(); + m_invalid_color_texture.reset(); + m_invalid_cubemap_texture.reset(); + m_invalid_array_texture.reset(); m_asset_cache.Reset(); + m_texture_pool.Reset(); + m_worker_thread.Reset("resource-worker"); } void CustomResourceManager::MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id) @@ -38,24 +67,99 @@ void CustomResourceManager::XFBTriggered() m_asset_cache.Update(); } +void CustomResourceManager::SetHostConfig(const ShaderHostConfig& host_config) +{ + for (auto& [id, shader_resources] : m_shader_resources) + { + for (auto& [key, shader_resource] : shader_resources) + { + shader_resource->SetHostConfig(host_config); + + // Hack to get access to resource internals + Resource* resource = shader_resource.get(); + + // Tell shader and references to trigger a reload + // on next usage + resource->NotifyAssetChanged(false); + } + } + + m_host_config.bits = host_config.bits; +} + TextureDataResource* CustomResourceManager::GetTextureDataFromAsset( const CustomAssetLibrary::AssetID& asset_id, std::shared_ptr library) { - const auto [it, added] = m_texture_data_resources.try_emplace(asset_id, nullptr); - if (added) + auto& resource = m_texture_data_resources[asset_id]; + if (resource == nullptr) { - it->second = std::make_unique(CreateResourceContext(asset_id, library)); + resource = + std::make_unique(CreateResourceContext(asset_id, std::move(library))); } - ProcessResource(it->second.get()); - return it->second.get(); + ProcessResource(resource.get()); + return resource.get(); +} + +MaterialResource* CustomResourceManager::GetMaterialFromAsset( + const CustomAssetLibrary::AssetID& asset_id, const GXPipelineUid& pipeline_uid, + std::shared_ptr library) +{ + auto& resource = m_material_resources[asset_id][PipelineToHash(pipeline_uid)]; + if (resource == nullptr) + { + resource = std::make_unique( + CreateResourceContext(asset_id, std::move(library)), pipeline_uid); + } + ProcessResource(resource.get()); + return resource.get(); +} + +ShaderResource* +CustomResourceManager::GetShaderFromAsset(const CustomAssetLibrary::AssetID& asset_id, + std::size_t shader_key, const GXPipelineUid& pipeline_uid, + const std::string& preprocessor_settings, + std::shared_ptr library) +{ + auto& resource = m_shader_resources[asset_id][shader_key]; + if (resource == nullptr) + { + resource = std::make_unique(CreateResourceContext(asset_id, std::move(library)), + pipeline_uid, preprocessor_settings, m_host_config); + } + ProcessResource(resource.get()); + return resource.get(); +} + +TextureAndSamplerResource* CustomResourceManager::GetTextureAndSamplerFromAsset( + const CustomAssetLibrary::AssetID& asset_id, + std::shared_ptr library) +{ + auto& resource = m_texture_sampler_resources[asset_id]; + if (resource == nullptr) + { + resource = std::make_unique( + CreateResourceContext(asset_id, std::move(library))); + } + ProcessResource(resource.get()); + return resource.get(); } Resource::ResourceContext CustomResourceManager::CreateResourceContext( const CustomAssetLibrary::AssetID& asset_id, - const std::shared_ptr& library) + std::shared_ptr library) { - return Resource::ResourceContext{asset_id, library, &m_asset_cache, this}; + return Resource::ResourceContext{asset_id, + std::move(library), + &m_asset_cache, + this, + &m_texture_pool, + &m_worker_thread, + m_async_shader_compiler.get(), + m_invalid_array_texture.get(), + m_invalid_color_texture.get(), + m_invalid_cubemap_texture.get(), + m_invalid_transparent_texture.get()}; } void CustomResourceManager::ProcessResource(Resource* resource) @@ -71,18 +175,15 @@ void CustomResourceManager::ProcessResource(Resource* resource) return; } - // Early out if we're already at our end state - if (resource->GetState() == Resource::State::DataAvailable) - return; - ProcessResourceState(resource); } void CustomResourceManager::ProcessResourceState(Resource* resource) { - Resource::State next_state = resource->GetState(); + const auto current_state = resource->GetState(); + Resource::State next_state = current_state; Resource::TaskComplete task_complete = Resource::TaskComplete::No; - switch (resource->GetState()) + switch (current_state) { case Resource::State::ReloadData: resource->ResetData(); @@ -102,6 +203,14 @@ void CustomResourceManager::ProcessResourceState(Resource* resource) case Resource::State::ProcessingData: task_complete = resource->ProcessData(); next_state = Resource::State::DataAvailable; + break; + case Resource::State::DataAvailable: + // Early out, we're already at our end state + return; + default: + ERROR_LOG_FMT(VIDEO, "Unknown resource state '{}' for resource '{}'", + static_cast(current_state), resource->m_resource_context.primary_asset_id); + return; }; if (task_complete == Resource::TaskComplete::Yes) diff --git a/Source/Core/VideoCommon/Resources/CustomResourceManager.h b/Source/Core/VideoCommon/Resources/CustomResourceManager.h index 512bd77712e3..538bec13f1c9 100644 --- a/Source/Core/VideoCommon/Resources/CustomResourceManager.h +++ b/Source/Core/VideoCommon/Resources/CustomResourceManager.h @@ -7,9 +7,16 @@ #include #include "Common/HookableEvent.h" +#include "Common/WorkQueueThread.h" +#include "VideoCommon/AbstractTexture.h" #include "VideoCommon/Assets/CustomAssetCache.h" +#include "VideoCommon/AsyncShaderCompiler.h" +#include "VideoCommon/Resources/MaterialResource.h" +#include "VideoCommon/Resources/ShaderResource.h" +#include "VideoCommon/Resources/TextureAndSamplerResource.h" #include "VideoCommon/Resources/TextureDataResource.h" +#include "VideoCommon/Resources/TexturePool.h" namespace VideoCommon { @@ -25,22 +32,53 @@ class CustomResourceManager void MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id); void XFBTriggered(); + void SetHostConfig(const ShaderHostConfig& host_config); TextureDataResource* GetTextureDataFromAsset(const CustomAssetLibrary::AssetID& asset_id, std::shared_ptr library); + MaterialResource* GetMaterialFromAsset(const CustomAssetLibrary::AssetID& asset_id, + const GXPipelineUid& pipeline_uid, + std::shared_ptr library); + + ShaderResource* GetShaderFromAsset(const CustomAssetLibrary::AssetID& asset_id, + std::size_t shader_key, const GXPipelineUid& pipeline_uid, + const std::string& preprocessor_settings, + std::shared_ptr library); + TextureAndSamplerResource* + GetTextureAndSamplerFromAsset(const CustomAssetLibrary::AssetID& asset_id, + std::shared_ptr library); private: Resource::ResourceContext CreateResourceContext(const CustomAssetLibrary::AssetID& asset_id, - const std::shared_ptr& library); + std::shared_ptr library); void ProcessResource(Resource* resource); void ProcessResourceState(Resource* resource); CustomAssetCache m_asset_cache; + TexturePool m_texture_pool; + Common::AsyncWorkThreadSP m_worker_thread; + std::unique_ptr m_async_shader_compiler; + + using PipelineIdToMaterial = std::map>; + std::map m_material_resources; + + using ShaderKeyToShader = std::map>; + std::map m_shader_resources; std::map> m_texture_data_resources; + std::map> + m_texture_sampler_resources; + + ShaderHostConfig m_host_config; + Common::EventHook m_xfb_event; + + std::unique_ptr m_invalid_transparent_texture; + std::unique_ptr m_invalid_color_texture; + std::unique_ptr m_invalid_cubemap_texture; + std::unique_ptr m_invalid_array_texture; }; } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/MaterialResource.cpp b/Source/Core/VideoCommon/Resources/MaterialResource.cpp new file mode 100644 index 000000000000..657647ffb98b --- /dev/null +++ b/Source/Core/VideoCommon/Resources/MaterialResource.cpp @@ -0,0 +1,385 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "VideoCommon/Resources/MaterialResource.h" + +#include + +#include "Common/VariantUtil.h" + +#include "VideoCommon/AbstractGfx.h" +#include "VideoCommon/Assets/CustomAssetCache.h" +#include "VideoCommon/AsyncShaderCompiler.h" +#include "VideoCommon/FramebufferManager.h" +#include "VideoCommon/PipelineUtils.h" +#include "VideoCommon/Resources/CustomResourceManager.h" +#include "VideoCommon/VideoConfig.h" + +namespace +{ +// TODO: absorb this with TextureCacheBase +bool IsAnisotropicEnhancementSafe(const SamplerState::TM0& tm0) +{ + return !(tm0.min_filter == FilterMode::Near && tm0.mag_filter == FilterMode::Near); +} + +// TODO: absorb this with TextureCacheBase +SamplerState CalculateSamplerAnisotropy(const SamplerState& initial_sampler) +{ + SamplerState state = initial_sampler; + if (g_ActiveConfig.iMaxAnisotropy != AnisotropicFilteringMode::Default && + IsAnisotropicEnhancementSafe(state.tm0)) + { + state.tm0.anisotropic_filtering = Common::ToUnderlying(g_ActiveConfig.iMaxAnisotropy); + } + + if (state.tm0.anisotropic_filtering != 0) + { + // https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt + // For predictable results on all hardware/drivers, only use one of: + // GL_LINEAR + GL_LINEAR (No Mipmaps [Bilinear]) + // GL_LINEAR + GL_LINEAR_MIPMAP_LINEAR (w/ Mipmaps [Trilinear]) + // Letting the game set other combinations will have varying arbitrary results; + // possibly being interpreted as equal to bilinear/trilinear, implicitly + // disabling anisotropy, or changing the anisotropic algorithm employed. + state.tm0.min_filter = FilterMode::Linear; + state.tm0.mag_filter = FilterMode::Linear; + state.tm0.mipmap_filter = FilterMode::Linear; + } + return state; +} +} // namespace + +namespace VideoCommon +{ +MaterialResource::MaterialResource(Resource::ResourceContext resource_context, + const GXPipelineUid& pipeline_uid) + : Resource(std::move(resource_context)), m_uid(pipeline_uid) +{ + m_material_asset = m_resource_context.asset_cache->CreateAsset( + m_resource_context.primary_asset_id, m_resource_context.asset_library, this); + m_uid_vertex_format_copy = + g_gfx->CreateNativeVertexFormat(m_uid.vertex_format->GetVertexDeclaration()); + m_uid.vertex_format = m_uid_vertex_format_copy.get(); +} + +void MaterialResource::ResetData() +{ + if (m_current_data) + { + m_current_data->m_shader_resource->RemoveReference(this); + for (const auto& texture_like_resource : m_current_data->m_texture_like_resources) + { + if (texture_like_resource) + texture_like_resource->RemoveReference(this); + } + if (m_current_data->m_next_material) + m_current_data->m_next_material->RemoveReference(this); + } + m_load_data = std::make_shared(); + m_processing_load_data = false; +} + +Resource::TaskComplete MaterialResource::CollectPrimaryData() +{ + const auto material_data = m_material_asset->GetData(); + if (!material_data) [[unlikely]] + { + return Resource::TaskComplete::No; + } + m_load_data->m_material_data = material_data; + + // A shader asset is required to function + if (m_load_data->m_material_data->shader_asset == "") + { + return Resource::TaskComplete::Error; + } + + CreateTextureData(m_load_data.get()); + SetShaderKey(m_load_data.get(), &m_uid); + + return Resource::TaskComplete::Yes; +} + +Resource::TaskComplete MaterialResource::CollectDependencyData() +{ + bool loaded = true; + { + auto* const shader_resource = m_resource_context.resource_manager->GetShaderFromAsset( + m_load_data->m_material_data->shader_asset, m_load_data->m_shader_key, m_uid, + m_load_data->m_preprocessor_settings, m_resource_context.asset_library); + shader_resource->AddReference(this); + m_load_data->m_shader_resource = shader_resource; + const auto data_processed = shader_resource->IsDataProcessed(); + if (data_processed == TaskComplete::Error) + return TaskComplete::Error; + + loaded &= data_processed == TaskComplete::Yes; + } + + for (std::size_t i = 0; i < m_load_data->m_material_data->textures.size(); i++) + { + const auto& texture_and_sampler = m_load_data->m_material_data->textures[i]; + if (texture_and_sampler.asset == "") + continue; + + const auto texture = m_resource_context.resource_manager->GetTextureAndSamplerFromAsset( + texture_and_sampler.asset, m_resource_context.asset_library); + m_load_data->m_texture_like_resources[i] = texture; + m_load_data->m_texture_like_data[i] = texture->GetData(); + texture->AddReference(this); + + const auto data_processed = texture->IsDataProcessed(); + if (data_processed == TaskComplete::Error) + return TaskComplete::Error; + + loaded &= data_processed == TaskComplete::Yes; + } + + if (m_load_data->m_material_data->next_material_asset != "") + { + m_load_data->m_next_material = m_resource_context.resource_manager->GetMaterialFromAsset( + m_load_data->m_material_data->next_material_asset, m_uid, m_resource_context.asset_library); + m_load_data->m_next_material->AddReference(this); + const auto data_processed = m_load_data->m_next_material->IsDataProcessed(); + if (data_processed == TaskComplete::Error) + return TaskComplete::Error; + + loaded &= data_processed == TaskComplete::Yes; + } + + return loaded ? TaskComplete::Yes : TaskComplete::No; +} + +Resource::TaskComplete MaterialResource::ProcessData() +{ + auto shader_data = m_load_data->m_shader_resource->GetData(); + + if (!shader_data) [[unlikely]] + return Resource::TaskComplete::Error; + + for (std::size_t i = 0; i < m_load_data->m_texture_like_data.size(); i++) + { + auto& texture_like_reference = m_load_data->m_texture_like_references[i]; + const auto& texture_and_sampler = m_load_data->m_material_data->textures[i]; + + // If the texture doesn't exist, use one of the placeholders + if (texture_and_sampler.asset == "") + { + const auto texture_type = shader_data->GetTextureType(i); + if (texture_type == AbstractTextureType::Texture_2D) + texture_like_reference.texture = m_resource_context.invalid_color_texture; + else if (texture_type == AbstractTextureType::Texture_2DArray) + texture_like_reference.texture = m_resource_context.invalid_array_texture; + else if (texture_type == AbstractTextureType::Texture_CubeMap) + texture_like_reference.texture = m_resource_context.invalid_cubemap_texture; + + if (texture_like_reference.texture == nullptr) + { + PanicAlertFmt("Invalid texture (texture_type={}) is not found during material " + "resource processing (asset_id={})", + texture_type, m_resource_context.primary_asset_id); + } + + continue; + } + + auto& texture_like_data = m_load_data->m_texture_like_data[i]; + + std::visit(overloaded{[&](const std::shared_ptr& data) { + texture_like_reference.texture = data->GetTexture(); + texture_like_reference.sampler = CalculateSamplerAnisotropy(data->GetSampler()); + ; + }}, + texture_like_data); + } + + class WorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem + { + public: + WorkItem(std::shared_ptr material_resource_data, + std::shared_ptr shader_resource_data, + VideoCommon::GXPipelineUid* uid, FramebufferState frame_buffer_state) + : m_material_resource_data(std::move(material_resource_data)), + m_shader_resource_data(std::move(shader_resource_data)), m_uid(uid), + m_frame_buffer_state(frame_buffer_state) + { + } + + bool Compile() override + { + // Sanity check + if (!m_shader_resource_data->IsCompiled()) + { + m_material_resource_data->m_processing_finished = true; + return false; + } + + AbstractPipelineConfig config; + config.vertex_shader = m_shader_resource_data->GetVertexShader(); + config.pixel_shader = m_shader_resource_data->GetPixelShader(); + config.geometry_shader = m_shader_resource_data->GetGeometryShader(); + + const auto actual_uid = ApplyDriverBugs(*m_uid); + + if (m_material_resource_data->m_material_data->blending_state) + config.blending_state = *m_material_resource_data->m_material_data->blending_state; + else + config.blending_state = actual_uid.blending_state; + + if (m_material_resource_data->m_material_data->depth_state) + config.depth_state = *m_material_resource_data->m_material_data->depth_state; + else + config.depth_state = actual_uid.depth_state; + + config.framebuffer_state = std::move(m_frame_buffer_state); + config.framebuffer_state.additional_color_attachment_count = 0; + + config.rasterization_state = actual_uid.rasterization_state; + if (m_material_resource_data->m_material_data->cull_mode) + { + config.rasterization_state.cull_mode = + *m_material_resource_data->m_material_data->cull_mode; + } + + config.vertex_format = actual_uid.vertex_format; + config.usage = AbstractPipelineUsage::GX; + + m_material_resource_data->m_pipeline = g_gfx->CreatePipeline(config); + + if (m_material_resource_data->m_pipeline) + { + WriteUniforms(m_material_resource_data.get()); + } + m_material_resource_data->m_processing_finished = true; + return true; + } + void Retrieve() override {} + + private: + std::shared_ptr m_material_resource_data; + std::shared_ptr m_shader_resource_data; + VideoCommon::GXPipelineUid* m_uid; + FramebufferState m_frame_buffer_state; + }; + + if (!m_processing_load_data) + { + auto wi = m_resource_context.shader_compiler->CreateWorkItem( + m_load_data, std::move(shader_data), &m_uid, + g_framebuffer_manager->GetEFBFramebufferState()); + + // We don't need priority, that is already handled by the resource system + m_resource_context.shader_compiler->QueueWorkItem(std::move(wi), 0); + m_processing_load_data = true; + } + + if (!m_load_data->m_processing_finished) + return TaskComplete::No; + + if (!m_load_data->m_pipeline) + { + return TaskComplete::Error; + } + + std::swap(m_current_data, m_load_data); + return TaskComplete::Yes; +} + +void MaterialResource::MarkAsActive() +{ + if (!m_current_data) [[unlikely]] + return; + + m_resource_context.asset_cache->MarkAssetActive(m_material_asset); + for (const auto& texture_like_resource : m_current_data->m_texture_like_resources) + { + if (texture_like_resource) + texture_like_resource->MarkAsActive(); + } + if (m_current_data->m_shader_resource) + m_current_data->m_shader_resource->MarkAsActive(); + if (m_current_data->m_next_material) + m_current_data->m_next_material->MarkAsActive(); +} + +void MaterialResource::MarkAsPending() +{ + m_resource_context.asset_cache->MarkAssetPending(m_material_asset); +} + +void MaterialResource::CreateTextureData(Data* data) +{ + ShaderCode preprocessor_settings; + + const auto& material_data = *data->m_material_data; + data->m_texture_like_data.clear(); + data->m_texture_like_resources.clear(); + data->m_texture_like_references.clear(); + const u32 custom_sampler_index_offset = 8; + for (u32 i = 0; i < static_cast(material_data.textures.size()); i++) + { + const auto& texture_and_sampler = material_data.textures[i]; + data->m_texture_like_references.push_back(TextureLikeReference{}); + + TextureAndSamplerResource* value = nullptr; + data->m_texture_like_resources.push_back(value); + data->m_texture_like_data.push_back(std::shared_ptr{}); + + auto& texture_like_reference = data->m_texture_like_references[i]; + + if (texture_and_sampler.asset == "") + { + preprocessor_settings.Write("#define HAS_SAMPLER_{} 0\n", i); + + // For an invalid asset, force the sampler to use the default sampler + texture_like_reference.sampler_origin = + VideoCommon::TextureSamplerValue::SamplerOrigin::Asset; + texture_like_reference.texture_hash = ""; + } + else + { + preprocessor_settings.Write("#define HAS_SAMPLER_{} 1\n", i); + + texture_like_reference.sampler_origin = texture_and_sampler.sampler_origin; + texture_like_reference.texture_hash = texture_and_sampler.texture_hash; + } + + texture_like_reference.sampler_index = i + custom_sampler_index_offset; + texture_like_reference.texture = nullptr; + } + + data->m_preprocessor_settings = preprocessor_settings.GetBuffer(); +} + +void MaterialResource::SetShaderKey(Data* data, GXPipelineUid* uid) +{ + XXH3_state_t shader_key_hash; + XXH3_INITSTATE(&shader_key_hash); + XXH3_64bits_reset_withSeed(&shader_key_hash, static_cast(1)); + + UpdateHashWithPipeline(*uid, &shader_key_hash); + XXH3_64bits_update(&shader_key_hash, data->m_preprocessor_settings.c_str(), + data->m_preprocessor_settings.size()); + + data->m_shader_key = XXH3_64bits_digest(&shader_key_hash); +} + +void MaterialResource::WriteUniforms(Data* data) +{ + // Calculate the size in memory of the buffer + std::size_t max_uniformdata_size = 0; + for (const auto& property : data->m_material_data->properties) + { + max_uniformdata_size += VideoCommon::MaterialProperty::GetMemorySize(property); + } + data->m_uniform_data = Common::UniqueBuffer(max_uniformdata_size); + + // Now write the memory + u8* uniform_data = data->m_uniform_data.data(); + for (const auto& property : data->m_material_data->properties) + { + VideoCommon::MaterialProperty::WriteToMemory(uniform_data, property); + } +} +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/MaterialResource.h b/Source/Core/VideoCommon/Resources/MaterialResource.h new file mode 100644 index 000000000000..4842f000ea49 --- /dev/null +++ b/Source/Core/VideoCommon/Resources/MaterialResource.h @@ -0,0 +1,99 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include +#include + +#include "Common/Buffer.h" +#include "Common/SmallVector.h" + +#include "VideoCommon/AbstractPipeline.h" +#include "VideoCommon/Assets/MaterialAsset.h" +#include "VideoCommon/Assets/TextureSamplerValue.h" +#include "VideoCommon/Constants.h" +#include "VideoCommon/GXPipelineTypes.h" +#include "VideoCommon/RenderState.h" +#include "VideoCommon/Resources/Resource.h" +#include "VideoCommon/Resources/ShaderResource.h" +#include "VideoCommon/Resources/TextureAndSamplerResource.h" + +namespace VideoCommon +{ +class MaterialResource final : public Resource +{ +public: + MaterialResource(Resource::ResourceContext resource_context, const GXPipelineUid& pipeline_uid); + + struct TextureLikeReference + { + SamplerState sampler; + u32 sampler_index; + TextureSamplerValue::SamplerOrigin sampler_origin; + std::string_view texture_hash; + AbstractTexture* texture; + }; + + class Data + { + public: + AbstractPipeline* GetPipeline() const { return m_pipeline.get(); } + std::span GetUniforms() const { return m_uniform_data; } + std::span GetTextures() const { return m_texture_like_references; } + MaterialResource* GetNextMaterial() const { return m_next_material; } + + private: + friend class MaterialResource; + std::unique_ptr m_pipeline = nullptr; + Common::UniqueBuffer m_uniform_data; + std::shared_ptr m_material_data = nullptr; + ShaderResource* m_shader_resource = nullptr; + + using TextureLikeResource = Resource*; + Common::SmallVector + m_texture_like_resources; + + // Variant for future expansion... + using TextureLikeData = std::variant>; + Common::SmallVector + m_texture_like_data; + + Common::SmallVector + m_texture_like_references; + + MaterialResource* m_next_material = nullptr; + std::size_t m_shader_key; + std::string m_preprocessor_settings; + std::atomic_bool m_processing_finished; + }; + + const std::shared_ptr& GetData() const { return m_current_data; } + void MarkAsActive() override; + void MarkAsPending() override; + +private: + void ResetData() override; + Resource::TaskComplete CollectPrimaryData() override; + Resource::TaskComplete CollectDependencyData() override; + Resource::TaskComplete ProcessData() override; + + static void CreateTextureData(Data* data); + static void SetShaderKey(Data* data, GXPipelineUid* uid); + static void WriteUniforms(Data* data); + + std::shared_ptr m_current_data; + + std::shared_ptr m_load_data; + bool m_processing_load_data = false; + + // Note: asset cache owns the asset, we access as a reference + MaterialAsset* m_material_asset = nullptr; + + GXPipelineUid m_uid; + std::unique_ptr m_uid_vertex_format_copy; +}; +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/Resource.h b/Source/Core/VideoCommon/Resources/Resource.h index f9656fe2fa6c..4bcec910c787 100644 --- a/Source/Core/VideoCommon/Resources/Resource.h +++ b/Source/Core/VideoCommon/Resources/Resource.h @@ -3,6 +3,8 @@ #pragma once +#include "Common/WorkQueueThread.h" + #include "VideoCommon/Assets/AssetListener.h" #include "VideoCommon/Assets/CustomAssetLibrary.h" @@ -12,8 +14,10 @@ class AbstractTexture; namespace VideoCommon { +class AsyncShaderCompiler; class CustomAssetCache; class CustomResourceManager; +class TexturePool; // A resource is an abstract object that maintains // relationships between assets (ex: a material that references a texture), @@ -28,6 +32,13 @@ class Resource : public AssetListener std::shared_ptr asset_library; CustomAssetCache* asset_cache; CustomResourceManager* resource_manager; + TexturePool* texture_pool; + Common::AsyncWorkThreadSP* worker_queue; + AsyncShaderCompiler* shader_compiler; + AbstractTexture* invalid_array_texture; + AbstractTexture* invalid_color_texture; + AbstractTexture* invalid_cubemap_texture; + AbstractTexture* invalid_transparent_texture; }; explicit Resource(ResourceContext resource_context); diff --git a/Source/Core/VideoCommon/Resources/ShaderResource.cpp b/Source/Core/VideoCommon/Resources/ShaderResource.cpp new file mode 100644 index 000000000000..e1aecd355c21 --- /dev/null +++ b/Source/Core/VideoCommon/Resources/ShaderResource.cpp @@ -0,0 +1,311 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "VideoCommon/Resources/ShaderResource.h" + +#include + +#include + +#include "VideoCommon/AbstractGfx.h" +#include "VideoCommon/Assets/CustomAssetCache.h" +#include "VideoCommon/AsyncShaderCompiler.h" +#include "VideoCommon/GeometryShaderGen.h" +#include "VideoCommon/PipelineUtils.h" +#include "VideoCommon/PixelShaderGen.h" +#include "VideoCommon/VertexShaderGen.h" +#include "VideoCommon/VideoConfig.h" + +namespace VideoCommon +{ +namespace +{ +std::unique_ptr +CompileGeometryShader(const GeometryShaderUid& uid, APIType api_type, ShaderHostConfig host_config) +{ + const ShaderCode source_code = + GenerateGeometryShaderCode(api_type, host_config, uid.GetUidData()); + return g_gfx->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer(), nullptr, + fmt::format("Geometry shader: {}", *uid.GetUidData())); +} + +std::unique_ptr CompilePixelShader(const PixelShaderUid& uid, + std::string_view preprocessor_settings, + APIType api_type, + const ShaderHostConfig& host_config, + RasterSurfaceShaderData* shader_data) +{ + ShaderCode shader_code; + + // Write any preprocessor values that were passed in + shader_code.Write("{}", preprocessor_settings); + + // TODO: in the future we could dynamically determine the amount of samplers + // available, for now just hardcode to start at 8 (the first non game + // sampler index available) + const std::size_t custom_sampler_index_offset = 8; + for (std::size_t i = 0; i < shader_data->samplers.size(); i++) + { + const auto& sampler = shader_data->samplers[i]; + std::string_view sampler_type; + switch (sampler.type) + { + case AbstractTextureType::Texture_2D: + sampler_type = "sampler2D"; + break; + case AbstractTextureType::Texture_2DArray: + sampler_type = "sampler2DArray"; + break; + case AbstractTextureType::Texture_CubeMap: + sampler_type = "samplerCube"; + break; + }; + shader_code.Write("SAMPLER_BINDING({}) uniform {} samp_{};\n", custom_sampler_index_offset + i, + sampler_type, sampler.name); + + // Sampler usage is passed in from the material + // Write a new preprocessor value with the sampler name + // for easier code in the shader + shader_code.Write("#if HAS_SAMPLER_{} == 1\n", i); + shader_code.Write("#define HAS_{} 1\n", sampler.name); + shader_code.Write("#endif\n"); + + shader_code.Write("\n"); + } + shader_code.Write("\n"); + + // Now write the custom shader + shader_code.Write("{}", ReplaceAll(shader_data->pixel_source, "\r\n", "\n")); + + // Write out the uniform data + ShaderCode uniform_code; + for (const auto& property : shader_data->uniform_properties) + { + VideoCommon::ShaderProperty::WriteAsShaderCode(uniform_code, property); + } + if (!shader_data->uniform_properties.empty()) + uniform_code.Write("\n\n"); + + // Compile the shader + CustomPixelContents contents{.shader = shader_code.GetBuffer(), + .uniforms = uniform_code.GetBuffer()}; + const ShaderCode source_code = + GeneratePixelShaderCode(api_type, host_config, uid.GetUidData(), contents); + ShaderIncluder* shader_includer = + shader_data->shader_includer ? &*shader_data->shader_includer : nullptr; + return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(), shader_includer, + "Custom Pixel Shader"); +} + +std::unique_ptr CompileVertexShader(const VertexShaderUid& uid, + std::string_view preprocessor_settings, + APIType api_type, + const ShaderHostConfig& host_config, + const RasterSurfaceShaderData& shader_data) +{ + ShaderCode shader_code; + + // Write any preprocessor values that were passed in + shader_code.Write("{}", preprocessor_settings); + + // TODO: in the future we could dynamically determine the amount of samplers + // available, for now just hardcode to start at 8 (the first non game + // sampler index available) + const std::size_t custom_sampler_index_offset = 8; + for (std::size_t i = 0; i < shader_data.samplers.size(); i++) + { + const auto& sampler = shader_data.samplers[i]; + std::string_view sampler_type = ""; + switch (sampler.type) + { + case AbstractTextureType::Texture_2D: + sampler_type = "sampler2D"; + break; + case AbstractTextureType::Texture_2DArray: + sampler_type = "sampler2DArray"; + break; + case AbstractTextureType::Texture_CubeMap: + sampler_type = "samplerCube"; + break; + }; + shader_code.Write("SAMPLER_BINDING({}) uniform {} samp_{};\n", custom_sampler_index_offset + i, + sampler_type, sampler.name); + + // Sampler usage is passed in from the material + // Write a new preprocessor value with the sampler name + // for easier code in the shader + shader_code.Write("#if HAS_SAMPLER_{} == 1\n", i); + shader_code.Write("#define HAS_{} 1\n", sampler.name); + shader_code.Write("#endif\n"); + + shader_code.Write("\n"); + } + shader_code.Write("\n"); + + // Now write the custom shader + shader_code.Write("{}", ReplaceAll(shader_data.vertex_source, "\r\n", "\n")); + + // Write out the uniform data + ShaderCode uniform_code; + for (const auto& property : shader_data.uniform_properties) + { + VideoCommon::ShaderProperty::WriteAsShaderCode(uniform_code, property); + } + if (!shader_data.uniform_properties.empty()) + uniform_code.Write("\n\n"); + + // Compile the shader + CustomVertexContents contents{.shader = shader_code.GetBuffer(), + .uniforms = uniform_code.GetBuffer()}; + const ShaderCode source_code = + GenerateVertexShaderCode(api_type, host_config, uid.GetUidData(), contents); + return g_gfx->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer(), nullptr, + "Custom Vertex Shader"); +} +} // namespace +ShaderResource::ShaderResource(Resource::ResourceContext resource_context, + const GXPipelineUid& pipeline_uid, + const std::string& preprocessor_setting, + const ShaderHostConfig& shader_host_config) + : Resource(std::move(resource_context)), m_uid(pipeline_uid), + m_preprocessor_settings(preprocessor_setting), + m_shader_host_config{.bits = shader_host_config.bits} +{ + m_shader_asset = m_resource_context.asset_cache->CreateAsset( + m_resource_context.primary_asset_id, m_resource_context.asset_library, this); +} + +void ShaderResource::SetHostConfig(const ShaderHostConfig& host_config) +{ + m_shader_host_config.bits = host_config.bits; +} + +void ShaderResource::MarkAsPending() +{ + m_resource_context.asset_cache->MarkAssetPending(m_shader_asset); +} + +void ShaderResource::MarkAsActive() +{ + m_resource_context.asset_cache->MarkAssetActive(m_shader_asset); +} + +AbstractShader* ShaderResource::Data::GetVertexShader() const +{ + if (!m_vertex_shader) + return nullptr; + return m_vertex_shader.get(); +} + +AbstractShader* ShaderResource::Data::GetPixelShader() const +{ + if (!m_pixel_shader) + return nullptr; + return m_pixel_shader.get(); +} + +AbstractShader* ShaderResource::Data::GetGeometryShader() const +{ + if (!m_geometry_shader) + return nullptr; + return m_geometry_shader.get(); +} + +bool ShaderResource::Data::IsCompiled() const +{ + return m_vertex_shader && m_pixel_shader && (!m_needs_geometry_shader || m_geometry_shader); +} + +AbstractTextureType ShaderResource::Data::GetTextureType(std::size_t index) +{ + // If the data doesn't exist, just pick one... + if (!m_shader_data || index >= m_shader_data->samplers.size()) [[unlikely]] + return AbstractTextureType::Texture_2D; + + return m_shader_data->samplers[index].type; +} + +void ShaderResource::ResetData() +{ + m_load_data = std::make_shared(); + m_processing_load_data = false; +} + +Resource::TaskComplete ShaderResource::CollectPrimaryData() +{ + const auto shader_data = m_shader_asset->GetData(); + if (!shader_data) [[unlikely]] + { + return Resource::TaskComplete::No; + } + m_load_data->m_shader_data = shader_data; + + return Resource::TaskComplete::Yes; +} + +Resource::TaskComplete ShaderResource::ProcessData() +{ + class WorkItem final : public VideoCommon::AsyncShaderCompiler::WorkItem + { + public: + WorkItem(std::shared_ptr resource_data, VideoCommon::GXPipelineUid* uid, + u32 shader_bits, std::string_view preprocessor_settings) + : m_resource_data(std::move(resource_data)), m_uid(uid), m_shader_bits(shader_bits), + m_preprocessor_settings(preprocessor_settings) + { + } + + bool Compile() override + { + const ShaderHostConfig shader_host_config{.bits = m_shader_bits}; + auto actual_uid = ApplyDriverBugs(*m_uid); + + ClearUnusedPixelShaderUidBits(g_backend_info.api_type, shader_host_config, + &actual_uid.ps_uid); + m_resource_data->m_needs_geometry_shader = shader_host_config.backend_geometry_shaders && + !actual_uid.gs_uid.GetUidData()->IsPassthrough(); + + if (m_resource_data->m_needs_geometry_shader) + { + m_resource_data->m_geometry_shader = + CompileGeometryShader(actual_uid.gs_uid, g_backend_info.api_type, shader_host_config); + } + m_resource_data->m_pixel_shader = + CompilePixelShader(actual_uid.ps_uid, m_preprocessor_settings, g_backend_info.api_type, + shader_host_config, m_resource_data->m_shader_data.get()); + m_resource_data->m_vertex_shader = + CompileVertexShader(actual_uid.vs_uid, m_preprocessor_settings, g_backend_info.api_type, + shader_host_config, *m_resource_data->m_shader_data); + m_resource_data->m_processing_finished = true; + return true; + } + void Retrieve() override {} + + private: + std::shared_ptr m_resource_data; + VideoCommon::GXPipelineUid* m_uid; + u32 m_shader_bits; + std::string_view m_preprocessor_settings; + }; + + if (!m_processing_load_data) + { + std::string_view preprocessor_settings = m_preprocessor_settings; + auto wi = m_resource_context.shader_compiler->CreateWorkItem( + m_load_data, &m_uid, m_shader_host_config.bits, preprocessor_settings); + + // We don't need priority, that is already handled by the resource system + m_resource_context.shader_compiler->QueueWorkItem(std::move(wi), 0); + m_processing_load_data = true; + } + + if (!m_load_data->m_processing_finished) + return Resource::TaskComplete::No; + + if (!m_load_data->IsCompiled()) + return Resource::TaskComplete::Error; + + std::swap(m_current_data, m_load_data); + return Resource::TaskComplete::Yes; +} +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/ShaderResource.h b/Source/Core/VideoCommon/Resources/ShaderResource.h new file mode 100644 index 000000000000..0f91cd3714a7 --- /dev/null +++ b/Source/Core/VideoCommon/Resources/ShaderResource.h @@ -0,0 +1,67 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "VideoCommon/Resources/Resource.h" + +#include "VideoCommon/Assets/ShaderAsset.h" +#include "VideoCommon/GXPipelineTypes.h" +#include "VideoCommon/ShaderGenCommon.h" + +namespace VideoCommon +{ +class ShaderResource final : public Resource +{ +public: + ShaderResource(Resource::ResourceContext resource_context, const GXPipelineUid& pipeline_uid, + const std::string& preprocessor_settings, + const ShaderHostConfig& shader_host_config); + + class Data + { + public: + AbstractShader* GetVertexShader() const; + AbstractShader* GetPixelShader() const; + AbstractShader* GetGeometryShader() const; + + bool IsCompiled() const; + AbstractTextureType GetTextureType(std::size_t index); + + private: + friend class ShaderResource; + std::unique_ptr m_vertex_shader; + std::unique_ptr m_pixel_shader; + std::unique_ptr m_geometry_shader; + std::shared_ptr m_shader_data; + bool m_needs_geometry_shader = false; + std::atomic_bool m_processing_finished; + }; + + // Changes the shader host config. Shaders should be reloaded afterwards. + void SetHostConfig(const ShaderHostConfig& host_config); + const std::shared_ptr& GetData() const { return m_current_data; } + + void MarkAsActive() override; + void MarkAsPending() override; + +private: + void ResetData() override; + Resource::TaskComplete CollectPrimaryData() override; + TaskComplete ProcessData() override; + + // Note: asset cache owns the asset, we access as a reference + RasterSurfaceShaderAsset* m_shader_asset = nullptr; + + std::shared_ptr m_current_data; + std::shared_ptr m_load_data; + + bool m_processing_load_data = false; + + ShaderHostConfig m_shader_host_config; + GXPipelineUid m_uid; + std::string m_preprocessor_settings; +}; +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.cpp b/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.cpp new file mode 100644 index 000000000000..735a64a357be --- /dev/null +++ b/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.cpp @@ -0,0 +1,103 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "VideoCommon/Resources/TextureAndSamplerResource.h" + +#include "VideoCommon/Assets/CustomAssetCache.h" +#include "VideoCommon/Resources/TexturePool.h" + +namespace VideoCommon +{ +TextureAndSamplerResource::TextureAndSamplerResource(Resource::ResourceContext resource_context) + : Resource(std::move(resource_context)) +{ + m_texture_and_sampler_asset = m_resource_context.asset_cache->CreateAsset( + m_resource_context.primary_asset_id, m_resource_context.asset_library, this); +} + +void TextureAndSamplerResource::MarkAsActive() +{ + m_resource_context.asset_cache->MarkAssetActive(m_texture_and_sampler_asset); +} + +void TextureAndSamplerResource::MarkAsPending() +{ + m_resource_context.asset_cache->MarkAssetPending(m_texture_and_sampler_asset); +} + +const std::shared_ptr& TextureAndSamplerResource::GetData() const +{ + return m_current_data; +} + +void TextureAndSamplerResource::ResetData() +{ + m_load_data = std::make_shared(); +} + +Resource::TaskComplete TextureAndSamplerResource::CollectPrimaryData() +{ + m_load_data->m_texture_and_sampler_data = m_texture_and_sampler_asset->GetData(); + if (!m_load_data->m_texture_and_sampler_data) + return Resource::TaskComplete::No; + + auto& texture_data = m_load_data->m_texture_and_sampler_data->texture_data; + if (texture_data.m_slices.empty()) + return Resource::TaskComplete::Error; + + if (texture_data.m_slices[0].m_levels.empty()) + return Resource::TaskComplete::Error; + + const auto& first_level = texture_data.m_slices[0].m_levels[0]; + + auto& config = m_load_data->m_config; + config.format = first_level.format; + config.flags = 0; + config.layers = 1; + config.levels = 1; + config.type = m_load_data->m_texture_and_sampler_data->type; + config.samples = 1; + + config.width = first_level.width; + config.height = first_level.height; + + return Resource::TaskComplete::Yes; +} + +Resource::TaskComplete TextureAndSamplerResource::ProcessData() +{ + auto texture = m_resource_context.texture_pool->AllocateTexture(m_load_data->m_config); + if (!texture) [[unlikely]] + return Resource::TaskComplete::Error; + + m_load_data->m_texture = std::move(texture); + + auto& texture_data = m_load_data->m_texture_and_sampler_data->texture_data; + for (std::size_t slice_index = 0; slice_index < texture_data.m_slices.size(); slice_index++) + { + auto& slice = texture_data.m_slices[slice_index]; + for (u32 level_index = 0; level_index < static_cast(slice.m_levels.size()); ++level_index) + { + auto& level = slice.m_levels[level_index]; + m_load_data->m_texture->Load(level_index, level.width, level.height, level.row_length, + level.data.data(), level.data.size(), + static_cast(slice_index)); + } + } + std::swap(m_current_data, m_load_data); + + // Release old data back to the pool + if (m_load_data) + m_resource_context.texture_pool->ReleaseTexture(std::move(m_load_data->m_texture)); + + return Resource::TaskComplete::Yes; +} + +void TextureAndSamplerResource::OnUnloadRequested() +{ + if (!m_current_data) + return; + m_resource_context.texture_pool->ReleaseTexture(std::move(m_current_data->m_texture)); + m_current_data = nullptr; +} +} // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.h b/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.h new file mode 100644 index 000000000000..3641b8eb9128 --- /dev/null +++ b/Source/Core/VideoCommon/Resources/TextureAndSamplerResource.h @@ -0,0 +1,49 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "VideoCommon/Resources/Resource.h" + +#include "VideoCommon/AbstractTexture.h" +#include "VideoCommon/Assets/TextureAsset.h" + +namespace VideoCommon +{ +class TextureAndSamplerResource final : public Resource +{ +public: + explicit TextureAndSamplerResource(Resource::ResourceContext resource_context); + void MarkAsActive() override; + void MarkAsPending() override; + + class Data + { + public: + AbstractTexture* GetTexture() const { return m_texture.get(); } + const SamplerState& GetSampler() const { return m_texture_and_sampler_data->sampler; } + + private: + friend class TextureAndSamplerResource; + + std::shared_ptr m_texture_and_sampler_data; + std::unique_ptr m_texture; + TextureConfig m_config; + }; + + const std::shared_ptr& GetData() const; + +private: + void ResetData() override; + TaskComplete CollectPrimaryData() override; + TaskComplete ProcessData() override; + + void OnUnloadRequested() override; + + // Note: asset cache owns the asset, we access as a reference + TextureAndSamplerAsset* m_texture_and_sampler_asset = nullptr; + + std::shared_ptr m_current_data; + std::shared_ptr m_load_data; +}; +} // namespace VideoCommon From c97a947f678bc33735b7267dff46848442dab332 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sat, 8 Nov 2025 19:16:48 -0600 Subject: [PATCH 039/267] VideoCommon: move resource state processing to the resource base class --- .../Resources/CustomResourceManager.cpp | 79 +------------------ .../Resources/CustomResourceManager.h | 2 - .../Core/VideoCommon/Resources/Resource.cpp | 72 ++++++++++++++++- Source/Core/VideoCommon/Resources/Resource.h | 23 +++--- 4 files changed, 87 insertions(+), 89 deletions(-) diff --git a/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp b/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp index 8148ccd899d7..56556285d8f5 100644 --- a/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp +++ b/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp @@ -3,8 +3,6 @@ #include "VideoCommon/Resources/CustomResourceManager.h" -#include "Common/Logging/Log.h" - #include "VideoCommon/AbstractGfx.h" #include "VideoCommon/PipelineUtils.h" #include "VideoCommon/Resources/InvalidTextures.h" @@ -97,7 +95,7 @@ TextureDataResource* CustomResourceManager::GetTextureDataFromAsset( resource = std::make_unique(CreateResourceContext(asset_id, std::move(library))); } - ProcessResource(resource.get()); + resource->Process(); return resource.get(); } @@ -111,7 +109,7 @@ MaterialResource* CustomResourceManager::GetMaterialFromAsset( resource = std::make_unique( CreateResourceContext(asset_id, std::move(library)), pipeline_uid); } - ProcessResource(resource.get()); + resource->Process(); return resource.get(); } @@ -127,7 +125,7 @@ CustomResourceManager::GetShaderFromAsset(const CustomAssetLibrary::AssetID& ass resource = std::make_unique(CreateResourceContext(asset_id, std::move(library)), pipeline_uid, preprocessor_settings, m_host_config); } - ProcessResource(resource.get()); + resource->Process(); return resource.get(); } @@ -141,7 +139,7 @@ TextureAndSamplerResource* CustomResourceManager::GetTextureAndSamplerFromAsset( resource = std::make_unique( CreateResourceContext(asset_id, std::move(library))); } - ProcessResource(resource.get()); + resource->Process(); return resource.get(); } @@ -161,73 +159,4 @@ Resource::ResourceContext CustomResourceManager::CreateResourceContext( m_invalid_cubemap_texture.get(), m_invalid_transparent_texture.get()}; } - -void CustomResourceManager::ProcessResource(Resource* resource) -{ - resource->MarkAsActive(); - - const auto data_processed = resource->IsDataProcessed(); - if (data_processed == Resource::TaskComplete::Yes || - data_processed == Resource::TaskComplete::Error) - { - resource->MarkAsActive(); - if (data_processed == Resource::TaskComplete::Error) - return; - } - - ProcessResourceState(resource); -} - -void CustomResourceManager::ProcessResourceState(Resource* resource) -{ - const auto current_state = resource->GetState(); - Resource::State next_state = current_state; - Resource::TaskComplete task_complete = Resource::TaskComplete::No; - switch (current_state) - { - case Resource::State::ReloadData: - resource->ResetData(); - task_complete = Resource::TaskComplete::Yes; - next_state = Resource::State::CollectingPrimaryData; - break; - case Resource::State::CollectingPrimaryData: - task_complete = resource->CollectPrimaryData(); - next_state = Resource::State::CollectingDependencyData; - if (task_complete == Resource::TaskComplete::No) - resource->MarkAsPending(); - break; - case Resource::State::CollectingDependencyData: - task_complete = resource->CollectDependencyData(); - next_state = Resource::State::ProcessingData; - break; - case Resource::State::ProcessingData: - task_complete = resource->ProcessData(); - next_state = Resource::State::DataAvailable; - break; - case Resource::State::DataAvailable: - // Early out, we're already at our end state - return; - default: - ERROR_LOG_FMT(VIDEO, "Unknown resource state '{}' for resource '{}'", - static_cast(current_state), resource->m_resource_context.primary_asset_id); - return; - }; - - if (task_complete == Resource::TaskComplete::Yes) - { - resource->m_state = next_state; - if (next_state == Resource::State::DataAvailable) - { - resource->m_data_processed = task_complete; - } - else - { - ProcessResourceState(resource); - } - } - else if (task_complete == Resource::TaskComplete::Error) - { - resource->m_data_processed = task_complete; - } -} } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/CustomResourceManager.h b/Source/Core/VideoCommon/Resources/CustomResourceManager.h index 538bec13f1c9..04eaa4694254 100644 --- a/Source/Core/VideoCommon/Resources/CustomResourceManager.h +++ b/Source/Core/VideoCommon/Resources/CustomResourceManager.h @@ -53,8 +53,6 @@ class CustomResourceManager Resource::ResourceContext CreateResourceContext(const CustomAssetLibrary::AssetID& asset_id, std::shared_ptr library); - void ProcessResource(Resource* resource); - void ProcessResourceState(Resource* resource); CustomAssetCache m_asset_cache; TexturePool m_texture_pool; Common::AsyncWorkThreadSP m_worker_thread; diff --git a/Source/Core/VideoCommon/Resources/Resource.cpp b/Source/Core/VideoCommon/Resources/Resource.cpp index 52d1d8b01cbc..b4376314db64 100644 --- a/Source/Core/VideoCommon/Resources/Resource.cpp +++ b/Source/Core/VideoCommon/Resources/Resource.cpp @@ -3,6 +3,8 @@ #include "VideoCommon/Resources/Resource.h" +#include "Common/Logging/Log.h" + namespace VideoCommon { Resource::Resource(ResourceContext resource_context) @@ -10,10 +12,78 @@ Resource::Resource(ResourceContext resource_context) { } +void Resource::Process() +{ + MarkAsActive(); + + if (m_data_processed == TaskComplete::Error) + return; + + ProcessCurrentTask(); +} + +void Resource::ProcessCurrentTask() +{ + Task next_task = m_current_task; + TaskComplete task_complete = TaskComplete::No; + switch (m_current_task) + { + case Task::ReloadData: + ResetData(); + task_complete = TaskComplete::Yes; + next_task = Task::CollectPrimaryData; + break; + case Task::CollectPrimaryData: + task_complete = CollectPrimaryData(); + next_task = Task::CollectDependencyData; + if (task_complete == TaskComplete::No) + MarkAsPending(); + break; + case Task::CollectDependencyData: + task_complete = CollectDependencyData(); + next_task = Task::ProcessData; + break; + case Task::ProcessData: + task_complete = ProcessData(); + next_task = Task::DataAvailable; + break; + case Task::DataAvailable: + // Early out, we're already at our end state + return; + default: + ERROR_LOG_FMT(VIDEO, "Unknown task '{}' for resource '{}'", static_cast(m_current_task), + m_resource_context.primary_asset_id); + return; + }; + + if (task_complete == Resource::TaskComplete::Yes) + { + m_current_task = next_task; + if (next_task == Resource::Task::DataAvailable) + { + m_data_processed = task_complete; + } + else + { + // No need to wait for the next resource request + // process the new task immediately + ProcessCurrentTask(); + } + } + else if (task_complete == Resource::TaskComplete::Error) + { + // If we failed our task due to an error, + // we can't service this resource request, + // wait for a reload and mark the whole + // data processing as an error + m_data_processed = task_complete; + } +} + void Resource::NotifyAssetChanged(bool has_error) { m_data_processed = has_error ? TaskComplete::Error : TaskComplete::No; - m_state = State::ReloadData; + m_current_task = Task::ReloadData; for (Resource* reference : m_references) { diff --git a/Source/Core/VideoCommon/Resources/Resource.h b/Source/Core/VideoCommon/Resources/Resource.h index 4bcec910c787..d53460004f0d 100644 --- a/Source/Core/VideoCommon/Resources/Resource.h +++ b/Source/Core/VideoCommon/Resources/Resource.h @@ -49,17 +49,8 @@ class Resource : public AssetListener Error, }; - enum class State - { - ReloadData, - CollectingPrimaryData, - CollectingDependencyData, - ProcessingData, - DataAvailable, - }; - + void Process(); TaskComplete IsDataProcessed() const { return m_data_processed; } - State GetState() const { return m_state; } void AddReference(Resource* reference); void RemoveReference(Resource* reference); @@ -71,6 +62,7 @@ class Resource : public AssetListener ResourceContext m_resource_context; private: + void ProcessCurrentTask(); void NotifyAssetChanged(bool has_error); void NotifyAssetUnloaded(); @@ -86,7 +78,16 @@ class Resource : public AssetListener virtual TaskComplete ProcessData(); TaskComplete m_data_processed = TaskComplete::No; - State m_state = State::ReloadData; + + enum class Task + { + ReloadData, + CollectPrimaryData, + CollectDependencyData, + ProcessData, + DataAvailable, + }; + Task m_current_task = Task::ReloadData; std::unordered_set m_references; }; From 5391c92f49f20afb84a5d2184ba82e9695bdbbdb Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Mon, 24 Nov 2025 16:13:02 -0600 Subject: [PATCH 040/267] GameSettings: Don't force off ImmediateXFB in Kirby's Return to Dream Land. The game appears to work fine with it enabled. --- Data/Sys/GameSettings/SUK.ini | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 Data/Sys/GameSettings/SUK.ini diff --git a/Data/Sys/GameSettings/SUK.ini b/Data/Sys/GameSettings/SUK.ini deleted file mode 100644 index 1d7efa4b72cb..000000000000 --- a/Data/Sys/GameSettings/SUK.ini +++ /dev/null @@ -1,16 +0,0 @@ -# SUKE01, SUKJ01, SUKP01 - Kirby Wii - -[Core] -# Values set here will override the main Dolphin settings. - -[OnFrame] -# Add memory patches to be applied every frame here. - -[ActionReplay] -# Add action replay cheats here. - -[Video_Settings] - -[Video_Hacks] -ImmediateXFBEnable = False - From 44a766772f399c3134c50bbf4f8273f149f2e218 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Mon, 24 Nov 2025 15:31:50 -0600 Subject: [PATCH 041/267] VideoCommon: Add a hidden setting to cap immediate XFB swaps to one per VI. --- Source/Core/Core/Config/GraphicsSettings.cpp | 1 + Source/Core/Core/Config/GraphicsSettings.h | 1 + Source/Core/VideoCommon/Present.cpp | 17 ++++++++++++++++- Source/Core/VideoCommon/Present.h | 3 +++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/Config/GraphicsSettings.cpp b/Source/Core/Core/Config/GraphicsSettings.cpp index 7062a724cb52..53090bec8a34 100644 --- a/Source/Core/Core/Config/GraphicsSettings.cpp +++ b/Source/Core/Core/Config/GraphicsSettings.cpp @@ -194,6 +194,7 @@ const Info GFX_HACK_SKIP_XFB_COPY_TO_RAM{{System::GFX, "Hacks", "XFBToText const Info GFX_HACK_DISABLE_COPY_TO_VRAM{{System::GFX, "Hacks", "DisableCopyToVRAM"}, false}; const Info GFX_HACK_DEFER_EFB_COPIES{{System::GFX, "Hacks", "DeferEFBCopies"}, true}; const Info GFX_HACK_IMMEDIATE_XFB{{System::GFX, "Hacks", "ImmediateXFBEnable"}, false}; +const Info GFX_HACK_CAP_IMMEDIATE_XFB{{System::GFX, "Hacks", "CapImmediateXFB"}, false}; const Info GFX_HACK_SKIP_DUPLICATE_XFBS{{System::GFX, "Hacks", "SkipDuplicateXFBs"}, true}; const Info GFX_HACK_EARLY_XFB_OUTPUT{{System::GFX, "Hacks", "EarlyXFBOutput"}, true}; const Info GFX_HACK_COPY_EFB_SCALED{{System::GFX, "Hacks", "EFBScaledCopy"}, true}; diff --git a/Source/Core/Core/Config/GraphicsSettings.h b/Source/Core/Core/Config/GraphicsSettings.h index 99dbfb5e6452..5c22f588eaf5 100644 --- a/Source/Core/Core/Config/GraphicsSettings.h +++ b/Source/Core/Core/Config/GraphicsSettings.h @@ -168,6 +168,7 @@ extern const Info GFX_HACK_SKIP_XFB_COPY_TO_RAM; extern const Info GFX_HACK_DISABLE_COPY_TO_VRAM; extern const Info GFX_HACK_DEFER_EFB_COPIES; extern const Info GFX_HACK_IMMEDIATE_XFB; +extern const Info GFX_HACK_CAP_IMMEDIATE_XFB; extern const Info GFX_HACK_SKIP_DUPLICATE_XFBS; extern const Info GFX_HACK_EARLY_XFB_OUTPUT; extern const Info GFX_HACK_COPY_EFB_SCALED; diff --git a/Source/Core/VideoCommon/Present.cpp b/Source/Core/VideoCommon/Present.cpp index ea7cb65f95d2..ea7f2d6d745d 100644 --- a/Source/Core/VideoCommon/Present.cpp +++ b/Source/Core/VideoCommon/Present.cpp @@ -95,8 +95,13 @@ static void TryToSnapToXFBSize(int& width, int& height, int xfb_width, int xfb_h Presenter::Presenter() { + auto& video_events = GetVideoEvents(); + m_config_changed = - GetVideoEvents().config_changed_event.Register([this](u32 bits) { ConfigChanged(bits); }); + video_events.config_changed_event.Register([this](u32 bits) { ConfigChanged(bits); }); + + m_end_field_hook = video_events.vi_end_field_event.Register( + [this] { m_immediate_swap_happened_this_field.store(false, std::memory_order_relaxed); }); } Presenter::~Presenter() @@ -109,6 +114,8 @@ bool Presenter::Initialize() { UpdateDrawRectangle(); + m_immediate_swap_happened_this_field.store(false, std::memory_order_relaxed); + if (!g_gfx->IsHeadless()) { SetBackbuffer(g_gfx->GetSurfaceInfo()); @@ -214,6 +221,12 @@ void Presenter::ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, void Presenter::ImmediateSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height) { + if (m_immediate_swap_happened_this_field.exchange(true, std::memory_order_relaxed) && + Config::Get(Config::GFX_HACK_CAP_IMMEDIATE_XFB)) + { + return; + } + const u64 ticks = m_next_swap_estimated_ticks; FetchXFB(xfb_addr, fb_width, fb_stride, fb_height, ticks); @@ -984,6 +997,8 @@ void Presenter::DoState(PointerWrap& p) m_next_swap_estimated_ticks = m_last_xfb_ticks; m_next_swap_estimated_time = Clock::now(); + m_immediate_swap_happened_this_field.store(false, std::memory_order_relaxed); + ImmediateSwap(m_last_xfb_addr, m_last_xfb_width, m_last_xfb_stride, m_last_xfb_height); } } diff --git a/Source/Core/VideoCommon/Present.h b/Source/Core/VideoCommon/Present.h index e9ad21dbd937..7e5ce651e36a 100644 --- a/Source/Core/VideoCommon/Present.h +++ b/Source/Core/VideoCommon/Present.h @@ -169,6 +169,7 @@ class Presenter u32 m_last_xfb_height = MAX_XFB_HEIGHT; Common::EventHook m_config_changed; + Common::EventHook m_end_field_hook; // Updates state for the SmoothEarlyPresentation setting if enabled. // Returns the desired presentation time regardless. @@ -181,6 +182,8 @@ class Presenter // Can be used for presentation of ImmediateXFB swaps which don't have timing information. u64 m_next_swap_estimated_ticks = 0; TimePoint m_next_swap_estimated_time{Clock::now()}; + + std::atomic_bool m_immediate_swap_happened_this_field{}; }; } // namespace VideoCommon From a358636234003df1a4d9d49eb30c4de51d83f1a2 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Mon, 24 Nov 2025 15:34:39 -0600 Subject: [PATCH 042/267] GameSettings: Enable CapImmediateXFB in Xenoblade instead of disabling ImmediateXFB to handle the uncapped "Reading Disc" screen. --- Data/Sys/GameSettings/SX4.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Data/Sys/GameSettings/SX4.ini b/Data/Sys/GameSettings/SX4.ini index 1d937ab49c4b..24d31349e1a1 100644 --- a/Data/Sys/GameSettings/SX4.ini +++ b/Data/Sys/GameSettings/SX4.ini @@ -10,4 +10,5 @@ # Add action replay cheats here. [Video_Hacks] -ImmediateXFBEnable = False +# Makes the uncapped "Reading Disc" screen not unbearably slow. +CapImmediateXFB = True From 43104036749251ca75454b266e2f49910080c130 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Mon, 24 Nov 2025 22:54:10 -0600 Subject: [PATCH 043/267] GameSettings: Enable CapImmediateXFB in Lost Kingdoms II to allow ImmediateXFB without consistent extraneous swaps that cause terrible pacing. --- Data/Sys/GameSettings/GR2.ini | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Data/Sys/GameSettings/GR2.ini diff --git a/Data/Sys/GameSettings/GR2.ini b/Data/Sys/GameSettings/GR2.ini new file mode 100644 index 000000000000..a44ecb6d98eb --- /dev/null +++ b/Data/Sys/GameSettings/GR2.ini @@ -0,0 +1,5 @@ +# GR2P52, GR2JCQ, GR2E52 - Lost Kingdoms II + +[Video_Hacks] +# Avoids consistent extraneous swaps that cause terrible pacing. +CapImmediateXFB = True From 025ff87a27118f320e561c0ff27be7b66f52d7a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Wed, 26 Nov 2025 23:40:05 +0100 Subject: [PATCH 044/267] Use minizip-ng's CMakeLists instead of relying on our own implementation This is a carry over from back when we used `minizip` and had our own CMakeLists for it. --- CMakeLists.txt | 2 +- Externals/minizip-ng/CMakeLists.txt | 105 +++------------------------- Source/Core/Common/CMakeLists.txt | 2 +- Source/Core/DiscIO/CMakeLists.txt | 2 +- Source/Core/UICommon/CMakeLists.txt | 2 +- 5 files changed, 13 insertions(+), 100 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fa3769f8fde..afa692c4f8d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -690,7 +690,7 @@ dolphin_find_optional_system_library_pkgconfig(ZSTD libzstd>=1.4.0 zstd::zstd Ex dolphin_find_optional_system_library_pkgconfig(ZLIB zlib>=1.3.1 ZLIB::ZLIB Externals/zlib-ng) dolphin_find_optional_system_library_pkgconfig(minizip-ng - "minizip-ng>=4.0.4" minizip-ng::minizip-ng Externals/minizip-ng + "minizip-ng>=4.0.4" MINIZIP::minizip-ng Externals/minizip-ng ) dolphin_find_optional_system_library(LZO Externals/LZO) diff --git a/Externals/minizip-ng/CMakeLists.txt b/Externals/minizip-ng/CMakeLists.txt index 22f8d058ac24..adf26118410d 100644 --- a/Externals/minizip-ng/CMakeLists.txt +++ b/Externals/minizip-ng/CMakeLists.txt @@ -1,96 +1,9 @@ -project(minizip C) - -include(CheckFunctionExists) -include(CheckIncludeFile) - -add_library(minizip STATIC - minizip-ng/mz.h - # minizip-ng/compat/crypt.h - # minizip-ng/compat/ioapi.c - # minizip-ng/compat/ioapi.h - # minizip-ng/compat/unzip.c - # minizip-ng/compat/unzip.h - # minizip-ng/compat/zip.c - # minizip-ng/compat/zip.h - minizip-ng/mz_crypt.c - minizip-ng/mz_crypt.h - minizip-ng/mz_os.c - minizip-ng/mz_os.h - minizip-ng/mz_strm.c - minizip-ng/mz_strm.h - minizip-ng/mz_strm_buf.c - minizip-ng/mz_strm_buf.h -# minizip-ng/mz_strm_bzip.c -# minizip-ng/mz_strm_bzip.h -# minizip-ng/mz_strm_libcomp.c -# minizip-ng/mz_strm_libcomp.h -# minizip-ng/mz_strm_lzma.c -# minizip-ng/mz_strm_lzma.h - minizip-ng/mz_strm_mem.c - minizip-ng/mz_strm_mem.h - minizip-ng/mz_strm_os.h -# minizip-ng/mz_strm_pkcrypt.c -# minizip-ng/mz_strm_pkcrypt.h - minizip-ng/mz_strm_split.c - minizip-ng/mz_strm_split.h -# minizip-ng/mz_strm_wzaes.c -# minizip-ng/mz_strm_wzaes.h - minizip-ng/mz_strm_zlib.c - minizip-ng/mz_strm_zlib.h -# minizip-ng/mz_strm_zstd.c -# minizip-ng/mz_strm_zstd.h - minizip-ng/mz_zip.c - minizip-ng/mz_zip.h - minizip-ng/mz_zip_rw.c - minizip-ng/mz_zip_rw.h -) -dolphin_disable_warnings(minizip) - -if (UNIX) - target_sources(minizip PRIVATE - minizip-ng/mz_os_posix.c - minizip-ng/mz_strm_os_posix.c - ) -endif() - -if (WIN32) - target_sources(minizip PRIVATE - minizip-ng/mz_os_win32.c - minizip-ng/mz_strm_os_win32.c - ) -endif() - -# Unused files -# minizip-ng/minigzip.c -# minizip-ng/minizip.c -# minizip-ng/mz_crypt_apple.c -# minizip-ng/mz_crypt_openssl.c -# minizip-ng/mz_crypt_winvista.c -# minizip-ng/mz_crypt_winxp.c - -target_include_directories(minizip PUBLIC minizip-ng minizip-ng/compat) - -target_compile_definitions(minizip PRIVATE HAVE_ZLIB ZLIB_COMPAT MZ_ZIP_NO_CRYPTO MZ_ZIP_NO_ENCRYPTION) -if (UNIX) - target_compile_definitions(minizip PRIVATE _POSIX_C_SOURCE=200809L) - target_compile_definitions(minizip PRIVATE __USE_LARGEFILE64 _LARGEFILE64_SOURCE) -endif() - -check_include_file(stdint.h HAVE_STDINT_H) -if (HAVE_STDINT_H) - target_compile_definitions(minizip PRIVATE HAVE_STDINT_H) -endif() - -check_include_file(inttypes.h HAVE_INTTYPES_H) -if (HAVE_INTTYPES_H) - target_compile_definitions(minizip PRIVATE HAVE_INTTYPES_H) -endif() - -check_function_exists(fseeko HAVE_FSEEKO) -if (NOT HAVE_FSEEKO) - target_compile_definitions(minizip PRIVATE NO_FSEEKO) -endif() - -target_link_libraries(minizip PUBLIC ZLIB::ZLIB) - -add_library(minizip-ng::minizip-ng ALIAS minizip) +set(MZ_COMPAT OFF) +set(MZ_BUILD_TESTS OFF) +set(MZ_BUILD_UNIT_TESTS OFF) +set(MZ_BUILD_FUZZ_TESTS OFF) +set(MZ_CODE_COVERAGE OFF) +set(SKIP_INSTALL_ALL ON) + +add_subdirectory(minizip-ng) +dolphin_disable_warnings(minizip-ng) diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 2447d1ed401d..33a03729ca4a 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -183,7 +183,7 @@ PUBLIC enet::enet fmt::fmt MbedTLS::mbedtls - minizip-ng::minizip-ng + MINIZIP::minizip-ng sfml-network PRIVATE diff --git a/Source/Core/DiscIO/CMakeLists.txt b/Source/Core/DiscIO/CMakeLists.txt index 884f3de4f2dc..d72c9c1bda55 100644 --- a/Source/Core/DiscIO/CMakeLists.txt +++ b/Source/Core/DiscIO/CMakeLists.txt @@ -75,7 +75,7 @@ PUBLIC PRIVATE fmt::fmt - minizip-ng::minizip-ng + MINIZIP::minizip-ng pugixml ZLIB::ZLIB ) diff --git a/Source/Core/UICommon/CMakeLists.txt b/Source/Core/UICommon/CMakeLists.txt index 2f248e1066b4..e141eab6f940 100644 --- a/Source/Core/UICommon/CMakeLists.txt +++ b/Source/Core/UICommon/CMakeLists.txt @@ -26,7 +26,7 @@ PUBLIC common core cpp-optparse - minizip-ng::minizip-ng + MINIZIP::minizip-ng pugixml PRIVATE From 1958c439207f13baff0f8255c53747a1ad4dcd56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Thu, 27 Nov 2025 00:14:59 +0100 Subject: [PATCH 045/267] Bump zstd to 711e17da98510a3567bf47f85a08a76f64811474 and use upstream CMakeLists --- Externals/zstd/CMakeLists.txt | 150 ++-------------------------------- Externals/zstd/zstd | 2 +- 2 files changed, 8 insertions(+), 144 deletions(-) diff --git a/Externals/zstd/CMakeLists.txt b/Externals/zstd/CMakeLists.txt index bb164b45a706..d83ce4cb1fdf 100644 --- a/Externals/zstd/CMakeLists.txt +++ b/Externals/zstd/CMakeLists.txt @@ -1,146 +1,10 @@ -project(zstd C) +cmake_minimum_required(VERSION 3.13...4.2.0) -if(NOT MSVC) - enable_language(ASM) -endif() +set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) +set(ZSTD_BUILD_PROGRAMS OFF) +set(ZSTD_BUILD_SHARED OFF) -include(CheckTypeSize) -include(CheckFunctionExists) -include(CheckIncludeFile) +add_subdirectory(zstd EXCLUDE_FROM_ALL) -check_include_file(sys/types.h HAVE_SYS_TYPES_H) -check_include_file(stdint.h HAVE_STDINT_H) -check_include_file(stddef.h HAVE_STDDEF_H) - -# Check to see if we have large file support -set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1) -# We add these other definitions here because CheckTypeSize.cmake -# in CMake 2.4.x does not automatically do so and we want -# compatibility with CMake 2.4.x. -if(HAVE_SYS_TYPES_H) - list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H) -endif() -if(HAVE_STDINT_H) - list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H) -endif() -if(HAVE_STDDEF_H) - list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H) -endif() -check_type_size(off64_t OFF64_T) -if(HAVE_OFF64_T) - add_definitions(-D_LARGEFILE64_SOURCE=1) -endif() -set(CMAKE_REQUIRED_DEFINITIONS) # clear variable - -# Check for fseeko -check_function_exists(fseeko HAVE_FSEEKO) -if(NOT HAVE_FSEEKO) - add_definitions(-DNO_FSEEKO) -endif() - -# -# Check for unistd.h -# -check_include_file(unistd.h HAVE_UNISTD_H) -if(HAVE_UNISTD_H) - add_definitions(-DHAVE_UNISTD_H) -endif() - -if(MSVC) - add_definitions(-D_CRT_SECURE_NO_DEPRECATE) - add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) -endif() - -# Always hide XXHash symbols -add_definitions(-DXXH_NAMESPACE=ZSTD_) - -#============================================================================ -# zstd -#============================================================================ - -set(ZSTD_PUBLIC_HDRS - zstd/lib/zstd.h - zstd/lib/zstd_errors.h -) -set(ZSTD_PRIVATE_HDRS - zstd/lib/common/allocations.h - zstd/lib/common/bits.h - zstd/lib/common/bitstream.h - zstd/lib/common/compiler.h - zstd/lib/common/cpu.h - zstd/lib/common/debug.h - zstd/lib/common/error_private.h - zstd/lib/common/fse.h - zstd/lib/common/huf.h - zstd/lib/common/mem.h - zstd/lib/common/pool.h - zstd/lib/common/portability_macros.h - zstd/lib/common/threading.h - zstd/lib/common/xxhash.h - zstd/lib/common/zstd_deps.h - zstd/lib/common/zstd_internal.h - zstd/lib/common/zstd_trace.h - zstd/lib/compress/clevels.h - zstd/lib/compress/hist.h - zstd/lib/compress/zstd_compress_internal.h - zstd/lib/compress/zstd_compress_literals.h - zstd/lib/compress/zstd_compress_sequences.h - zstd/lib/compress/zstd_compress_superblock.h - zstd/lib/compress/zstd_cwksp.h - zstd/lib/compress/zstd_double_fast.h - zstd/lib/compress/zstd_fast.h - zstd/lib/compress/zstd_lazy.h - zstd/lib/compress/zstd_ldm.h - zstd/lib/compress/zstd_ldm_geartab.h - zstd/lib/compress/zstd_opt.h - zstd/lib/compress/zstd_preSplit.h - zstd/lib/compress/zstdmt_compress.h - zstd/lib/decompress/zstd_ddict.h - zstd/lib/decompress/zstd_decompress_block.h - zstd/lib/decompress/zstd_decompress_internal.h -) -set(ZSTD_SRCS - zstd/lib/common/debug.c - zstd/lib/common/entropy_common.c - zstd/lib/common/error_private.c - zstd/lib/common/fse_decompress.c - zstd/lib/common/pool.c - zstd/lib/common/threading.c - zstd/lib/common/xxhash.c - zstd/lib/common/zstd_common.c - zstd/lib/compress/fse_compress.c - zstd/lib/compress/hist.c - zstd/lib/compress/huf_compress.c - zstd/lib/compress/zstd_compress.c - zstd/lib/compress/zstd_compress_literals.c - zstd/lib/compress/zstd_compress_sequences.c - zstd/lib/compress/zstd_compress_superblock.c - zstd/lib/compress/zstd_double_fast.c - zstd/lib/compress/zstd_fast.c - zstd/lib/compress/zstd_lazy.c - zstd/lib/compress/zstd_ldm.c - zstd/lib/compress/zstd_opt.c - zstd/lib/compress/zstd_preSplit.c - zstd/lib/compress/zstdmt_compress.c - zstd/lib/decompress/huf_decompress.c - zstd/lib/decompress/zstd_ddict.c - zstd/lib/decompress/zstd_decompress.c - zstd/lib/decompress/zstd_decompress_block.c -) - -add_library(zstd STATIC ${ZSTD_SRCS} ${ZSTD_PUBLIC_HDRS} ${ZSTD_PRIVATE_HDRS}) -target_compile_definitions(zstd PUBLIC ZSTD_LEGACY_SUPPORT=0) - -if(MSVC) - target_compile_definitions(zstd PUBLIC ZSTD_DISABLE_ASM) -else() - target_sources(zstd PRIVATE zstd/lib/decompress/huf_decompress_amd64.S) -endif() - -dolphin_disable_warnings(zstd) -add_library(zstd::zstd ALIAS zstd) - -target_include_directories(zstd -PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/zstd/lib -) +dolphin_disable_warnings(libzstd_static) +add_library(zstd::zstd ALIAS libzstd_static) diff --git a/Externals/zstd/zstd b/Externals/zstd/zstd index f8745da6ff1a..711e17da9851 160000 --- a/Externals/zstd/zstd +++ b/Externals/zstd/zstd @@ -1 +1 @@ -Subproject commit f8745da6ff1ad1e7bab384bd1f9d742439278e99 +Subproject commit 711e17da98510a3567bf47f85a08a76f64811474 From 54c74429df86379a20b7f58da80f080abe72a8c3 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Fri, 28 Nov 2025 02:12:25 -0600 Subject: [PATCH 046/267] IOS/ES: Make UpdateUIDAndGID and CheckIsAllowedToSetUID take an existing UIDSys so it only needs to be built once in ESDevice::SetUID. Constructing the UIDSys from the filesystem is a major bottleneck in the Wii menu "Data Management" -> "Save Data" -> "Wii" screen and this change makes it about twice as fast. --- Source/Core/Core/IOS/ES/ES.cpp | 39 +++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index de13cf9bd11c..7d3502d1d212 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -256,11 +256,10 @@ IPCReply ESDevice::GetTitleId(const IOCtlVRequest& request) return IPCReply(IPC_SUCCESS); } -static bool UpdateUIDAndGID(EmulationKernel& kernel, const ES::TMDReader& tmd) +static bool UpdateUIDAndGID(EmulationKernel& kernel, ES::UIDSys* uid_sys, const ES::TMDReader& tmd) { - ES::UIDSys uid_sys{kernel.GetFSCore()}; const u64 title_id = tmd.GetTitleId(); - const u32 uid = uid_sys.GetOrInsertUIDForTitle(title_id); + const u32 uid = uid_sys->GetOrInsertUIDForTitle(title_id); if (uid == 0) { ERROR_LOG_FMT(IOS_ES, "Failed to get UID for title {:016x}", title_id); @@ -271,11 +270,10 @@ static bool UpdateUIDAndGID(EmulationKernel& kernel, const ES::TMDReader& tmd) return true; } -static ReturnCode CheckIsAllowedToSetUID(EmulationKernel& kernel, const u32 caller_uid, - const ES::TMDReader& active_tmd) +static ReturnCode CheckIsAllowedToSetUID(EmulationKernel& kernel, ES::UIDSys* uid_sys, + const u32 caller_uid, const ES::TMDReader& active_tmd) { - ES::UIDSys uid_map{kernel.GetFSCore()}; - const u32 system_menu_uid = uid_map.GetOrInsertUIDForTitle(Titles::SYSTEM_MENU); + const u32 system_menu_uid = uid_sys->GetOrInsertUIDForTitle(Titles::SYSTEM_MENU); if (!system_menu_uid) return ES_SHORT_READ; @@ -303,7 +301,9 @@ IPCReply ESDevice::SetUID(u32 uid, const IOCtlVRequest& request) const u64 title_id = memory.Read_U64(request.in_vectors[0].address); - const s32 ret = CheckIsAllowedToSetUID(GetEmulationKernel(), uid, m_core.m_title_context.tmd); + auto& kernel = GetEmulationKernel(); + ES::UIDSys uid_sys{kernel.GetFSCore()}; + const s32 ret = CheckIsAllowedToSetUID(kernel, &uid_sys, uid, m_core.m_title_context.tmd); if (ret < 0) { ERROR_LOG_FMT(IOS_ES, "SetUID: Permission check failed with error {}", ret); @@ -314,7 +314,7 @@ IPCReply ESDevice::SetUID(u32 uid, const IOCtlVRequest& request) if (!tmd.IsValid()) return IPCReply(FS_ENOENT); - if (!UpdateUIDAndGID(GetEmulationKernel(), tmd)) + if (!UpdateUIDAndGID(kernel, &uid_sys, tmd)) { ERROR_LOG_FMT(IOS_ES, "SetUID: Failed to get UID for title {:016x}", title_id); return IPCReply(ES_SHORT_READ); @@ -436,8 +436,10 @@ bool ESDevice::LaunchPPCTitle(u64 title_id) // To keep track of the PPC title launch, a temporary launch file (LAUNCH_FILE_PATH) is used // to store the title ID of the title to launch and its TMD. // The launch file not existing means an IOS reload is required. - if (const auto launch_file_fd = GetEmulationKernel().GetFSCore().Open( - PID_KERNEL, PID_KERNEL, LAUNCH_FILE_PATH, FS::Mode::Read, {}, &ticks); + auto& kernel = GetEmulationKernel(); + auto& fs_core = kernel.GetFSCore(); + if (const auto launch_file_fd = + fs_core.Open(PID_KERNEL, PID_KERNEL, LAUNCH_FILE_PATH, FS::Mode::Read, {}, &ticks); launch_file_fd.Get() < 0) { if (WriteLaunchFile(tmd, &ticks) != IPC_SUCCESS) @@ -456,7 +458,7 @@ bool ESDevice::LaunchPPCTitle(u64 title_id) // Otherwise, assume that the PPC title can now be launched directly. // Unlike IOS, we won't bother checking the title ID in the launch file. (It's not useful.) - GetEmulationKernel().GetFSCore().DeleteFile(PID_KERNEL, PID_KERNEL, LAUNCH_FILE_PATH, &ticks); + fs_core.DeleteFile(PID_KERNEL, PID_KERNEL, LAUNCH_FILE_PATH, &ticks); WriteSystemFile(SPACE_FILE_PATH, std::vector(SPACE_FILE_SIZE), &ticks); m_core.m_title_context.Update(tmd, ticket, DiscIO::Platform::WiiWAD); @@ -464,7 +466,8 @@ bool ESDevice::LaunchPPCTitle(u64 title_id) // Note: the UID/GID is also updated for IOS titles, but since we have no guarantee IOS titles // are installed, we can only do this for PPC titles. - if (!UpdateUIDAndGID(GetEmulationKernel(), m_core.m_title_context.tmd)) + ES::UIDSys uid_sys{fs_core}; + if (!UpdateUIDAndGID(kernel, &uid_sys, m_core.m_title_context.tmd)) { m_core.m_title_context.Clear(); INFO_LOG_FMT(IOS_ES, "LaunchPPCTitle: Title context changed: (none)"); @@ -837,7 +840,8 @@ ReturnCode ESDevice::DIVerify(const ES::TMDReader& tmd, const ES::TicketReader& // XXX: We are supposed to verify the TMD and ticket here, but cannot because // this may cause issues with custom/patched games. - const auto fs = GetEmulationKernel().GetFS(); + auto& kernel = GetEmulationKernel(); + const auto fs = kernel.GetFS(); if (!m_core.FindInstalledTMD(tmd.GetTitleId()).IsValid()) { if (const ReturnCode ret = WriteTmdForDiVerify(fs.get(), tmd)) @@ -847,7 +851,8 @@ ReturnCode ESDevice::DIVerify(const ES::TMDReader& tmd, const ES::TicketReader& } } - if (!UpdateUIDAndGID(GetEmulationKernel(), m_core.m_title_context.tmd)) + ES::UIDSys uid_sys{kernel.GetFSCore()}; + if (!UpdateUIDAndGID(kernel, &uid_sys, m_core.m_title_context.tmd)) { return ES_SHORT_READ; } @@ -856,8 +861,8 @@ ReturnCode ESDevice::DIVerify(const ES::TMDReader& tmd, const ES::TicketReader& // Might already exist, so we only need to check whether the second operation succeeded. constexpr FS::Modes data_dir_modes{FS::Mode::ReadWrite, FS::Mode::None, FS::Mode::None}; fs->CreateDirectory(PID_KERNEL, PID_KERNEL, data_dir, 0, data_dir_modes); - return FS::ConvertResult(fs->SetMetadata(0, data_dir, GetEmulationKernel().GetUidForPPC(), - GetEmulationKernel().GetGidForPPC(), 0, data_dir_modes)); + return FS::ConvertResult(fs->SetMetadata(0, data_dir, kernel.GetUidForPPC(), + kernel.GetGidForPPC(), 0, data_dir_modes)); } ReturnCode ESCore::CheckStreamKeyPermissions(const u32 uid, const u8* ticket_view, From 3072779705fa1b90566af8f1e78b4f1493b6dcaa Mon Sep 17 00:00:00 2001 From: "Mateus B. Cassiano" Date: Fri, 28 Nov 2025 09:13:47 -0400 Subject: [PATCH 047/267] DolphinQt: minor fixes for the OnScreenDisplayPane --- Source/Core/DolphinQt/Settings/OnScreenDisplayPane.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Core/DolphinQt/Settings/OnScreenDisplayPane.cpp b/Source/Core/DolphinQt/Settings/OnScreenDisplayPane.cpp index 6b344f946f99..9ff343d00e0e 100644 --- a/Source/Core/DolphinQt/Settings/OnScreenDisplayPane.cpp +++ b/Source/Core/DolphinQt/Settings/OnScreenDisplayPane.cpp @@ -34,6 +34,7 @@ void OnScreenDisplayPane::CreateLayout() general_layout->addWidget(m_enable_osd, 0, 0); general_layout->addWidget(new QLabel(tr("Font Size:")), 1, 0); + m_font_size->SetTitle(tr("Font Size")); general_layout->addWidget(m_font_size, 1, 1); // Performance @@ -48,9 +49,7 @@ void OnScreenDisplayPane::CreateLayout() m_show_speed = new ConfigBool(tr("Show % Speed"), Config::GFX_SHOW_SPEED); m_show_graph = new ConfigBool(tr("Show Performance Graphs"), Config::GFX_SHOW_GRAPHS); m_speed_colors = new ConfigBool(tr("Show Speed Colors"), Config::GFX_SHOW_SPEED_COLORS); - auto* const perf_sample_window_label = new QLabel(tr("Performance Sample Window (ms)")); m_perf_sample_window = new ConfigInteger(0, 10000, Config::GFX_PERF_SAMP_WINDOW, 100); - m_perf_sample_window->SetTitle(perf_sample_window_label->text()); performance_layout->addWidget(m_show_fps, 0, 0); performance_layout->addWidget(m_show_ftimes, 0, 1); @@ -59,7 +58,8 @@ void OnScreenDisplayPane::CreateLayout() performance_layout->addWidget(m_show_speed, 2, 0); performance_layout->addWidget(m_show_graph, 2, 1); performance_layout->addWidget(m_speed_colors, 3, 0); - performance_layout->addWidget(perf_sample_window_label, 4, 0); + performance_layout->addWidget(new QLabel(tr("Performance Sample Window (ms):")), 4, 0); + m_perf_sample_window->SetTitle(tr("Performance Sample Window (ms)")); performance_layout->addWidget(m_perf_sample_window, 4, 1); // Movie From afaedb3c13778843f1bbc596f0e77b644861bb87 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Fri, 28 Nov 2025 02:23:43 -0600 Subject: [PATCH 048/267] IOS/ES: Set the ESDevice::SetUID IPCReply delay based on ESCore::FindInstalledTMD. This makes SetUID take more emulated time giving the host more time to actually do the work. The Wii menu "Data Management" -> "Save Data" -> "Wii" screen is no longer nearly as hard to emulate at full speed. --- Source/Core/Core/IOS/ES/ES.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 7d3502d1d212..c6cc2e942f8a 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -310,17 +310,22 @@ IPCReply ESDevice::SetUID(u32 uid, const IOCtlVRequest& request) return IPCReply(ret); } - const auto tmd = m_core.FindInstalledTMD(title_id); + // The IPCReply delay is calculated within FindInstalledTMD. + // No clue if this is close to accurate, but our default delay of 4000 + // isn't enough time to actually do the work and is too hard to emulate at 100% speed. + u64 delay_ticks = 0; + + const auto tmd = m_core.FindInstalledTMD(title_id, Ticks{&delay_ticks}); if (!tmd.IsValid()) - return IPCReply(FS_ENOENT); + return IPCReply(FS_ENOENT, delay_ticks); if (!UpdateUIDAndGID(kernel, &uid_sys, tmd)) { ERROR_LOG_FMT(IOS_ES, "SetUID: Failed to get UID for title {:016x}", title_id); - return IPCReply(ES_SHORT_READ); + return IPCReply(ES_SHORT_READ, delay_ticks); } - return IPCReply(IPC_SUCCESS); + return IPCReply(IPC_SUCCESS, delay_ticks); } bool ESDevice::LaunchTitle(u64 title_id, HangPPC hang_ppc) From 7ab899f928535acfb38f32d9740a04f46b7e45d1 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Tue, 2 Dec 2025 15:43:15 -0600 Subject: [PATCH 049/267] Externals: Update SDL to release-3.2.28. --- Externals/SDL/SDL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Externals/SDL/SDL b/Externals/SDL/SDL index badbf8da4ee7..7f3ae3d57459 160000 --- a/Externals/SDL/SDL +++ b/Externals/SDL/SDL @@ -1 +1 @@ -Subproject commit badbf8da4ee72b3ef599c721ffc9899e8d7c8d90 +Subproject commit 7f3ae3d57459e59943a4ecfefc8f6277ec6bf540 From 40f2c99bac4bd17738bd781bfd48091dd104b75f Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Thu, 4 Dec 2025 02:26:45 -0600 Subject: [PATCH 050/267] GameSettings: Fix Game ID for Japanese version of Dragon Ball Z: Budokai. --- Data/Sys/GameSettings/GD7.ini | 2 +- Data/Sys/GameSettings/GZB.ini | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Data/Sys/GameSettings/GZB.ini diff --git a/Data/Sys/GameSettings/GD7.ini b/Data/Sys/GameSettings/GD7.ini index 1788c98cd224..e568ddb7e5e9 100644 --- a/Data/Sys/GameSettings/GD7.ini +++ b/Data/Sys/GameSettings/GD7.ini @@ -1,4 +1,4 @@ -# GD7JB2, GD7E70, GD7PB2 - Dragon Ball Z: Budokai +# GD7E70, GD7PB2 - Dragon Ball Z: Budokai [Video_Hacks] # Frame pacing diff --git a/Data/Sys/GameSettings/GZB.ini b/Data/Sys/GameSettings/GZB.ini new file mode 100644 index 000000000000..b51a319210e1 --- /dev/null +++ b/Data/Sys/GameSettings/GZB.ini @@ -0,0 +1,5 @@ +# GZBJB2 - ドラゴンボールZ + +[Video_Hacks] +# Frame pacing +ImmediateXFBEnable = False From 80465b255445d48772998358ace3df98abc40f4c Mon Sep 17 00:00:00 2001 From: JMC47 Date: Thu, 4 Dec 2025 00:48:20 -0500 Subject: [PATCH 051/267] GameSettings: Convert "Deinterlacing Fix" codes to patches for Dragon Ball Z: Budokai 1 and 2, enabled them by default, and also added the patch for the Japanese version of the game. --- Data/Sys/ApprovedInis.json | 2 +- Data/Sys/GameSettings/GD7E70.ini | 14 ++++---------- Data/Sys/GameSettings/GD7PB2.ini | 14 ++++---------- Data/Sys/GameSettings/GZ3E70.ini | 12 ++++++++---- Data/Sys/GameSettings/GZBJB2.ini | 11 +++++++++++ Source/Core/Core/AchievementManager.h | 4 ++-- 6 files changed, 30 insertions(+), 27 deletions(-) create mode 100644 Data/Sys/GameSettings/GZBJB2.ini diff --git a/Data/Sys/ApprovedInis.json b/Data/Sys/ApprovedInis.json index 396bcf11af70..78bba10e8d86 100644 --- a/Data/Sys/ApprovedInis.json +++ b/Data/Sys/ApprovedInis.json @@ -1 +1 @@ -{"D43J01":{"loophack":"CAB9CED2D904F12CCB21F5B1DE9B5433620C3E13"},"DPOJ8P":{"Bypass Modem Detection":"90BA66E25640A538FEFA6693715718139079FA7B"},"G2BE5G":{"Disable interlaced rendering":"7FFF6BDD93713BEDFD23739C32B86153FA19AEA0"},"G2BP7D":{"Disable interlaced rendering":"56E85D7285F10348E1E5354E379918D07E79EDA9"},"G2VE08":{"16:9 Widescreen":"3ED033396382424533A263A39687A0961EC994A6"},"G2VP08":{"16:9 Widescreen":"EEBC3C5F04BB70AFCA1A4C3D638335CDC9142BA2"},"G3RP52":{"16:9 Widescreen":"7F6B7743F0DDD3704B15882330E490103AE24E36","60fps":"4C9A8572A35F1DB85BBB2F32ED34288A343F1FC0"},"G3YP52":{"16:9 Widescreen":"3D102AFEE2F4945894E74BB702ED3ED2294C6FEC","Force PAL60":"FD61581C593EA34DD358AE33819FAB310F2CE961"},"G4AEE9":{"16:9 Aspect Ratio Fix":"8C2564CF47BB6A9B57D712C90E17F459B0BB6CCD"},"G4ME69":{"16:9 Widescreen":"6FC6E5D91693FAABE25CC721F2121CB0B5CA9D12"},"G5SE7D":{"16:9 Widescreen":"16119398BFE241A84151C046E0BC5BCF89D22049","Remove Bloom":"A5F2FB2B3BFF61F34F8AB1DD5A912A0FD8DFA720"},"G5SP7D":{"16:9 Widescreen":"718AA8BD831961C33114852FDA75BB58F768F46A"},"G8ME01":{"16:9 Aspect Ratio Fix - Centered HUD":"8C2FC3FC6F7766AA8E87425BF3BDD2E46E73DE71","16:9 Aspect Ratio Fix - Centered HUD with letterboxing":"AE3DBE2604CA0660165CA870C4B80E2B523C9475","16:9 Aspect Ratio Fix - Normal HUD":"F6E8264CF14D0189219C1E2D20C4182F190F4B88","16:9 Aspect Ratio Fix - Stretched HUD":"8EA4C7B80ADE3E8FEC28EEFA3A046B6B04162E81","No Letterbox":"B1DE2A3526F2E4511F2B94A5171BF7B3C2C52B9B"},"G8MJ01":{"16:9 Aspect Ratio Fix - Centered HUD":"B3181CA1AAB11EAE9132184DA48D76E775AC0A24","16:9 Aspect Ratio Fix - Centered HUD with letterboxing":"904C0EEEF16D761F7BDF7099DEB384DD9AB26E00","16:9 Aspect Ratio Fix - Normal HUD":"631CE99BDE3F1475303C00C67E3C130D4EB2547B","16:9 Aspect Ratio Fix - Stretched HUD":"81F7AD591F12A01DE82850457ECF147998D1238F"},"G8MP01":{"16:9 Aspect Ratio Fix - Centered HUD":"75AF5D7FA49BE9C3C73EA1482B49CD9B36CE817E","16:9 Aspect Ratio Fix - Centered HUD with letterboxing":"C2E5003E74551DF693A7CB814850CA51D77549EF","16:9 Aspect Ratio Fix - Normal HUD":"FB26AA84B0CB787705E84E869B649307776A2839","16:9 Aspect Ratio Fix - Stretched HUD":"C5F8A81520193418C07C7BC4881F02BE9C4DC9BC","No Letterbox":"7828F5B0C8B470620755C16C60A5A4554F92640C"},"G9SE8P":{"16:9 Widescreen":"CD043229AC47AC93D537B6A0725A2D0BB6FEF4E8"},"G9SJ8P":{"16:9 Widescreen":"C55EF90B542AA3973352A232629A828BC22A8509"},"G9SP8P":{"16:9 Widescreen":"9521774ADEE769CFCCE86F8170FE626387E73019"},"GAFE01":{"16:9 Widescreen":"D24F6D9BE5D79D3C795C2844634A0214BB68B5DA","Make Game Save Copyable (donny2112)":"F9A812FF62A20D5440CAB79DB6AFAE068457A10E"},"GAHEGG":{"Limit internal frame rate (speed hack)":"2873E5178C8068AFA8AFE751F903A69CA9A41F16"},"GAL":{"Trophy Viewer":"DBDB50216B22CDFFF77BDD80261CD0FF75803D3B"},"GALE01r0":{"Normal C Stick Functionality in Singleplayer Modes":"9DC8D90D986FAC175F45006AFF20CF00EDFBE053","Proper 16:9 Widescreen Support":"18B4159E77013EDFE499A33281B771C442970E3B","Properly Display in 4:3":"DC2BCA7D99EBDE1DC7C68CA6AC7F543B93FD6A67"},"GALE01r1":{"Normal C Stick Functionality in Singleplayer Modes":"F6030959C1CAC92F37287D556F18B3C5298FAD5B"},"GALE01r2":{"Disable Rumble":"CFDEEA8AD2A99394BFFEA7211EF03394E7471FA9","Normal C Stick Functionality in Singleplayer Modes":"BCD918A72368B2A30E797C76994E7539A1C0B5D9","PAL Stock Icons":"6B92D95F0EEA165EA84FD753F74B0A9E2079C2D7","Proper 16:9 Widescreen Support":"CEDF18354CDCFC49398551C629E51B053331A55B","Widescreen Support v1.2 [Dan Salvato]":"D32ED4CD685F3FF649F7E749E8C182C657013918"},"GALP01":{"Normal C Stick Functionality in Singleplayer Modes":"4817F202678559291F9F76B46DC7561A45D00B77","Proper 16:9 Widescreen Support":"BFCBE098FE8679B9140A48EA1D8620D5A369697C","Properly Display in 4:3":"5BA2933B8365E21553AA273B91954A4C722B1035"},"GAZE69":{"60FPS":"BC281053C5266B21FDDC6C8996A6021DEA03D459"},"GBLE52":{"16:9 Widescreen":"C0F3AB3BBC9B21F4BF25F44E48CF1CD36D2B3F45"},"GBLP52":{"16:9 Widescreen":"797040CB097BFD369490A1BE29659929D76CE6F7"},"GBRJ18":{"16:9 Widescreen":"B3C867AB34D90E2E9C5B799D800F4C191DE279FA"},"GBSE8P":{"16:9 Widescreen":"4148D453F61A5B81E53669335BC667E651865C76"},"GBSP8P":{"16:9 Widescreen":"6CB029AE768BA5B9995D5F12C1EBB37B3D1FE242"},"GC6E01":{"16:9 Widescreen":"DE932CCAD1B5EB1FAA8D08733BD0D3940C78382A","60 FPS [Nerdzilla]":"85F98064F17AFE0FB02A99A182AF3FEB7644DCAA","Allow Memory Card saving with Savestates":"2F64F98686E62B60E466E931A9EBCD19A750FF4E"},"GC6J01":{"60 FPS [Nerdzilla]":"A6146772E37970EA5564F51A622A04792158B321","Allow Memory Card saving with Savestates":"D8F327304A88FBC717BB1F775494C5F864B9E8D2"},"GC6P01":{"16:9 Widescreen [Ralf]":"05C9016BF58A628A3FD7B16E1B9BB0769A14846F","60 FPS [Nerdzilla]":"1D3FB017C0D20754E48A8BA54EEE7DC4851BE84B","Allow Memory Card saving with Savestates":"EDEE0E28EEA1834868F2865336290FFBDFB9C6DA"},"GC8JA4":{"Fix C4 texture tiling (used for buttons and some character icons)":"843297019804192AF1FC660BC85F4B10891D0BA3"},"GCBE7D":{"16:9 Widescreen":"478DA1D596D8513C343850719155813CB61A56DD"},"GCBP7D":{"16:9 Widescreen":"478DA1D596D8513C343850719155813CB61A56DD","60Hz":"DF2C4DDF082C9E67919443C5ACC485AB2CF7F8D0"},"GCCE01":{"16:9 Widescreen":"BA0066518E7EA8599A81F8496BD39DE20CC369D6","Fix GBA connections":"483BDB94615C690045C3759795AF13CE76552286","Fix buffer overrun bug (crash at Goblin Wall)":"6C107FEC15C76201233CA2645EB5FAB4FF9751CE"},"GCCJGC":{"Fix GBA connections":"4C104D24329172F5D0F8649DE9423B931FE72CA3"},"GCCP01":{"16:9 Widescreen":"2580E7379633CF4DE13B9EC945DB17543477828A","Fix GBA connections":"2EAA60A8A115AD68A795109FB59E4A726D29016D"},"GCN":{"Fix C4 texture tiling (used for buttons and some character icons)":"601FE183C9524ACCF068874DABD73921C86769CF"},"GCVEEB":{"16:9 Widescreen":"ADA686C90189D1D7D23E23E525EFC96EFA104BB9"},"GD7E70":{"Deinterlacing Fix":"95A17AFAAFD83E96CD1CC6242B8667F6A3DC8416"},"GD7PB2":{"Deinterlacing Fix":"847264D37B4822FCBE30082590D936A45BB327D6"},"GDREAF":{"Fix audio issues":"F8EAE60FEB0CFB4477FDC4B9E136B63F68DFA63A"},"GDRP69":{"Fix audio issues":"E23D98B2CE185C3993A40F2495D37E41B971BF91"},"GEDE01":{"Fix startup hang":"21068C3CE905FB0CFFAA7408A93154AF8A5295A2"},"GEDJ01":{"Fix startup hang":"7061F3CF11BF64D3BA7F32CCF2BAC42FF3614AB6"},"GEDP01":{"Fix startup hang":"6F1B00517CBA30BEB738EAA90E71221378CD570D"},"GEME7F":{"Force Progressive Scan":"CB04E00918C9C0F161715D21D046ED6620F7ADEF"},"GEMJ28":{"Force Progressive Scan":"41D8F2C833C0B7B79FCA038752052059207AE4D5"},"GEZE8P":{"16:9 Widescreen [gamemasterplc]":"5CEBCFBEA4E444495D2FD6D8B6607DFB2349CC1B"},"GF7E01":{"16:9 Widescreen [gamemasterplc]":"C59CCA3EF8A5E97B32EB64DB9AE80E652ED281C6"},"GF7P01":{"16:9 Widescreen [gamemasterplc]":"1230053B5C347B62E432EFD6635433A183D18619"},"GFQEA4":{"16:9 Widescreen":"5CD9568CE58EF82EB371594667015C9B799454B9"},"GFZJ01":{"Make Save Copyable":"F659D22CB1DFF15C3915D7630D838EED8DB0BA48"},"GFZP01":{"Make Save Copyable":"F659D22CB1DFF15C3915D7630D838EED8DB0BA48"},"GGTE01":{"16:9 Widescreen [darkludx]":"EF128E7A9C22676834F558BA0F0F7FD8B9028727","Experimental 60fps":"D40344111D989EA009901F8B1C45B5AC8D39E6D2","Simple 60FPS":"5232A937D1D813FF58DD71D716284ED6AB535689"},"GGTJ01":{"Experimental 60fps":"BEC2310911003AF9E4B984A4051E0F885B8CC825","Simple 60FPS":"D62E777A2F019D7BD0AFFBCE876BD9AE408F1667"},"GGTP01":{"16:9 Widescreen":"FA9CD330ECDA01275DA88BD0803DE47757D16A4E","Experimental 60fps":"EB1ACD613BB432A3391CFFF1F0145A6ACE66B210","Simple 60FPS":"43FAD0DDD130BE1E4C8C7603EF6CA7DAA0DF5EE9"},"GGVD78":{"16:9 Widescreen":"9D07DBB5EC2FAA47F2E4587FBD75FD6F3E7E91B0","EFB Copy Fix":"FE52240DF6D132C15A8324E8A477F2BF2250D208"},"GGVE78":{"16:9 Widescreen":"86E561452235BF88D41884558EF34F54CE0FEB48","EFB Copy Fix":"5E38E10829D5F77243C95E9E41518BB3ADE24139"},"GGVP78":{"16:9 Widescreen":"F9B2108D833084FA36A53E00F1647A9579F847D3","EFB Copy Fix":"5E38E10829D5F77243C95E9E41518BB3ADE24139"},"GGVX78":{"EFB Copy Fix":"740F2D1C01DA39D1760D96B03974A48E6F74578D"},"GHAE08":{"Fix audio issues":"9799AFF8463EC86C9230E31E2627E141F0C129D3"},"GHAJ08":{"Fix audio issues":"B45A8FC32D14567B8D6C95F303E00A72C0E1D344"},"GHAP08":{"Fix audio issues":"BC7F3CFC97593AA2055C370C175950DC478D2709"},"GHKD7D":{"Limit internal frame rate (speed hack, also fixes audio and gameplay bugs)":"1AF09E98F0B72833A0F4E519EC3D4130C36D615E"},"GHKE7D":{"Limit internal frame rate (speed hack, also fixes audio and gameplay bugs)":"9BFBDE9184BC05EBD545625DEE486E3AAB36B6A3"},"GHKF7D":{"Limit internal frame rate (speed hack, also fixes audio and gameplay bugs)":"919E853513192C97F3CF49246A65ECBF39E7C201"},"GHKP7D":{"Limit internal frame rate (speed hack, also fixes audio and gameplay bugs)":"1AF09E98F0B72833A0F4E519EC3D4130C36D615E"},"GHKS7D":{"Limit internal frame rate (speed hack, also fixes audio and gameplay bugs)":"919E853513192C97F3CF49246A65ECBF39E7C201"},"GHLE69":{"16:9 Widescreen":"742BFC79D8F0BA5D6215772B58F5A0EADD7BFAFF"},"GHQE7D":{"16:9 Widescreen":"520E5F718D3BD1291C55021776091E0DE0FB4822","Limit internal frame rate during startup (speed hack)":"F6BF450D22104FD2527122EA6E81B1F70E916B95"},"GHQP7D":{"16:9 Widescreen":"AAE14CDC13A0C082A850DED85417100A8C8A0687","60Hz":"884A33613AE8D916128E3FF39B3AA9F63DAADC58","Limit internal frame rate during startup (speed hack)":"BD475ADEF145AC9226514CD1B2D4D5F3BFE67964"},"GHSE69":{"16:9 Widescreen":"3538CDBD13FA939B7BA5F0F82253401AFDD1E2CD"},"GHSP69":{"16:9 Widescreen":"409754E2EBB6F05DEE1AFC647E25B15D462638FF"},"GICD78":{"EFB Copy Fix":"3A94591A149AE88C150AB3320BBC909FE54BAEA5"},"GICE78":{"EFB Copy Fix":"5BF55685B8867A85EAA9C86571309B17BF7DED32"},"GICF78":{"EFB Copy Fix":"85AABAEB9A59C4F96D9330A3B884F6D757DA1683"},"GICH78":{"EFB Copy Fix":"3A94591A149AE88C150AB3320BBC909FE54BAEA5"},"GICJG9":{"EFB Copy Fix":"969134EA21A160EBDA91C0870266E7D1707FDC43"},"GICP78":{"EFB Copy Fix":"13B158CF41F5412BC637F50644193D43CC3DA49A"},"GIQE78":{"EFB Copy Fix":"E15AA1E30D26E5735D68AAADE436E7B7E4A33A35"},"GIQJ8P":{"EFB Copy Fix":"FFFCB76E98DDB06A7BBBC0AA73C869C87EB787D6"},"GIQX78":{"EFB Copy Fix":"485DA99FAB35646DAA2A138B0315361495ABE778"},"GIQY78":{"EFB Copy Fix":"485DA99FAB35646DAA2A138B0315361495ABE778"},"GK2":{"16:9 Widescreen [Vague Rant]":"6B4C59C2A2C5D71C7A38C8513A76E6467E307A26"},"GK2E52":{"60 FPS":"8F2397930A50C3C176188526EB9612578F9CBCE5"},"GK4":{"16:9 Widescreen":"4652969A4DA869FD28F2CAA3869A38F5C2AAFEB1"},"GKB":{"16:9 Widescreen Region-Free":"4652969A4DA869FD28F2CAA3869A38F5C2AAFEB1"},"GKBPAF":{"60Hz":"8E4E0ABA0E6D102A33206F34F4DEE63159B3CB4F"},"GKDP01":{"16:9 Widescreen":"DF4657937DE730107B636C73E959277EB963D210","60Hz":"6740D7B914CC897AF50798C0AB391965294FD1E1"},"GKRPB2":{"16:9 Widescreen":"69C01A4F91D991CF866237FED94A138308FC104F","60Hz":"40D06A5C7A3D873ABC73DEDF573738C2E3E37FF0"},"GKWJ18":{"16:9 Widescreen":"696570101FA040778EAD310377C484C846D87430"},"GKYE01":{"16:9 Widescreen":"6520EF1B7D88F00747B120A3A010458602ED989D"},"GKYJ01":{"16:9 Widescreen":"47B8EF7D02831AA5C375C698797BF2D5475FEFF2"},"GKYP01":{"16:9 Widescreen":"69413C75036D2975716066E6574461B981FF0124"},"GLEE08":{"Fix audio issues":"7355F358CAC6F418D37E4C23E64F7867D46E4FC9"},"GLEJ08":{"Fix audio issues":"12B24A6D7389A2AC5AB75FC0BF8493E7661F2A73"},"GLEP08":{"Fix audio issues":"81BD39F5527552DE89E3B59BA86298900F0A3168"},"GLSD64":{"Fix freeze in opening cutscene":"5E2A73717BD66EF647846DD64C33BC80AD9B5227"},"GLSE64":{"Fix freeze in opening cutscene":"1CE78E7954415A44DF693C0BB879AA5A4FF059A3"},"GLSF64":{"Fix freeze in opening cutscene":"009B0C4AD80A9C28C987934D254C2C4AACC9A07A"},"GLSP64":{"16:9 Widescreen":"8E7A544C10E7A5E2F0304A0D2586879627EF6586","60Hz":"B67144E87B54246137142992A3BC83DC13BE68A7","Fix freeze in opening cutscene":"3D0894616C9A7FA5ED91C1D2F461BF14DF47ECEC"},"GM4E01":{"16:9 Menu Backgrounds Add-On":"87D1A6A3E29ADA03B0D29C2F1841C18E62DB0A15","16:9 Widescreen v2":"78BE50F93E81A1972CA31ABC318949E366E82BD0"},"GM4P01":{"16:9 Menu Backgrounds Add-On":"87D1A6A3E29ADA03B0D29C2F1841C18E62DB0A15","16:9 Widescreen v2":"6D950B6EEFD6D304E1A424355B74A595D32BDF2F"},"GMBE8P":{"16:9 Widescreen":"D12DE9E3941BCE6EB50B8DA92140E09AFC0104C8","NA Stretched HUD":"0151A6683E1FBFD20096807C54A6952C4A4BAD40"},"GMBP8P":{"16:9 Widescreen":"8A688981F33A2C53882EF08FCF20B88AD43EF417"},"GMNE78":{"Limit internal FPS to VPS (improves performance)":"DE38BC8493EA24F93B6D805F28746AA99C53C677"},"GMNP78":{"Limit internal FPS to VPS (improves performance)":"65FB9B430F7D58EBC76DAADE8CA9DBBAA32B8B51"},"GMOP70":{"16:9 Widescreen":"CE4D298616BD42E4D8F8936B325CD1FD7F5B956B","60Hz":"0CD2CC787A5FF551901E41C85C8AAC02017ECB89"},"GMPE01":{"16:9 Widescreen":"4F98592DB3DEE3857469A8D8605FAF4BD6F7C76D","QOL - Allow Digital Presses for Map Screen":"E232B27564E9AA0C32DE163C9C056317A7B2B12E","QOL - Automatically Advance Text Boxes":"59607671BFC4717ACAF9807BB7EB0D9F982866D4","QOL - Disable Advance on Results":"CAEA37F3FEF89400513353EB85875F2A3AF4C03E","QOL - Faster Boot Time":"F75FBBD838C5B84FF687962FBA9195B217DE132C","QOL - Increased Board Speed":"19F264DE7F07EAC9433CA4B591BEBA1EC976C9F1","QOL - Increased Taunt Capabilities":"C70391D4961A0E820DE40141C89341369A9F021B","QOL - Instant Text Display":"F4E6913CF034E5778B9F9CA5FF448FF1B78B3333","QOL - Rumble Always Off":"93621947019532F02C25937FD3EEEE21A788CB07","QOL - Show Controller Port Number of Who Paused":"D7249AC3C949FEB860CF4350C5B7B79AC16569F1"},"GMPJ01":{"16:9 Widescreen":"A795811F2F0C92D9DCABDE97D9E39B47B1DBCEFD"},"GMPP01":{"16:9 Widescreen":"A795811F2F0C92D9DCABDE97D9E39B47B1DBCEFD"},"GMSE01":{"60FPS":"2805B1A0DD53EB64877D375D10F667700955720F","Widescreen":"BD718F961DBA5372B1D0257D454D535746C453A0"},"GMSJ01":{"16:9 Widescreen":"E8112A01040A06460E368F142C5D1FD0B4085D94"},"GMSJ01r0":{"60FPS":"9894B5B6B5215844D48411021FF8EECFE851D79D"},"GMSJ01r1":{"60FPS":"2DB69DB7A3753D543CD85CA4C77B4EF0AED7486E"},"GMSP01":{"60FPS":"D07009B710B3BBC6B12E54ED6A7969D58197EDAF","Widescreen":"0B7B89BF0868393076EF5F9DBD689DD0EDBCB84C"},"GNHE5d":{"Nop Hack":"89393A24E2336841AA4CD0AD3BE1C9A66B89E9EF"},"GOCE5D":{"16:9 Widescreen":"E4D800B90F16A15D9252EED1B2A23AEAF5CD230A"},"GOME01":{"16:9 Widescreen":"C33CBBF6F22195BF626104B4827200B3EE1CF30C"},"GOMP01":{"16:9 Widescreen":"874784CCD4AC3DC9C69654E471C18AD0F5E4D9AE"},"GONE69":{"Widescreen Hack Culling":"6412A67E1C26E146A9526AFC9F0EE517B214069D"},"GP4J18":{"16:9 Widescreen":"BF4D2D6AF66F285E81173B3B20D5369DB6FB351B"},"GP5E01":{"16:9 Widescreen":"5ED053787332DB5EEB8B963BA5DF197B58C6BB75","QOL - Automatically Advance Text Boxes":"41EF84663008668682BB75DC8B874E38669AE041","QOL - Disable Advance on Results":"6C36BEFE751131298BC8B39012892F6A6903CE60","QOL - Faster Boot Time":"8E952E6E12639AC20F6F9FDD150C12F0C294DF43","QOL - Increased Board Speed":"4BD72B8ED75ED8EFB3329C104BAD114FDDB8AD2C","QOL - Increased Capsule Throwing Speed":"C5BA3C9D386D09DD6CB9242A12A0D041BEB93160","QOL - Increased Taunt Capabilities":"C360EBDDCB0237076052C983BD9719411CA67CDE","QOL - Instant Text Display":"2CD4A06A3B9C18CC9EA2A2DEBD96E066CD1D700A","QOL - Show Controller Port Number of Who Paused":"5BA3648D18346EDC97B23475D4748C637E6095A2"},"GP5J01":{"16:9 Widescreen":"81E69B6BEE85E06805EC24E1CFEA9405BF459DF8"},"GP5P01":{"16:9 Widescreen":"FD4FCCB97C06F0173A30D4CC9A99422B2C0ABA9B"},"GP6E01":{"16:9 Widescreen":"B502AF0887792E9B140516D14BA75F99772C17BE","QOL - Auto Advance Text Boxes":"E645DF70CE0266D174D917A817A7FBEEE974A9F0","QOL - Disable Advance on Results":"798E566B621F6A32BF23C588E76EAC0776E2A8A3","QOL - Faster Boot Time":"B089A3C80D5DA86ABF6258F8BFB1DC78BB54A973","QOL - Increased Board Speed":"501C52ACF117950888A66DB2BEDBDFD7D9B20235","QOL - Increased Orb Throwing Speed":"845F439278DA8CBC225658FF4E2F82D707422BFB","QOL - Increased Taunt Capabilities":"0AED27341A06186AD92D5725C0B9693CA8F85B7B","QOL - Instant Text Display":"5AAC4E21927D4AEE7AC329CE793D4CDAEDDF7A3F","QOL - Show Controller Port Number of Who Paused":"DF5D2F068D76ABF2B1C294D413B9154B8C356929"},"GP6J01":{"16:9 Widescreen":"88F50F8298F82E3E5C161277BD4A985CE893A9D0"},"GP6P01":{"16:9 Widescreen":"DCCE59CA987624C753F0A86BEBA4287635901C93","Remove Black Bars":"138A86D43B5830BFE1926F58C0A4FBE2971BB02D"},"GP7E01":{"16:9 Widescreen":"87EBF72D90503EBC5CE9BC994795669E48A92A4A","QOL - Auto Advance Text Boxes":"82338AB5D82A7F398B4EB674CA4866DD1F4A1E65","QOL - Controller Options Always Acesssible":"D2F9CC0B9E52136E77187395FB7DA9B64B2C3B30","QOL - Disable Advance on Results":"A644551162A61DE7997B2A84F5BFDEFFD3FC2FB5","QOL - Faster Boot Time":"1939B5C575AE8FF6890BDDDD1B3FEA472D8CABA0","QOL - Increased Board Speed":"7E06A2EBCFECADB8074152B489984237A6FE9F21","QOL - Increased Orb Throwing Speed":"6671BEE71920D6B845AE1257AFE3AB3B95CD6FBD","QOL - Increased Taunt Capabilities":"9F60923F95FFE709CCD06966CD2DF743263934D1","QOL - Instant Text Display":"48FA6002E42DA9BB83ABC980A32C60CE3B21C4FC","QOL - Show Controller Port Number of Who Paused":"5E6F8C6C87D5944DB18A4E4F9A45F61EE87A4163"},"GP7J01":{"16:9 Widescreen":"A081F0729068D233E99DC00C64E36CA33C945640"},"GP7P01":{"16:9 Widescreen":"75D6CDA4EA301A71F7701A0487544E79136850B9","60Hz":"6D0D5B7CA58C38A3147F8ED981B5B21CC6C519CD"},"GPIE01":{"No Blur":"A25CDDB79991F090BD7F12840AD06F13BD5CCF95"},"GPIE01r0":{"16:9 Widescreen":"2B58166A66644F984E64077A6245C94C79B51063"},"GPIE01r1":{"16:9 Widescreen":"9A1545AB4E2B9216B95AFFA83420D723512DA8C8","60FPS":"3337C767EAA21D30C6CFEAE9985FFCABFC63E2E3","Disable Pikmin optimizations":"CBD15E9104929F0631713AE482475CB2B90E71F2"},"GPIP01":{"16:9 Widescreen":"5AE44D5B0E0D4C412B453B95CF5A41DBA4D685E6","60Hz":"AE59FF751E167632AE283F38CC4B96BDF7B9B81F","Turn off blur":"4ED79A548DBD7DBD35928A2F1138315FF103E260"},"GPNE08":{"16:9 Widescreen [Ralf, darkludx]":"ED3D9BB08C5F1D21BC8D5C73155C00E3C25C466F"},"GPNP08":{"16:9 Widescreen [Ralf]":"469B18FE8219031D355557B836EF02B625040A4F"},"GPOE8P":{"Make Save Copyable NTSC Port - 1.0\/1.1":"7A4B3E596BA4FDA8F3FCF984079B3F44CB2D6AB3","Make Save Copyable NTSC Port - PLUS\/1.2":"304DB311F2107E88EBCE058535B266F9263AA8E2","Save Validation Code v 1.0\/v1.1":"9F6259132453DCC0607EAB35DB182C76818F2F9F","Save Validation Code v1.2\/Plus":"17EB6CFB408EF27D44C053A1336C3B87B6A05018"},"GPOE8Pr0":{"16:9 Widescreen":"99986BB1D4ABE45C429D48B01BFB578FEA69C14F"},"GPOE8Pr1":{"16:9 Widescreen (Plus) [Ralf]":"5563671A6702785FFE106DAB7EF3F4FE6D9F705B"},"GPOP8P":{"16:9 Widescreen":"DF133C61C29D5CFA87A2A785C962C205F80E6D04","Game Save Valid":"40EC1590DB26C7C58D00E3065F1E404341EF0E73","Game Save copyable":"2F5FB98927DAFF141D1CCD1EACA8AF626397E284"},"GPVE01":{"16:9 Widescreen":"E5B51080CFD518FE584CF3B61A1099CD032479D6","60 FPS":"ADF5E3BBF0002A76949D0C11C51E58089BACFEED"},"GPVP01":{"16:9 Widescreen":"78F3C9A789827B063A6701987262276A66ABD82B"},"GQPE78":{"EFB Copy Fix":"880B114E9A308084CAB92C004A9EE067B371C310"},"GQPP78":{"EFB Copy Fix":"5D9A14954AE8D639C9B254F3BA73A70F284BBC8D"},"GQSDAF":{"16:9 Widescreen":"CA82C44B2E8FC5C184E3FF935BC89661B7DB55D6","60Hz":"952165FD78543EB6D2F5230F7570B0513773D332","No Blur":"DEB7DF358423F0EF30C9FD49F4F14590836D52A6"},"GQSEAF":{"16:9 Widescreen":"48AFE1D32843C6B5AD4337A49F15FD447DF2A752","Remove Blur":"EF448CF1FA6A15EB2661EA5338703C13D52EF65B"},"GQSFAF":{"16:9 Widescreen":"76C30E1737CC5C3B5DE32532B5F9A5CD50B690F8","No Blur":"986BAE5103CDE9286D2D34FD28FE2540D0759AAB"},"GR2E52":{"16:9 Widescreen":"5F55CE7DA7E1E3261CF2FF88F34CDA63BA511003"},"GR2J52":{"16:9 Widescreen":"D3C6FA690BED07BFA65C2E1FCDE2FFA5AA0EEEE4"},"GR2P52":{"16:9 Widescreen":"D7BCADD4E76B5E3F7D9D463F55A2777528E37E94"},"GRNE52":{"16:9 Widescreen":"483D74C47AD1012606D591A226AB3144C7FB201C"},"GRNJ52":{"16:9 Widescreen":"949281B7221B20680B7BC29E4754B73A326EBE85"},"GRNP52":{"16:9 Widescreen":"11051B094FE5A8B2E73060BFF786C1588E36979A"},"GROE5Z":{"16:9 Widescreen":"FADBAB5EC280CF8ED4C9536A33F4184BA210C9B0"},"GRYE41":{"Disable Culling to Fix Rise and Shrine Hang":"AF0A575EB6071EAC0D2EC3D2EA30A23EB05A4192"},"GSAE01r0":{"viWidth 704 Aspect Ratio Fix":"0D529180B9B28BB06E21EDBDBA61C17EEF0FFB7F"},"GSAE01r1":{"viWidth 704 Aspect Ratio Fix":"CB15ED22625690A5DBE4607FE30160125421461D"},"GSAP01":{"viWidth 704 Aspect Ratio Fix":"749EDA62B1B73354599929F1B50E992E111C5493"},"GSNE8P":{"16:9 Widescreen":"CFDF3FA5B48B347E49E8E521D7BE47FCC9A5CBF4","60Hz Aspect Ratio Fix":"D90F66C0D46D9BEF27C8E13BC8804DB1F382C8B1"},"GSNJ8P":{"60Hz Aspect Ratio Fix":"98DF9D67DE77F66A4B09F25C5621805DEB40865B"},"GSNP8P":{"60Hz Aspect Ratio Fix":"D90F66C0D46D9BEF27C8E13BC8804DB1F382C8B1"},"GSO":{"16:9 Widescreen Region Free":"0D60D0593F6DA28B1236381B22082506B9533F0E"},"GSPE69":{"16:9 Widescreen":"80E18A8963F4EFD3C03494C95934452FCB6E521B"},"GSPP69":{"16:9 Widescreen":"162E87E9F5511CD82216811055836C11B374C45B","60Hz":"E5DF2DF34D2F0BDEE4205C891576511EC572C5DC"},"GSWE64":{"16:9 Widescreen":"6480326CCA8FF64A4868EC6E9FDE9F38819A75A1","Disable Dithering":"85F65E4B627641862C1A6091D29A3BB0626B04C3"},"GTEE01":{"16:9 Widescreen":"6B57EBCB9CC0ACE2EDA0F13E3F1F55F3FABC3A26"},"GTEP01":{"16:9 Widescreen":"72785784363C46180AF8E388348FD77667E7D382"},"GTOJAF":{"Remove Blur":"53A2EDF113F2ED7E54A16AA0E73FDB2C44C79DE5"},"GTRE78r0":{"Limit internal FPS to VPS (improves performance)":"42B85EFC5DEF8B243521EAD434DDCBDF95664CB1"},"GTRE78r1":{"Limit internal FPS to VPS (improves performance)":"ADB3A41B992EAB15AE484B2E575ACF3354415186"},"GTRJ8N":{"Limit internal FPS to VPS (improves performance)":"47DBEFDCF22ADC2AB148A54AC885FE19B3C07E3F"},"GTRP78":{"Limit internal FPS to VPS (improves performance)":"E8752E1B60DF76CD0CC7408074E742B0966BC904"},"GTZE41":{"16:9 Widescreen":"ECCE87E0006475C73E7D936AA0150BD20166F9EF"},"GTZP41":{"16:9 Widescreen":"62D8F159B93167171E0860D96C4BB32A5BF5648B"},"GU2D78":{"EFB Copy Fix":"CFF4C3F932B08732627572EDA1A0CD2D9C71AE0C"},"GU2F78":{"EFB Copy Fix":"CFF4C3F932B08732627572EDA1A0CD2D9C71AE0C"},"GU3D78":{"EFB Copy Fix":"8A0E3114862ADFE421874211BD6F5220AA425BF5"},"GU3X78":{"EFB Copy Fix":"E3303FDAE7ECA17A72EDC440C32D94648A6453A0"},"GU4Y78":{"EFB Copy Fix":"D54767785E139A8BC8C4B75573FBD5A0B686D8E3"},"GUNE5Dr0":{"16:9 Widescreen":"C942EBCBE8A487C25E296EC1FAC2358DA1487DBD","60 FPS":"A441630EC5FF0EB74D2243A3092D22E69C6BEA02"},"GUNE5Dr1":{"16:9 Widescreen":"39BD84CBE2AFACFEDEC5E9020D1A8B0D36DD53F9","60 FPS":"05779F1A3D0C43305D52A95447D612CB424942C0"},"GUNP5D":{"16:9 Widescreen":"FE3BA1DAA1AF278A7839E27BF466B0BA0B390EC2","50 FPS":"3B20499A3F8D1D7CCA5B0015F2D80ECED25842A6"},"GV4E69":{"Fix 2D Rendering":"8679891FCAA250FCFF670B26E0CB9875900D17FD"},"GVJE08":{"16:9 Widescreen":"09EFDA75D876A675121C8344D8FDD09A70A1A846"},"GVJP08":{"16:9 Widescreen":"93938F4C6112C91549F2B52E6259170F7501EC07"},"GVPE69":{"Fix 2D Rendering":"3159CA79B0A890131763EA6CB163684BEE886E3F"},"GVSE8P":{"16:9 Widescreen":"4CE9C491160A4B631142EE9CE802C694163F1CA3"},"GWRE01":{"16:9 Widescreen":"AC42770B06662BE1DC863EC80F44B5E034C63664"},"GWRP01":{"16:9 Widescreen":"9DDDFAB28C4BD35CF64050E1EF684DC042B1AFFA"},"GWWE01":{"16:9 Widescreen":"98B2E75D8E1CED4A964D3129A5DC10E30538CAA6"},"GWWJ01":{"16:9 Widescreen":"2DAD9A5E2A140F02CCBA727C4BE7C74BAC156778"},"GWWP01":{"16:9 Widescreen":"2DAD9A5E2A140F02CCBA727C4BE7C74BAC156778"},"GWZE01":{"16:9 Widescreen":"9EFC191DE6D21A1681FE241AB2EE4A131259F317"},"GXCE01":{"16:9 Widescreen":"901A1E78A3A0124F55548507D3B3707125C64A8A"},"GXSE8P":{"16:9 Widescreen":"F50BBA440184FC77A4DFFAA58FF2BB888E2E072F","Aspect Ratio Fix":"4214C74DFB8A74FC3AA4A643E869BC4D9A38EDA0"},"GXSJ8P":{"Aspect Ratio Fix":"227909607984BBC3D36AAC7DB9DFE385F3363C49"},"GXXE01":{"16:9 Widescreen":"7CAFDAD7B5E7459CCC1BB209D439DDCBB5BE4E4E","60 FPS":"7E2829049003FC9DC8BC28044B33CAFF3768B54C","Allow Memory Card saving with Savestates":"64FAA15062F0D0C319F904BBDE9C4489A25D6369"},"GXXJ01":{"16:9 Widescreen":"AF704A8C6838FDF47054D9EDD9106B3F46781FA9","60 FPS":"4F5FD45B4EC1B33FE076FA06F8FF863C46A06BBA","Allow Memory Card saving with Savestates":"8293802260536FA2EF2EFDAB5266DE36BB88DE1B"},"GXXP01":{"16:9 Widescreen":"02716B2585BEE74F8FCDD97A78F6A0D3DC7F331B","60 FPS":"BF6171EA5CCF4B57AA596372589DDB5E6904DD7A","Allow Memory Card saving with Savestates":"3CAFBC4AE6FC5CE9F53377F86AB5BD8F1BC8861A"},"GYFPA4":{"60Hz":"402ED10AC842041AB4B39AE8F2D81B2D7AEF9CB4"},"GZ2E01":{"16:9 Widescreen v2":"E7521ED27BFC972628906CBE8D5403ED57253BB8","Hyrule Field Speed Hack":"FCB673D46E716C7F63C618B8D8BF83AEE0B501F0"},"GZ2J01":{"16:9 Widescreen":"F985A0A58D8E2B23E8A557FAFF8D367AFFEADD07","Hyrule Field Speed Hack":"FCB673D46E716C7F63C618B8D8BF83AEE0B501F0"},"GZ2P01":{"16:9 Widescreen v2":"CAC38B0D334B925A57AA3118D35932B8A185137E","Hyrule Field Speed Hack":"0F63623D4D984B7706F718F57C0ABDB6DBADCF8D"},"GZ3E70":{"16:9 Widescreen":"167F9E9A9B372CB3A01F308B46FF1403F8599C51","Deinterlacing Fix":"2E163CB5FE724EB49B31CF607E5B9AFDA031DDD5"},"GZDP70":{"16:9 Widescreen":"2E424E0BBAE6EF5D6A8FB4224EA1D0746BAC37D3"},"GZLE01":{"16:9 Widescreen":"9FA864EE7DD8CE7FF538EB4E0243F20137430BD8","Remove Distance Blur":"78EA34CEF8E01701491C280F155F1C12EC9BF1A2"},"GZLJ01":{"16:9 Widescreen":"E03B61989025CA33937E63A057E6E40A403811BC"},"GZLP01":{"16:9 Widescreen":"3EFFF6C52B5633A1729FAA6883D8579E77F7D057","Remove Distance Blur":"14BECBEA4DD281EBD0F7FE7DEE8020B6F2418ACD"},"GZPE70":{"16:9 Widescreen":"7142F2495507AC7136992128ED0FCA6BC72B61F4"},"GZPP70":{"16:9 Widescreen":"591FD6C9668C79FF1CE8558EBED2486A7A327F05","60Hz":"A59B84DB5486521AEE1C23B6C741ECD35216E5AD"},"GZSE70":{"16:9 Widescreen":"8E86EAC7EA4F4D2854DD9020CD795630CA64C4EE"},"HAF":{"BufferPatch":"181195871F63B89B1CF09AFA4420CF89B9883108"},"HAL":{"RSAPatch":"AD12237401ABE9FE4A545AADB5C5AE10355E2076"},"R7XE69":{"Speed hack":"53F3273525BB719D535007FB97E7F381D808A8A9"},"R7XJ13":{"Speed hack":"4590D425BCBAFA0D1E32D27B46068843F6A2BE09"},"R7XP69":{"Speed hack":"53F3273525BB719D535007FB97E7F381D808A8A9"},"RB7E54":{"Limit internal frame rate in loading screens (fix hangs)":"BD1A252B43FD339391ED33554542E786BAD6671B"},"RB7P54":{"Limit internal frame rate in loading screens (fix hangs)":"90247F89DF8EB7A4AFA2C425CD3006257A95A8F8"},"RGQE70":{"crashfix":"5F4CF8D4DA19A0FF74FF9EB925AC0236069BFD59"},"RLEEFS":{"Fix crash on main menu":"793642AC6862C2F3412035A9E3D7172CC4A1D5C7"},"RM8E01":{"16:9 Widescreen":"E61344EB1542A78D497981C307B6549985C7A05A","Extra - Disable Music":"25223F9EFAABF601CAC7810004F124E4056598B1","QOL - Faster Boot Time":"BCC4279F8B28636AD773F01540E78DF40EAD6087","QOL - Increased Board Speed":"B65AF1819966CD3435D88801E8C79704E3A52DB5","QOL - Increased Taunt Capabilities":"66495D7CB532FAE778AFC22CF45D17D0FFDE5310","QOL - Increased Text Display":"B4186DDC54F33F4D6A22188EF50CEB43FB205673","QOL - Invert IR Stick for GameCube Mod":"9D90A9C66AE8AD91B201B40C4145D1323B701A77","QOL - Remove Explanations":"330DD53AB993A99576564FEFD222D7BD211B878F"},"RM8J01":{"16:9 Widescreen":"A140BDCB8E1721CB6B4CD878E412113322258B57"},"RM8P01":{"16:9 Widescreen":"F664C32AFD3D785FC6E04D8990A3FA1C72A18C5C"},"RMHE08":{"Bloom OFF":"CCF233DA57B3E75221870DE502955114B0D4E7FA"},"RMHJ08":{"Bloom OFF":"29D3625B7ED577587E56AA07CB0EB8C47C97E823"},"RMHP08":{"Bloom OFF":"1720C1173D4698167080DBFC4232F21757C4DA08"},"RO2P7N":{"Hangfix":"EEE9C8DE4671C18DD7F81DD08D39B64C57600DEA"},"RPBE01":{"Fix black screen effects":"775ABECA6073E02C5C68CF4D644194D966A418F5"},"RPBJ01r0":{"Fix black screen effects":"0EAB5D8DE827894AFEF97C10ACB67378E6983323"},"RPBJ01r1":{"Fix black screen effects":"4905E08643E9D00136F7EAF51978CF2F54D10D07"},"RPBJ01r2":{"Fix black screen effects":"4905E08643E9D00136F7EAF51978CF2F54D10D07"},"RPBP01":{"Fix black screen effects":"82AEB60F9A9083F93060531A970FFAABE0833A40"},"RRBE41r0":{"Idle loop speed hack":"20C7A2D4A3D6D55A8029A9D200D57CBD11F60B88"},"RRBE41r1":{"Idle loop speed hack":"0A30FA4C7E787197A00B7267368F372EFF623776"},"RRBE41r2":{"Idle loop speed hack":"2227787007F16F0CD454422AE6EB94656464B6D0"},"RRBJ41":{"Idle loop speed hack":"E9209EB728AA13375B2ABEF1C15D066DAFBF2EBF"},"RRBP41":{"Idle loop speed hack":"8A47BC311138EE3A11E049DF3EE6AED38990FB49"},"RTH":{"Disable blur":"812EE46AC967BFCD239335B10A664D71A93E8175"},"RX4E4Z":{"Fix file reads (dcache bypass)":"9E4E0F1465A9A1E85349DBA3B1278AC215A97DBB"},"RX4PMT":{"Fix file reads (dcache bypass)":"EE85907C03F0295794821383B93F8D5B91D2697A"},"RZDE01r0":{"Hyrule Field Speed Hack":"15EAD073414C9903D6CAE5229DCE582BD17A9162"},"RZDE01r2":{"Hyrule Field Speed Hack":"27395CC8BC2C51201D566657D31A471A850482FB"},"RZDJ01":{"Hyrule Field Speed Hack":"B3F7473F8C911A32F1D616491C9E78EBBD7A6309"},"RZDK01":{"Hyrule Field Speed Hack":"A280C0114B800D7DC056ECFB5E482229DA0B1550"},"RZDP01":{"Hyrule Field Speed Hack":"2A83ADFB760F9498841ED0ED68B0C0438232472C"},"SAOE78":{"Fix crash on boot":"EA11FA4908FB20B61876ACD360EC7657A6D39FB2"},"SAOEVZ":{"Fix crash on boot":"AA55C214DE7545DE0E203CC39F06BF3D31451BE9"},"SC2":{"Limit internal frame rate (speed hack)":"B3FB0FCE108E85E6198BAF3535850470049E2BE2"},"SGLEA4":{"Fix black screen":"258378187ACF475A55EFEAF8A703681252E014C3"},"SGLPA4":{"Fix black screen":"6F8CD59D897338CA90939149E1A62588620C6D88"}} \ No newline at end of file +{"D43J01":{"loophack":"CAB9CED2D904F12CCB21F5B1DE9B5433620C3E13"},"DPOJ8P":{"Bypass Modem Detection":"90BA66E25640A538FEFA6693715718139079FA7B"},"G2BE5G":{"Disable interlaced rendering":"7FFF6BDD93713BEDFD23739C32B86153FA19AEA0"},"G2BP7D":{"Disable interlaced rendering":"56E85D7285F10348E1E5354E379918D07E79EDA9"},"G2VE08":{"16:9 Widescreen":"3ED033396382424533A263A39687A0961EC994A6"},"G2VP08":{"16:9 Widescreen":"EEBC3C5F04BB70AFCA1A4C3D638335CDC9142BA2"},"G3RP52":{"16:9 Widescreen":"7F6B7743F0DDD3704B15882330E490103AE24E36","60fps":"4C9A8572A35F1DB85BBB2F32ED34288A343F1FC0"},"G3YP52":{"16:9 Widescreen":"3D102AFEE2F4945894E74BB702ED3ED2294C6FEC","Force PAL60":"FD61581C593EA34DD358AE33819FAB310F2CE961"},"G4AEE9":{"16:9 Aspect Ratio Fix":"8C2564CF47BB6A9B57D712C90E17F459B0BB6CCD"},"G4ME69":{"16:9 Widescreen":"6FC6E5D91693FAABE25CC721F2121CB0B5CA9D12"},"G5SE7D":{"16:9 Widescreen":"16119398BFE241A84151C046E0BC5BCF89D22049","Remove Bloom":"A5F2FB2B3BFF61F34F8AB1DD5A912A0FD8DFA720"},"G5SP7D":{"16:9 Widescreen":"718AA8BD831961C33114852FDA75BB58F768F46A"},"G8ME01":{"16:9 Aspect Ratio Fix - Centered HUD":"8C2FC3FC6F7766AA8E87425BF3BDD2E46E73DE71","16:9 Aspect Ratio Fix - Centered HUD with letterboxing":"AE3DBE2604CA0660165CA870C4B80E2B523C9475","16:9 Aspect Ratio Fix - Normal HUD":"F6E8264CF14D0189219C1E2D20C4182F190F4B88","16:9 Aspect Ratio Fix - Stretched HUD":"8EA4C7B80ADE3E8FEC28EEFA3A046B6B04162E81","No Letterbox":"B1DE2A3526F2E4511F2B94A5171BF7B3C2C52B9B"},"G8MJ01":{"16:9 Aspect Ratio Fix - Centered HUD":"B3181CA1AAB11EAE9132184DA48D76E775AC0A24","16:9 Aspect Ratio Fix - Centered HUD with letterboxing":"904C0EEEF16D761F7BDF7099DEB384DD9AB26E00","16:9 Aspect Ratio Fix - Normal HUD":"631CE99BDE3F1475303C00C67E3C130D4EB2547B","16:9 Aspect Ratio Fix - Stretched HUD":"81F7AD591F12A01DE82850457ECF147998D1238F"},"G8MP01":{"16:9 Aspect Ratio Fix - Centered HUD":"75AF5D7FA49BE9C3C73EA1482B49CD9B36CE817E","16:9 Aspect Ratio Fix - Centered HUD with letterboxing":"C2E5003E74551DF693A7CB814850CA51D77549EF","16:9 Aspect Ratio Fix - Normal HUD":"FB26AA84B0CB787705E84E869B649307776A2839","16:9 Aspect Ratio Fix - Stretched HUD":"C5F8A81520193418C07C7BC4881F02BE9C4DC9BC","No Letterbox":"7828F5B0C8B470620755C16C60A5A4554F92640C"},"G9SE8P":{"16:9 Widescreen":"CD043229AC47AC93D537B6A0725A2D0BB6FEF4E8"},"G9SJ8P":{"16:9 Widescreen":"C55EF90B542AA3973352A232629A828BC22A8509"},"G9SP8P":{"16:9 Widescreen":"9521774ADEE769CFCCE86F8170FE626387E73019"},"GAFE01":{"16:9 Widescreen":"D24F6D9BE5D79D3C795C2844634A0214BB68B5DA","Make Game Save Copyable (donny2112)":"F9A812FF62A20D5440CAB79DB6AFAE068457A10E"},"GAHEGG":{"Limit internal frame rate (speed hack)":"2873E5178C8068AFA8AFE751F903A69CA9A41F16"},"GAL":{"Trophy Viewer":"DBDB50216B22CDFFF77BDD80261CD0FF75803D3B"},"GALE01r0":{"Normal C Stick Functionality in Singleplayer Modes":"9DC8D90D986FAC175F45006AFF20CF00EDFBE053","Proper 16:9 Widescreen Support":"18B4159E77013EDFE499A33281B771C442970E3B","Properly Display in 4:3":"DC2BCA7D99EBDE1DC7C68CA6AC7F543B93FD6A67"},"GALE01r1":{"Normal C Stick Functionality in Singleplayer Modes":"F6030959C1CAC92F37287D556F18B3C5298FAD5B"},"GALE01r2":{"Disable Rumble":"CFDEEA8AD2A99394BFFEA7211EF03394E7471FA9","Normal C Stick Functionality in Singleplayer Modes":"BCD918A72368B2A30E797C76994E7539A1C0B5D9","PAL Stock Icons":"6B92D95F0EEA165EA84FD753F74B0A9E2079C2D7","Proper 16:9 Widescreen Support":"CEDF18354CDCFC49398551C629E51B053331A55B","Widescreen Support v1.2 [Dan Salvato]":"D32ED4CD685F3FF649F7E749E8C182C657013918"},"GALP01":{"Normal C Stick Functionality in Singleplayer Modes":"4817F202678559291F9F76B46DC7561A45D00B77","Proper 16:9 Widescreen Support":"BFCBE098FE8679B9140A48EA1D8620D5A369697C","Properly Display in 4:3":"5BA2933B8365E21553AA273B91954A4C722B1035"},"GAZE69":{"60FPS":"BC281053C5266B21FDDC6C8996A6021DEA03D459"},"GBLE52":{"16:9 Widescreen":"C0F3AB3BBC9B21F4BF25F44E48CF1CD36D2B3F45"},"GBLP52":{"16:9 Widescreen":"797040CB097BFD369490A1BE29659929D76CE6F7"},"GBRJ18":{"16:9 Widescreen":"B3C867AB34D90E2E9C5B799D800F4C191DE279FA"},"GBSE8P":{"16:9 Widescreen":"4148D453F61A5B81E53669335BC667E651865C76"},"GBSP8P":{"16:9 Widescreen":"6CB029AE768BA5B9995D5F12C1EBB37B3D1FE242"},"GC6E01":{"16:9 Widescreen":"DE932CCAD1B5EB1FAA8D08733BD0D3940C78382A","60 FPS [Nerdzilla]":"85F98064F17AFE0FB02A99A182AF3FEB7644DCAA","Allow Memory Card saving with Savestates":"2F64F98686E62B60E466E931A9EBCD19A750FF4E"},"GC6J01":{"60 FPS [Nerdzilla]":"A6146772E37970EA5564F51A622A04792158B321","Allow Memory Card saving with Savestates":"D8F327304A88FBC717BB1F775494C5F864B9E8D2"},"GC6P01":{"16:9 Widescreen [Ralf]":"05C9016BF58A628A3FD7B16E1B9BB0769A14846F","60 FPS [Nerdzilla]":"1D3FB017C0D20754E48A8BA54EEE7DC4851BE84B","Allow Memory Card saving with Savestates":"EDEE0E28EEA1834868F2865336290FFBDFB9C6DA"},"GC8JA4":{"Fix C4 texture tiling (used for buttons and some character icons)":"843297019804192AF1FC660BC85F4B10891D0BA3"},"GCBE7D":{"16:9 Widescreen":"478DA1D596D8513C343850719155813CB61A56DD"},"GCBP7D":{"16:9 Widescreen":"478DA1D596D8513C343850719155813CB61A56DD","60Hz":"DF2C4DDF082C9E67919443C5ACC485AB2CF7F8D0"},"GCCE01":{"16:9 Widescreen":"BA0066518E7EA8599A81F8496BD39DE20CC369D6","Fix GBA connections":"483BDB94615C690045C3759795AF13CE76552286","Fix buffer overrun bug (crash at Goblin Wall)":"6C107FEC15C76201233CA2645EB5FAB4FF9751CE"},"GCCJGC":{"Fix GBA connections":"4C104D24329172F5D0F8649DE9423B931FE72CA3"},"GCCP01":{"16:9 Widescreen":"2580E7379633CF4DE13B9EC945DB17543477828A","Fix GBA connections":"2EAA60A8A115AD68A795109FB59E4A726D29016D"},"GCN":{"Fix C4 texture tiling (used for buttons and some character icons)":"601FE183C9524ACCF068874DABD73921C86769CF"},"GCVEEB":{"16:9 Widescreen":"ADA686C90189D1D7D23E23E525EFC96EFA104BB9"},"GD7E70":{"Deinterlacing Fix":"6F8B6E33214162E5CDEBD2BC6A60FAFA04D2EB10"},"GD7PB2":{"Deinterlacing Fix":"3B798C9D63E755349B253FAF9186BAE1F703D96A"},"GDREAF":{"Fix audio issues":"F8EAE60FEB0CFB4477FDC4B9E136B63F68DFA63A"},"GDRP69":{"Fix audio issues":"E23D98B2CE185C3993A40F2495D37E41B971BF91"},"GEDE01":{"Fix startup hang":"21068C3CE905FB0CFFAA7408A93154AF8A5295A2"},"GEDJ01":{"Fix startup hang":"7061F3CF11BF64D3BA7F32CCF2BAC42FF3614AB6"},"GEDP01":{"Fix startup hang":"6F1B00517CBA30BEB738EAA90E71221378CD570D"},"GEME7F":{"Force Progressive Scan":"CB04E00918C9C0F161715D21D046ED6620F7ADEF"},"GEMJ28":{"Force Progressive Scan":"41D8F2C833C0B7B79FCA038752052059207AE4D5"},"GEZE8P":{"16:9 Widescreen [gamemasterplc]":"5CEBCFBEA4E444495D2FD6D8B6607DFB2349CC1B"},"GF7E01":{"16:9 Widescreen [gamemasterplc]":"C59CCA3EF8A5E97B32EB64DB9AE80E652ED281C6"},"GF7P01":{"16:9 Widescreen [gamemasterplc]":"1230053B5C347B62E432EFD6635433A183D18619"},"GFQEA4":{"16:9 Widescreen":"5CD9568CE58EF82EB371594667015C9B799454B9"},"GFZJ01":{"Make Save Copyable":"F659D22CB1DFF15C3915D7630D838EED8DB0BA48"},"GFZP01":{"Make Save Copyable":"F659D22CB1DFF15C3915D7630D838EED8DB0BA48"},"GGTE01":{"16:9 Widescreen [darkludx]":"EF128E7A9C22676834F558BA0F0F7FD8B9028727","Experimental 60fps":"D40344111D989EA009901F8B1C45B5AC8D39E6D2","Simple 60FPS":"5232A937D1D813FF58DD71D716284ED6AB535689"},"GGTJ01":{"Experimental 60fps":"BEC2310911003AF9E4B984A4051E0F885B8CC825","Simple 60FPS":"D62E777A2F019D7BD0AFFBCE876BD9AE408F1667"},"GGTP01":{"16:9 Widescreen":"FA9CD330ECDA01275DA88BD0803DE47757D16A4E","Experimental 60fps":"EB1ACD613BB432A3391CFFF1F0145A6ACE66B210","Simple 60FPS":"43FAD0DDD130BE1E4C8C7603EF6CA7DAA0DF5EE9"},"GGVD78":{"16:9 Widescreen":"9D07DBB5EC2FAA47F2E4587FBD75FD6F3E7E91B0","EFB Copy Fix":"FE52240DF6D132C15A8324E8A477F2BF2250D208"},"GGVE78":{"16:9 Widescreen":"86E561452235BF88D41884558EF34F54CE0FEB48","EFB Copy Fix":"5E38E10829D5F77243C95E9E41518BB3ADE24139"},"GGVP78":{"16:9 Widescreen":"F9B2108D833084FA36A53E00F1647A9579F847D3","EFB Copy Fix":"5E38E10829D5F77243C95E9E41518BB3ADE24139"},"GGVX78":{"EFB Copy Fix":"740F2D1C01DA39D1760D96B03974A48E6F74578D"},"GHAE08":{"Fix audio issues":"9799AFF8463EC86C9230E31E2627E141F0C129D3"},"GHAJ08":{"Fix audio issues":"B45A8FC32D14567B8D6C95F303E00A72C0E1D344"},"GHAP08":{"Fix audio issues":"BC7F3CFC97593AA2055C370C175950DC478D2709"},"GHKD7D":{"Limit internal frame rate (speed hack, also fixes audio and gameplay bugs)":"1AF09E98F0B72833A0F4E519EC3D4130C36D615E"},"GHKE7D":{"Limit internal frame rate (speed hack, also fixes audio and gameplay bugs)":"9BFBDE9184BC05EBD545625DEE486E3AAB36B6A3"},"GHKF7D":{"Limit internal frame rate (speed hack, also fixes audio and gameplay bugs)":"919E853513192C97F3CF49246A65ECBF39E7C201"},"GHKP7D":{"Limit internal frame rate (speed hack, also fixes audio and gameplay bugs)":"1AF09E98F0B72833A0F4E519EC3D4130C36D615E"},"GHKS7D":{"Limit internal frame rate (speed hack, also fixes audio and gameplay bugs)":"919E853513192C97F3CF49246A65ECBF39E7C201"},"GHLE69":{"16:9 Widescreen":"742BFC79D8F0BA5D6215772B58F5A0EADD7BFAFF"},"GHQE7D":{"16:9 Widescreen":"520E5F718D3BD1291C55021776091E0DE0FB4822","Limit internal frame rate during startup (speed hack)":"F6BF450D22104FD2527122EA6E81B1F70E916B95"},"GHQP7D":{"16:9 Widescreen":"AAE14CDC13A0C082A850DED85417100A8C8A0687","60Hz":"884A33613AE8D916128E3FF39B3AA9F63DAADC58","Limit internal frame rate during startup (speed hack)":"BD475ADEF145AC9226514CD1B2D4D5F3BFE67964"},"GHSE69":{"16:9 Widescreen":"3538CDBD13FA939B7BA5F0F82253401AFDD1E2CD"},"GHSP69":{"16:9 Widescreen":"409754E2EBB6F05DEE1AFC647E25B15D462638FF"},"GICD78":{"EFB Copy Fix":"3A94591A149AE88C150AB3320BBC909FE54BAEA5"},"GICE78":{"EFB Copy Fix":"5BF55685B8867A85EAA9C86571309B17BF7DED32"},"GICF78":{"EFB Copy Fix":"85AABAEB9A59C4F96D9330A3B884F6D757DA1683"},"GICH78":{"EFB Copy Fix":"3A94591A149AE88C150AB3320BBC909FE54BAEA5"},"GICJG9":{"EFB Copy Fix":"969134EA21A160EBDA91C0870266E7D1707FDC43"},"GICP78":{"EFB Copy Fix":"13B158CF41F5412BC637F50644193D43CC3DA49A"},"GIQE78":{"EFB Copy Fix":"E15AA1E30D26E5735D68AAADE436E7B7E4A33A35"},"GIQJ8P":{"EFB Copy Fix":"FFFCB76E98DDB06A7BBBC0AA73C869C87EB787D6"},"GIQX78":{"EFB Copy Fix":"485DA99FAB35646DAA2A138B0315361495ABE778"},"GIQY78":{"EFB Copy Fix":"485DA99FAB35646DAA2A138B0315361495ABE778"},"GK2":{"16:9 Widescreen [Vague Rant]":"6B4C59C2A2C5D71C7A38C8513A76E6467E307A26"},"GK2E52":{"60 FPS":"8F2397930A50C3C176188526EB9612578F9CBCE5"},"GK4":{"16:9 Widescreen":"4652969A4DA869FD28F2CAA3869A38F5C2AAFEB1"},"GKB":{"16:9 Widescreen Region-Free":"4652969A4DA869FD28F2CAA3869A38F5C2AAFEB1"},"GKBPAF":{"60Hz":"8E4E0ABA0E6D102A33206F34F4DEE63159B3CB4F"},"GKDP01":{"16:9 Widescreen":"DF4657937DE730107B636C73E959277EB963D210","60Hz":"6740D7B914CC897AF50798C0AB391965294FD1E1"},"GKRPB2":{"16:9 Widescreen":"69C01A4F91D991CF866237FED94A138308FC104F","60Hz":"40D06A5C7A3D873ABC73DEDF573738C2E3E37FF0"},"GKWJ18":{"16:9 Widescreen":"696570101FA040778EAD310377C484C846D87430"},"GKYE01":{"16:9 Widescreen":"6520EF1B7D88F00747B120A3A010458602ED989D"},"GKYJ01":{"16:9 Widescreen":"47B8EF7D02831AA5C375C698797BF2D5475FEFF2"},"GKYP01":{"16:9 Widescreen":"69413C75036D2975716066E6574461B981FF0124"},"GLEE08":{"Fix audio issues":"7355F358CAC6F418D37E4C23E64F7867D46E4FC9"},"GLEJ08":{"Fix audio issues":"12B24A6D7389A2AC5AB75FC0BF8493E7661F2A73"},"GLEP08":{"Fix audio issues":"81BD39F5527552DE89E3B59BA86298900F0A3168"},"GLSD64":{"Fix freeze in opening cutscene":"5E2A73717BD66EF647846DD64C33BC80AD9B5227"},"GLSE64":{"Fix freeze in opening cutscene":"1CE78E7954415A44DF693C0BB879AA5A4FF059A3"},"GLSF64":{"Fix freeze in opening cutscene":"009B0C4AD80A9C28C987934D254C2C4AACC9A07A"},"GLSP64":{"16:9 Widescreen":"8E7A544C10E7A5E2F0304A0D2586879627EF6586","60Hz":"B67144E87B54246137142992A3BC83DC13BE68A7","Fix freeze in opening cutscene":"3D0894616C9A7FA5ED91C1D2F461BF14DF47ECEC"},"GM4E01":{"16:9 Menu Backgrounds Add-On":"87D1A6A3E29ADA03B0D29C2F1841C18E62DB0A15","16:9 Widescreen v2":"78BE50F93E81A1972CA31ABC318949E366E82BD0"},"GM4P01":{"16:9 Menu Backgrounds Add-On":"87D1A6A3E29ADA03B0D29C2F1841C18E62DB0A15","16:9 Widescreen v2":"6D950B6EEFD6D304E1A424355B74A595D32BDF2F"},"GMBE8P":{"16:9 Widescreen":"D12DE9E3941BCE6EB50B8DA92140E09AFC0104C8","NA Stretched HUD":"0151A6683E1FBFD20096807C54A6952C4A4BAD40"},"GMBP8P":{"16:9 Widescreen":"8A688981F33A2C53882EF08FCF20B88AD43EF417"},"GMNE78":{"Limit internal FPS to VPS (improves performance)":"DE38BC8493EA24F93B6D805F28746AA99C53C677"},"GMNP78":{"Limit internal FPS to VPS (improves performance)":"65FB9B430F7D58EBC76DAADE8CA9DBBAA32B8B51"},"GMOP70":{"16:9 Widescreen":"CE4D298616BD42E4D8F8936B325CD1FD7F5B956B","60Hz":"0CD2CC787A5FF551901E41C85C8AAC02017ECB89"},"GMPE01":{"16:9 Widescreen":"4F98592DB3DEE3857469A8D8605FAF4BD6F7C76D","QOL - Allow Digital Presses for Map Screen":"E232B27564E9AA0C32DE163C9C056317A7B2B12E","QOL - Automatically Advance Text Boxes":"59607671BFC4717ACAF9807BB7EB0D9F982866D4","QOL - Disable Advance on Results":"CAEA37F3FEF89400513353EB85875F2A3AF4C03E","QOL - Faster Boot Time":"F75FBBD838C5B84FF687962FBA9195B217DE132C","QOL - Increased Board Speed":"19F264DE7F07EAC9433CA4B591BEBA1EC976C9F1","QOL - Increased Taunt Capabilities":"C70391D4961A0E820DE40141C89341369A9F021B","QOL - Instant Text Display":"F4E6913CF034E5778B9F9CA5FF448FF1B78B3333","QOL - Rumble Always Off":"93621947019532F02C25937FD3EEEE21A788CB07","QOL - Show Controller Port Number of Who Paused":"D7249AC3C949FEB860CF4350C5B7B79AC16569F1"},"GMPJ01":{"16:9 Widescreen":"A795811F2F0C92D9DCABDE97D9E39B47B1DBCEFD"},"GMPP01":{"16:9 Widescreen":"A795811F2F0C92D9DCABDE97D9E39B47B1DBCEFD"},"GMSE01":{"60FPS":"2805B1A0DD53EB64877D375D10F667700955720F","Widescreen":"BD718F961DBA5372B1D0257D454D535746C453A0"},"GMSJ01":{"16:9 Widescreen":"E8112A01040A06460E368F142C5D1FD0B4085D94"},"GMSJ01r0":{"60FPS":"9894B5B6B5215844D48411021FF8EECFE851D79D"},"GMSJ01r1":{"60FPS":"2DB69DB7A3753D543CD85CA4C77B4EF0AED7486E"},"GMSP01":{"60FPS":"D07009B710B3BBC6B12E54ED6A7969D58197EDAF","Widescreen":"0B7B89BF0868393076EF5F9DBD689DD0EDBCB84C"},"GNHE5d":{"Nop Hack":"89393A24E2336841AA4CD0AD3BE1C9A66B89E9EF"},"GOCE5D":{"16:9 Widescreen":"E4D800B90F16A15D9252EED1B2A23AEAF5CD230A"},"GOME01":{"16:9 Widescreen":"C33CBBF6F22195BF626104B4827200B3EE1CF30C"},"GOMP01":{"16:9 Widescreen":"874784CCD4AC3DC9C69654E471C18AD0F5E4D9AE"},"GONE69":{"Widescreen Hack Culling":"6412A67E1C26E146A9526AFC9F0EE517B214069D"},"GP4J18":{"16:9 Widescreen":"BF4D2D6AF66F285E81173B3B20D5369DB6FB351B"},"GP5E01":{"16:9 Widescreen":"5ED053787332DB5EEB8B963BA5DF197B58C6BB75","QOL - Automatically Advance Text Boxes":"41EF84663008668682BB75DC8B874E38669AE041","QOL - Disable Advance on Results":"6C36BEFE751131298BC8B39012892F6A6903CE60","QOL - Faster Boot Time":"8E952E6E12639AC20F6F9FDD150C12F0C294DF43","QOL - Increased Board Speed":"4BD72B8ED75ED8EFB3329C104BAD114FDDB8AD2C","QOL - Increased Capsule Throwing Speed":"C5BA3C9D386D09DD6CB9242A12A0D041BEB93160","QOL - Increased Taunt Capabilities":"C360EBDDCB0237076052C983BD9719411CA67CDE","QOL - Instant Text Display":"2CD4A06A3B9C18CC9EA2A2DEBD96E066CD1D700A","QOL - Show Controller Port Number of Who Paused":"5BA3648D18346EDC97B23475D4748C637E6095A2"},"GP5J01":{"16:9 Widescreen":"81E69B6BEE85E06805EC24E1CFEA9405BF459DF8"},"GP5P01":{"16:9 Widescreen":"FD4FCCB97C06F0173A30D4CC9A99422B2C0ABA9B"},"GP6E01":{"16:9 Widescreen":"B502AF0887792E9B140516D14BA75F99772C17BE","QOL - Auto Advance Text Boxes":"E645DF70CE0266D174D917A817A7FBEEE974A9F0","QOL - Disable Advance on Results":"798E566B621F6A32BF23C588E76EAC0776E2A8A3","QOL - Faster Boot Time":"B089A3C80D5DA86ABF6258F8BFB1DC78BB54A973","QOL - Increased Board Speed":"501C52ACF117950888A66DB2BEDBDFD7D9B20235","QOL - Increased Orb Throwing Speed":"845F439278DA8CBC225658FF4E2F82D707422BFB","QOL - Increased Taunt Capabilities":"0AED27341A06186AD92D5725C0B9693CA8F85B7B","QOL - Instant Text Display":"5AAC4E21927D4AEE7AC329CE793D4CDAEDDF7A3F","QOL - Show Controller Port Number of Who Paused":"DF5D2F068D76ABF2B1C294D413B9154B8C356929"},"GP6J01":{"16:9 Widescreen":"88F50F8298F82E3E5C161277BD4A985CE893A9D0"},"GP6P01":{"16:9 Widescreen":"DCCE59CA987624C753F0A86BEBA4287635901C93","Remove Black Bars":"138A86D43B5830BFE1926F58C0A4FBE2971BB02D"},"GP7E01":{"16:9 Widescreen":"87EBF72D90503EBC5CE9BC994795669E48A92A4A","QOL - Auto Advance Text Boxes":"82338AB5D82A7F398B4EB674CA4866DD1F4A1E65","QOL - Controller Options Always Acesssible":"D2F9CC0B9E52136E77187395FB7DA9B64B2C3B30","QOL - Disable Advance on Results":"A644551162A61DE7997B2A84F5BFDEFFD3FC2FB5","QOL - Faster Boot Time":"1939B5C575AE8FF6890BDDDD1B3FEA472D8CABA0","QOL - Increased Board Speed":"7E06A2EBCFECADB8074152B489984237A6FE9F21","QOL - Increased Orb Throwing Speed":"6671BEE71920D6B845AE1257AFE3AB3B95CD6FBD","QOL - Increased Taunt Capabilities":"9F60923F95FFE709CCD06966CD2DF743263934D1","QOL - Instant Text Display":"48FA6002E42DA9BB83ABC980A32C60CE3B21C4FC","QOL - Show Controller Port Number of Who Paused":"5E6F8C6C87D5944DB18A4E4F9A45F61EE87A4163"},"GP7J01":{"16:9 Widescreen":"A081F0729068D233E99DC00C64E36CA33C945640"},"GP7P01":{"16:9 Widescreen":"75D6CDA4EA301A71F7701A0487544E79136850B9","60Hz":"6D0D5B7CA58C38A3147F8ED981B5B21CC6C519CD"},"GPIE01":{"No Blur":"A25CDDB79991F090BD7F12840AD06F13BD5CCF95"},"GPIE01r0":{"16:9 Widescreen":"2B58166A66644F984E64077A6245C94C79B51063"},"GPIE01r1":{"16:9 Widescreen":"9A1545AB4E2B9216B95AFFA83420D723512DA8C8","60FPS":"3337C767EAA21D30C6CFEAE9985FFCABFC63E2E3","Disable Pikmin optimizations":"CBD15E9104929F0631713AE482475CB2B90E71F2"},"GPIP01":{"16:9 Widescreen":"5AE44D5B0E0D4C412B453B95CF5A41DBA4D685E6","60Hz":"AE59FF751E167632AE283F38CC4B96BDF7B9B81F","Turn off blur":"4ED79A548DBD7DBD35928A2F1138315FF103E260"},"GPNE08":{"16:9 Widescreen [Ralf, darkludx]":"ED3D9BB08C5F1D21BC8D5C73155C00E3C25C466F"},"GPNP08":{"16:9 Widescreen [Ralf]":"469B18FE8219031D355557B836EF02B625040A4F"},"GPOE8P":{"Make Save Copyable NTSC Port - 1.0\/1.1":"7A4B3E596BA4FDA8F3FCF984079B3F44CB2D6AB3","Make Save Copyable NTSC Port - PLUS\/1.2":"304DB311F2107E88EBCE058535B266F9263AA8E2","Save Validation Code v 1.0\/v1.1":"9F6259132453DCC0607EAB35DB182C76818F2F9F","Save Validation Code v1.2\/Plus":"17EB6CFB408EF27D44C053A1336C3B87B6A05018"},"GPOE8Pr0":{"16:9 Widescreen":"99986BB1D4ABE45C429D48B01BFB578FEA69C14F"},"GPOE8Pr1":{"16:9 Widescreen (Plus) [Ralf]":"5563671A6702785FFE106DAB7EF3F4FE6D9F705B"},"GPOP8P":{"16:9 Widescreen":"DF133C61C29D5CFA87A2A785C962C205F80E6D04","Game Save Valid":"40EC1590DB26C7C58D00E3065F1E404341EF0E73","Game Save copyable":"2F5FB98927DAFF141D1CCD1EACA8AF626397E284"},"GPVE01":{"16:9 Widescreen":"E5B51080CFD518FE584CF3B61A1099CD032479D6","60 FPS":"ADF5E3BBF0002A76949D0C11C51E58089BACFEED"},"GPVP01":{"16:9 Widescreen":"78F3C9A789827B063A6701987262276A66ABD82B"},"GQPE78":{"EFB Copy Fix":"880B114E9A308084CAB92C004A9EE067B371C310"},"GQPP78":{"EFB Copy Fix":"5D9A14954AE8D639C9B254F3BA73A70F284BBC8D"},"GQSDAF":{"16:9 Widescreen":"CA82C44B2E8FC5C184E3FF935BC89661B7DB55D6","60Hz":"952165FD78543EB6D2F5230F7570B0513773D332","No Blur":"DEB7DF358423F0EF30C9FD49F4F14590836D52A6"},"GQSEAF":{"16:9 Widescreen":"48AFE1D32843C6B5AD4337A49F15FD447DF2A752","Remove Blur":"EF448CF1FA6A15EB2661EA5338703C13D52EF65B"},"GQSFAF":{"16:9 Widescreen":"76C30E1737CC5C3B5DE32532B5F9A5CD50B690F8","No Blur":"986BAE5103CDE9286D2D34FD28FE2540D0759AAB"},"GR2E52":{"16:9 Widescreen":"5F55CE7DA7E1E3261CF2FF88F34CDA63BA511003"},"GR2J52":{"16:9 Widescreen":"D3C6FA690BED07BFA65C2E1FCDE2FFA5AA0EEEE4"},"GR2P52":{"16:9 Widescreen":"D7BCADD4E76B5E3F7D9D463F55A2777528E37E94"},"GRNE52":{"16:9 Widescreen":"483D74C47AD1012606D591A226AB3144C7FB201C"},"GRNJ52":{"16:9 Widescreen":"949281B7221B20680B7BC29E4754B73A326EBE85"},"GRNP52":{"16:9 Widescreen":"11051B094FE5A8B2E73060BFF786C1588E36979A"},"GROE5Z":{"16:9 Widescreen":"FADBAB5EC280CF8ED4C9536A33F4184BA210C9B0"},"GRYE41":{"Disable Culling to Fix Rise and Shrine Hang":"AF0A575EB6071EAC0D2EC3D2EA30A23EB05A4192"},"GSAE01r0":{"viWidth 704 Aspect Ratio Fix":"0D529180B9B28BB06E21EDBDBA61C17EEF0FFB7F"},"GSAE01r1":{"viWidth 704 Aspect Ratio Fix":"CB15ED22625690A5DBE4607FE30160125421461D"},"GSAP01":{"viWidth 704 Aspect Ratio Fix":"749EDA62B1B73354599929F1B50E992E111C5493"},"GSNE8P":{"16:9 Widescreen":"CFDF3FA5B48B347E49E8E521D7BE47FCC9A5CBF4","60Hz Aspect Ratio Fix":"D90F66C0D46D9BEF27C8E13BC8804DB1F382C8B1"},"GSNJ8P":{"60Hz Aspect Ratio Fix":"98DF9D67DE77F66A4B09F25C5621805DEB40865B"},"GSNP8P":{"60Hz Aspect Ratio Fix":"D90F66C0D46D9BEF27C8E13BC8804DB1F382C8B1"},"GSO":{"16:9 Widescreen Region Free":"0D60D0593F6DA28B1236381B22082506B9533F0E"},"GSPE69":{"16:9 Widescreen":"80E18A8963F4EFD3C03494C95934452FCB6E521B"},"GSPP69":{"16:9 Widescreen":"162E87E9F5511CD82216811055836C11B374C45B","60Hz":"E5DF2DF34D2F0BDEE4205C891576511EC572C5DC"},"GSWE64":{"16:9 Widescreen":"6480326CCA8FF64A4868EC6E9FDE9F38819A75A1","Disable Dithering":"85F65E4B627641862C1A6091D29A3BB0626B04C3"},"GTEE01":{"16:9 Widescreen":"6B57EBCB9CC0ACE2EDA0F13E3F1F55F3FABC3A26"},"GTEP01":{"16:9 Widescreen":"72785784363C46180AF8E388348FD77667E7D382"},"GTOJAF":{"Remove Blur":"53A2EDF113F2ED7E54A16AA0E73FDB2C44C79DE5"},"GTRE78r0":{"Limit internal FPS to VPS (improves performance)":"42B85EFC5DEF8B243521EAD434DDCBDF95664CB1"},"GTRE78r1":{"Limit internal FPS to VPS (improves performance)":"ADB3A41B992EAB15AE484B2E575ACF3354415186"},"GTRJ8N":{"Limit internal FPS to VPS (improves performance)":"47DBEFDCF22ADC2AB148A54AC885FE19B3C07E3F"},"GTRP78":{"Limit internal FPS to VPS (improves performance)":"E8752E1B60DF76CD0CC7408074E742B0966BC904"},"GTZE41":{"16:9 Widescreen":"ECCE87E0006475C73E7D936AA0150BD20166F9EF"},"GTZP41":{"16:9 Widescreen":"62D8F159B93167171E0860D96C4BB32A5BF5648B"},"GU2D78":{"EFB Copy Fix":"CFF4C3F932B08732627572EDA1A0CD2D9C71AE0C"},"GU2F78":{"EFB Copy Fix":"CFF4C3F932B08732627572EDA1A0CD2D9C71AE0C"},"GU3D78":{"EFB Copy Fix":"8A0E3114862ADFE421874211BD6F5220AA425BF5"},"GU3X78":{"EFB Copy Fix":"E3303FDAE7ECA17A72EDC440C32D94648A6453A0"},"GU4Y78":{"EFB Copy Fix":"D54767785E139A8BC8C4B75573FBD5A0B686D8E3"},"GUNE5Dr0":{"16:9 Widescreen":"C942EBCBE8A487C25E296EC1FAC2358DA1487DBD","60 FPS":"A441630EC5FF0EB74D2243A3092D22E69C6BEA02"},"GUNE5Dr1":{"16:9 Widescreen":"39BD84CBE2AFACFEDEC5E9020D1A8B0D36DD53F9","60 FPS":"05779F1A3D0C43305D52A95447D612CB424942C0"},"GUNP5D":{"16:9 Widescreen":"FE3BA1DAA1AF278A7839E27BF466B0BA0B390EC2","50 FPS":"3B20499A3F8D1D7CCA5B0015F2D80ECED25842A6"},"GV4E69":{"Fix 2D Rendering":"8679891FCAA250FCFF670B26E0CB9875900D17FD"},"GVJE08":{"16:9 Widescreen":"09EFDA75D876A675121C8344D8FDD09A70A1A846"},"GVJP08":{"16:9 Widescreen":"93938F4C6112C91549F2B52E6259170F7501EC07"},"GVPE69":{"Fix 2D Rendering":"3159CA79B0A890131763EA6CB163684BEE886E3F"},"GVSE8P":{"16:9 Widescreen":"4CE9C491160A4B631142EE9CE802C694163F1CA3"},"GWRE01":{"16:9 Widescreen":"AC42770B06662BE1DC863EC80F44B5E034C63664"},"GWRP01":{"16:9 Widescreen":"9DDDFAB28C4BD35CF64050E1EF684DC042B1AFFA"},"GWWE01":{"16:9 Widescreen":"98B2E75D8E1CED4A964D3129A5DC10E30538CAA6"},"GWWJ01":{"16:9 Widescreen":"2DAD9A5E2A140F02CCBA727C4BE7C74BAC156778"},"GWWP01":{"16:9 Widescreen":"2DAD9A5E2A140F02CCBA727C4BE7C74BAC156778"},"GWZE01":{"16:9 Widescreen":"9EFC191DE6D21A1681FE241AB2EE4A131259F317"},"GXCE01":{"16:9 Widescreen":"901A1E78A3A0124F55548507D3B3707125C64A8A"},"GXSE8P":{"16:9 Widescreen":"F50BBA440184FC77A4DFFAA58FF2BB888E2E072F","Aspect Ratio Fix":"4214C74DFB8A74FC3AA4A643E869BC4D9A38EDA0"},"GXSJ8P":{"Aspect Ratio Fix":"227909607984BBC3D36AAC7DB9DFE385F3363C49"},"GXXE01":{"16:9 Widescreen":"7CAFDAD7B5E7459CCC1BB209D439DDCBB5BE4E4E","60 FPS":"7E2829049003FC9DC8BC28044B33CAFF3768B54C","Allow Memory Card saving with Savestates":"64FAA15062F0D0C319F904BBDE9C4489A25D6369"},"GXXJ01":{"16:9 Widescreen":"AF704A8C6838FDF47054D9EDD9106B3F46781FA9","60 FPS":"4F5FD45B4EC1B33FE076FA06F8FF863C46A06BBA","Allow Memory Card saving with Savestates":"8293802260536FA2EF2EFDAB5266DE36BB88DE1B"},"GXXP01":{"16:9 Widescreen":"02716B2585BEE74F8FCDD97A78F6A0D3DC7F331B","60 FPS":"BF6171EA5CCF4B57AA596372589DDB5E6904DD7A","Allow Memory Card saving with Savestates":"3CAFBC4AE6FC5CE9F53377F86AB5BD8F1BC8861A"},"GYFPA4":{"60Hz":"402ED10AC842041AB4B39AE8F2D81B2D7AEF9CB4"},"GZ2E01":{"16:9 Widescreen v2":"E7521ED27BFC972628906CBE8D5403ED57253BB8","Hyrule Field Speed Hack":"FCB673D46E716C7F63C618B8D8BF83AEE0B501F0"},"GZ2J01":{"16:9 Widescreen":"F985A0A58D8E2B23E8A557FAFF8D367AFFEADD07","Hyrule Field Speed Hack":"FCB673D46E716C7F63C618B8D8BF83AEE0B501F0"},"GZ2P01":{"16:9 Widescreen v2":"CAC38B0D334B925A57AA3118D35932B8A185137E","Hyrule Field Speed Hack":"0F63623D4D984B7706F718F57C0ABDB6DBADCF8D"},"GZ3E70":{"16:9 Widescreen":"167F9E9A9B372CB3A01F308B46FF1403F8599C51","Deinterlacing Fix":"EF1291C0E45277CDAE4D0F61E1949C1E75E5A3E1"},"GZBJB2":{"Deinterlacing Fix":"19D67BD12A18F0E3A960BBB92E2F490BEF5C00C1"},"GZDP70":{"16:9 Widescreen":"2E424E0BBAE6EF5D6A8FB4224EA1D0746BAC37D3"},"GZLE01":{"16:9 Widescreen":"9FA864EE7DD8CE7FF538EB4E0243F20137430BD8","Remove Distance Blur":"78EA34CEF8E01701491C280F155F1C12EC9BF1A2"},"GZLJ01":{"16:9 Widescreen":"E03B61989025CA33937E63A057E6E40A403811BC"},"GZLP01":{"16:9 Widescreen":"3EFFF6C52B5633A1729FAA6883D8579E77F7D057","Remove Distance Blur":"14BECBEA4DD281EBD0F7FE7DEE8020B6F2418ACD"},"GZPE70":{"16:9 Widescreen":"7142F2495507AC7136992128ED0FCA6BC72B61F4"},"GZPP70":{"16:9 Widescreen":"591FD6C9668C79FF1CE8558EBED2486A7A327F05","60Hz":"A59B84DB5486521AEE1C23B6C741ECD35216E5AD"},"GZSE70":{"16:9 Widescreen":"8E86EAC7EA4F4D2854DD9020CD795630CA64C4EE"},"HAF":{"BufferPatch":"181195871F63B89B1CF09AFA4420CF89B9883108"},"HAL":{"RSAPatch":"AD12237401ABE9FE4A545AADB5C5AE10355E2076"},"R7XE69":{"Speed hack":"53F3273525BB719D535007FB97E7F381D808A8A9"},"R7XJ13":{"Speed hack":"4590D425BCBAFA0D1E32D27B46068843F6A2BE09"},"R7XP69":{"Speed hack":"53F3273525BB719D535007FB97E7F381D808A8A9"},"RB7E54":{"Limit internal frame rate in loading screens (fix hangs)":"BD1A252B43FD339391ED33554542E786BAD6671B"},"RB7P54":{"Limit internal frame rate in loading screens (fix hangs)":"90247F89DF8EB7A4AFA2C425CD3006257A95A8F8"},"RGQE70":{"crashfix":"5F4CF8D4DA19A0FF74FF9EB925AC0236069BFD59"},"RLEEFS":{"Fix crash on main menu":"793642AC6862C2F3412035A9E3D7172CC4A1D5C7"},"RM8E01":{"16:9 Widescreen":"E61344EB1542A78D497981C307B6549985C7A05A","Extra - Disable Music":"25223F9EFAABF601CAC7810004F124E4056598B1","QOL - Faster Boot Time":"BCC4279F8B28636AD773F01540E78DF40EAD6087","QOL - Increased Board Speed":"B65AF1819966CD3435D88801E8C79704E3A52DB5","QOL - Increased Taunt Capabilities":"66495D7CB532FAE778AFC22CF45D17D0FFDE5310","QOL - Increased Text Display":"B4186DDC54F33F4D6A22188EF50CEB43FB205673","QOL - Invert IR Stick for GameCube Mod":"9D90A9C66AE8AD91B201B40C4145D1323B701A77","QOL - Remove Explanations":"330DD53AB993A99576564FEFD222D7BD211B878F"},"RM8J01":{"16:9 Widescreen":"A140BDCB8E1721CB6B4CD878E412113322258B57"},"RM8P01":{"16:9 Widescreen":"F664C32AFD3D785FC6E04D8990A3FA1C72A18C5C"},"RMHE08":{"Bloom OFF":"CCF233DA57B3E75221870DE502955114B0D4E7FA"},"RMHJ08":{"Bloom OFF":"29D3625B7ED577587E56AA07CB0EB8C47C97E823"},"RMHP08":{"Bloom OFF":"1720C1173D4698167080DBFC4232F21757C4DA08"},"RO2P7N":{"Hangfix":"EEE9C8DE4671C18DD7F81DD08D39B64C57600DEA"},"RPBE01":{"Fix black screen effects":"775ABECA6073E02C5C68CF4D644194D966A418F5"},"RPBJ01r0":{"Fix black screen effects":"0EAB5D8DE827894AFEF97C10ACB67378E6983323"},"RPBJ01r1":{"Fix black screen effects":"4905E08643E9D00136F7EAF51978CF2F54D10D07"},"RPBJ01r2":{"Fix black screen effects":"4905E08643E9D00136F7EAF51978CF2F54D10D07"},"RPBP01":{"Fix black screen effects":"82AEB60F9A9083F93060531A970FFAABE0833A40"},"RRBE41r0":{"Idle loop speed hack":"20C7A2D4A3D6D55A8029A9D200D57CBD11F60B88"},"RRBE41r1":{"Idle loop speed hack":"0A30FA4C7E787197A00B7267368F372EFF623776"},"RRBE41r2":{"Idle loop speed hack":"2227787007F16F0CD454422AE6EB94656464B6D0"},"RRBJ41":{"Idle loop speed hack":"E9209EB728AA13375B2ABEF1C15D066DAFBF2EBF"},"RRBP41":{"Idle loop speed hack":"8A47BC311138EE3A11E049DF3EE6AED38990FB49"},"RTH":{"Disable blur":"812EE46AC967BFCD239335B10A664D71A93E8175"},"RX4E4Z":{"Fix file reads (dcache bypass)":"9E4E0F1465A9A1E85349DBA3B1278AC215A97DBB"},"RX4PMT":{"Fix file reads (dcache bypass)":"EE85907C03F0295794821383B93F8D5B91D2697A"},"RZDE01r0":{"Hyrule Field Speed Hack":"15EAD073414C9903D6CAE5229DCE582BD17A9162"},"RZDE01r2":{"Hyrule Field Speed Hack":"27395CC8BC2C51201D566657D31A471A850482FB"},"RZDJ01":{"Hyrule Field Speed Hack":"B3F7473F8C911A32F1D616491C9E78EBBD7A6309"},"RZDK01":{"Hyrule Field Speed Hack":"A280C0114B800D7DC056ECFB5E482229DA0B1550"},"RZDP01":{"Hyrule Field Speed Hack":"2A83ADFB760F9498841ED0ED68B0C0438232472C"},"SAOE78":{"Fix crash on boot":"EA11FA4908FB20B61876ACD360EC7657A6D39FB2"},"SAOEVZ":{"Fix crash on boot":"AA55C214DE7545DE0E203CC39F06BF3D31451BE9"},"SC2":{"Limit internal frame rate (speed hack)":"B3FB0FCE108E85E6198BAF3535850470049E2BE2"},"SGLEA4":{"Fix black screen":"258378187ACF475A55EFEAF8A703681252E014C3"},"SGLPA4":{"Fix black screen":"6F8CD59D897338CA90939149E1A62588620C6D88"}} \ No newline at end of file diff --git a/Data/Sys/GameSettings/GD7E70.ini b/Data/Sys/GameSettings/GD7E70.ini index 991bf5493881..485c1c86a6ee 100644 --- a/Data/Sys/GameSettings/GD7E70.ini +++ b/Data/Sys/GameSettings/GD7E70.ini @@ -1,17 +1,11 @@ # GD7E70 - Dragon Ball Z: Budokai -[Core] -# Values set here will override the main Dolphin settings. - [OnFrame] -# Add memory patches to be applied every frame here. - -[ActionReplay] -# Add action replay cheats here. +$Deinterlacing Fix +0x803cb228:byte:0x00000000 -[Gecko] +[OnFrame_Enabled] $Deinterlacing Fix -003CB228 00000000 -[Gecko_RetroAchievements_Verified] +[Patches_RetroAchievements_Verified] $Deinterlacing Fix diff --git a/Data/Sys/GameSettings/GD7PB2.ini b/Data/Sys/GameSettings/GD7PB2.ini index 556c2eefcf79..d14a7c7d3fb8 100644 --- a/Data/Sys/GameSettings/GD7PB2.ini +++ b/Data/Sys/GameSettings/GD7PB2.ini @@ -1,17 +1,11 @@ # GD7PB2 - Dragon Ball Z: Budokai -[Core] -# Values set here will override the main Dolphin settings. - [OnFrame] -# Add memory patches to be applied every frame here. - -[ActionReplay] -# Add action replay cheats here. +$Deinterlacing Fix +0x8044e9a8:byte:0x00000000 -[Gecko] +[OnFrame_Enabled] $Deinterlacing Fix -0044E9A8 00000000 -[Gecko_RetroAchievements_Verified] +[Patches_RetroAchievements_Verified] $Deinterlacing Fix diff --git a/Data/Sys/GameSettings/GZ3E70.ini b/Data/Sys/GameSettings/GZ3E70.ini index a291d6a7939a..37c6a1230dc0 100644 --- a/Data/Sys/GameSettings/GZ3E70.ini +++ b/Data/Sys/GameSettings/GZ3E70.ini @@ -1,7 +1,8 @@ -# GZ3E70 - Dragon Ball Z 2 +# GZ3E70 - Dragon Ball Z: Budokai 2 [OnFrame] -# Add memory patches to be applied every frame here. +$Deinterlacing Fix +0x80625dc8:byte:0x00000000 [ActionReplay] # Add action replay cheats here. @@ -61,9 +62,12 @@ C0BA0020 00000000 202F2D50 3F4CCCCD 042F2D50 3F19999A E2000001 80008000 -$Deinterlacing Fix -00625DC8 00000000 [Gecko_RetroAchievements_Verified] $16:9 Widescreen + +[OnFrame_Enabled] +$Deinterlacing Fix + +[Patches_RetroAchievements_Verified] $Deinterlacing Fix diff --git a/Data/Sys/GameSettings/GZBJB2.ini b/Data/Sys/GameSettings/GZBJB2.ini new file mode 100644 index 000000000000..5d0456c35754 --- /dev/null +++ b/Data/Sys/GameSettings/GZBJB2.ini @@ -0,0 +1,11 @@ +# GZBJB2 - ドラゴンボールZ + +[OnFrame] +$Deinterlacing Fix +0x803C69E8:byte:0x00000000 + +[OnFrame_Enabled] +$Deinterlacing Fix + +[Patches_RetroAchievements_Verified] +$Deinterlacing Fix diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index 0c486deeba87..337f12fd081e 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -90,8 +90,8 @@ class AchievementManager static constexpr std::string_view BLUE = "#0B71C1"; static constexpr std::string_view APPROVED_LIST_FILENAME = "ApprovedInis.json"; static const inline Common::SHA1::Digest APPROVED_LIST_HASH = { - 0xDF, 0x11, 0xD6, 0xA7, 0x2E, 0x8D, 0x3B, 0x3C, 0x41, 0x22, - 0x29, 0x3F, 0x67, 0x40, 0xD9, 0x92, 0xBF, 0xC0, 0x1C, 0x43}; + 0x7D, 0x96, 0x3E, 0x00, 0x30, 0x1C, 0x7D, 0x0E, 0x72, 0x09, + 0xE1, 0xF0, 0xF3, 0x51, 0x6D, 0x5C, 0xB3, 0x68, 0xAD, 0x79}; struct LeaderboardEntry { From 48009fd898c2732652480bdf2c086ab6f77b2a7d Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 5 Dec 2025 19:27:06 +0100 Subject: [PATCH 052/267] Jit64: Return current value from RCOpArg::IsImm The constant propagation PR made it so that a guest register can be present in the register cache as both a host register and an immediate at the same time. If such a guest register is requested from the register cache, the register cache prefers returning it as a host register. However, RCOpArg::IsImm still returns true in this case. This is confusing, especially since OpArg::IsImm does not return true if the RCOpArg is converted into an OpArg. This commit makes RCOpArg::IsImm check whether RCOpArg::Location returns an immediate, so that RCOpArg::IsImm returns false when a host register is being used. Code that wants to know whether an immediate exists in the register cache rather than whether an immediate is currently being used should call RegCache::IsImm instead. --- .../PowerPC/Jit64/RegCache/JitRegCache.cpp | 41 ------------------- .../Core/PowerPC/Jit64/RegCache/JitRegCache.h | 6 +-- 2 files changed, 3 insertions(+), 44 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp index 2a787f312074..b39ed2e56161 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.cpp @@ -132,47 +132,6 @@ void RCOpArg::Unlock() contents = std::monostate{}; } -bool RCOpArg::IsImm() const -{ - if (const preg_t* preg = std::get_if(&contents)) - { - return rc->IsImm(*preg); - } - else if (std::holds_alternative(contents)) - { - return true; - } - return false; -} - -s32 RCOpArg::SImm32() const -{ - if (const preg_t* preg = std::get_if(&contents)) - { - return rc->SImm32(*preg); - } - else if (const u32* imm = std::get_if(&contents)) - { - return static_cast(*imm); - } - ASSERT(false); - return 0; -} - -u32 RCOpArg::Imm32() const -{ - if (const preg_t* preg = std::get_if(&contents)) - { - return rc->Imm32(*preg); - } - else if (const u32* imm = std::get_if(&contents)) - { - return *imm; - } - ASSERT(false); - return 0; -} - RCX64Reg::RCX64Reg() = default; RCX64Reg::RCX64Reg(RegCache* rc_, preg_t preg) : rc(rc_), contents(preg) diff --git a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h index 0a7ab3836d2a..4d74285a513f 100644 --- a/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h +++ b/Source/Core/Core/PowerPC/Jit64/RegCache/JitRegCache.h @@ -49,9 +49,9 @@ class RCOpArg void Unlock(); - bool IsImm() const; - s32 SImm32() const; - u32 Imm32() const; + bool IsImm() const { return Location().IsImm(); } + s32 SImm32() const { return Location().SImm32(); } + u32 Imm32() const { return Location().Imm32(); } bool IsZero() const { return IsImm() && Imm32() == 0; } private: From f31f11c0a4b37decebd0e0a349bdc33691fdd657 Mon Sep 17 00:00:00 2001 From: Nuh Uh <72356786+Geotale@users.noreply.github.com> Date: Wed, 10 Dec 2025 13:40:24 -0600 Subject: [PATCH 053/267] Update Comments Based On Hardware Test Checked on hardware that this bias was not added because I had assumed the other way around would be true, forgot to ask about making a PR for this when I initially had done so --- Source/Core/VideoCommon/UberShaderPixel.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Source/Core/VideoCommon/UberShaderPixel.cpp b/Source/Core/VideoCommon/UberShaderPixel.cpp index 4eb41fa94e15..203a377e7b19 100644 --- a/Source/Core/VideoCommon/UberShaderPixel.cpp +++ b/Source/Core/VideoCommon/UberShaderPixel.cpp @@ -399,9 +399,7 @@ ShaderCode GenPixelShader(APIType api_type, const ShaderHostConfig& host_config, " D = D << scale;\n" " }}\n" "\n" - " // TODO: Is this rounding bias still added when the scale is divide by 2? " - "Currently we " - "do not apply it.\n" + " // This rounding bias is not added when the scale is divide by 2\n" " if (scale != 3u)\n" " lerp = lerp + (op ? 127 : 128);\n" "\n" From 26b6980d1a6d59125d8d4cbc92adfa0ede70458d Mon Sep 17 00:00:00 2001 From: Craig Carnell <1188869+cscd98@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:38:25 +0000 Subject: [PATCH 054/267] mingw: replace SendMessage usage as clashes with existing function --- Source/Core/VideoCommon/NetPlayChatUI.cpp | 6 +++--- Source/Core/VideoCommon/NetPlayChatUI.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Core/VideoCommon/NetPlayChatUI.cpp b/Source/Core/VideoCommon/NetPlayChatUI.cpp index 772dd3fe81c8..e7d1a758dceb 100644 --- a/Source/Core/VideoCommon/NetPlayChatUI.cpp +++ b/Source/Core/VideoCommon/NetPlayChatUI.cpp @@ -59,7 +59,7 @@ void NetPlayChatUI::Display() if (ImGui::InputText("##NetplayMessageBuffer", m_message_buf, IM_ARRAYSIZE(m_message_buf), ImGuiInputTextFlags_EnterReturnsTrue)) { - SendMessage(); + SendChatMessage(); } if (m_activate) @@ -73,7 +73,7 @@ void NetPlayChatUI::Display() ImGui::SameLine(); if (ImGui::Button("Send")) - SendMessage(); + SendChatMessage(); ImGui::End(); } @@ -90,7 +90,7 @@ void NetPlayChatUI::AppendChat(std::string message, Color color) m_scroll_to_bottom = true; } -void NetPlayChatUI::SendMessage() +void NetPlayChatUI::SendChatMessage() { // Check whether the input field is empty if (m_message_buf[0] != '\0') diff --git a/Source/Core/VideoCommon/NetPlayChatUI.h b/Source/Core/VideoCommon/NetPlayChatUI.h index 0fdc1d086d33..a5fe6d547cd7 100644 --- a/Source/Core/VideoCommon/NetPlayChatUI.h +++ b/Source/Core/VideoCommon/NetPlayChatUI.h @@ -20,7 +20,7 @@ class NetPlayChatUI void Display(); void AppendChat(std::string message, Color color); - void SendMessage(); + void SendChatMessage(); void Activate(); private: From 355bca0fb3698b7e0383caf7439d68fe53fd1700 Mon Sep 17 00:00:00 2001 From: cristian64 Date: Wed, 10 Dec 2025 21:07:46 +0000 Subject: [PATCH 055/267] Externals: Upgrade cpp-ipc to v1.4.0. Apart from bugfixes and other enhancements, this update has brought support for FreeBSD. Full changelog: https://github.com/mutouyun/cpp-ipc/releases/tag/v1.4.0 --- Externals/cpp-ipc/cpp-ipc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Externals/cpp-ipc/cpp-ipc b/Externals/cpp-ipc/cpp-ipc index a0c7725a1441..ce0773b3e6d5 160000 --- a/Externals/cpp-ipc/cpp-ipc +++ b/Externals/cpp-ipc/cpp-ipc @@ -1 +1 @@ -Subproject commit a0c7725a1441d18bc768d748a93e512a0fa7ab52 +Subproject commit ce0773b3e6d5abaa8d104100c5704321113853ca From bd6ea9a9a1da72e721cbcc3a3f23cc8c62675fce Mon Sep 17 00:00:00 2001 From: cristian64 Date: Wed, 10 Dec 2025 21:11:08 +0000 Subject: [PATCH 056/267] Core/HW: Enable BBA (IPC) in FreeBSD. Since v1.4.0, cpp-ipc now supports FreeBSD. This was a limitation that prevented us from enabling compilation on FreeBSD in #13870. Full changelog: https://github.com/mutouyun/cpp-ipc/releases/tag/v1.4.0 --- CMakeLists.txt | 2 +- Source/Core/Core/CMakeLists.txt | 2 +- Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h | 4 ++-- Source/Core/DolphinQt/Settings/GameCubePane.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fa3769f8fde..0cadc9dd49e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -786,7 +786,7 @@ endif() add_subdirectory(Externals/watcher) -if(WIN32 OR LINUX) +if(NOT ANDROID AND NOT APPLE) add_subdirectory(Externals/cpp-ipc) endif() diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index be75ba89d953..4f5e313ce748 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -801,7 +801,7 @@ if(UNIX) ) endif() -if(WIN32 OR LINUX) +if(NOT ANDROID AND NOT APPLE) target_sources(core PRIVATE HW/EXI/BBA/IPC.cpp) target_link_libraries(core PRIVATE cpp-ipc::ipc) endif() diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h b/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h index 67a03178312e..a6b078088655 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h +++ b/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h @@ -15,7 +15,7 @@ #endif #include -#if defined(WIN32) || (defined(__linux__) && !defined(__ANDROID__)) +#if !defined(__ANDROID__) && !defined(__APPLE__) #include #endif @@ -483,7 +483,7 @@ class CEXIETHERNET : public IEXIDevice public: explicit IPCBBAInterface(CEXIETHERNET* const eth_ref) : NetworkInterface(eth_ref) {} -#if defined(WIN32) || (defined(__linux__) && !defined(__ANDROID__)) +#if !defined(__ANDROID__) && !defined(__APPLE__) bool Activate() override; void Deactivate() override; diff --git a/Source/Core/DolphinQt/Settings/GameCubePane.cpp b/Source/Core/DolphinQt/Settings/GameCubePane.cpp index 98460f6be07e..fd27612dc550 100644 --- a/Source/Core/DolphinQt/Settings/GameCubePane.cpp +++ b/Source/Core/DolphinQt/Settings/GameCubePane.cpp @@ -143,7 +143,7 @@ void GameCubePane::CreateWidgets() EXIDeviceType::EthernetXLink, EXIDeviceType::EthernetTapServer, EXIDeviceType::EthernetBuiltIn, -#if defined(WIN32) || (defined(__linux__) && !defined(__ANDROID__)) +#if !defined(__APPLE__) EXIDeviceType::EthernetIPC, #endif EXIDeviceType::ModemTapServer, From 5e0c0544e233723776fb12c22ccaf6b850dd9d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Sun, 7 Dec 2025 19:09:47 +0100 Subject: [PATCH 057/267] CMake: Work around implot#565 --- Externals/implot/CMakeLists.txt | 3 +++ Externals/implot/implot_isnan_fix.h | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 Externals/implot/implot_isnan_fix.h diff --git a/Externals/implot/CMakeLists.txt b/Externals/implot/CMakeLists.txt index 922ae4ff9397..c757ec48cb34 100644 --- a/Externals/implot/CMakeLists.txt +++ b/Externals/implot/CMakeLists.txt @@ -20,3 +20,6 @@ target_link_libraries(implot PRIVATE imgui PRIVATE fmt::fmt ) + +# https://github.com/epezent/implot/pull/565 +target_compile_options(implot PRIVATE -include "${CMAKE_CURRENT_SOURCE_DIR}/implot_isnan_fix.h") diff --git a/Externals/implot/implot_isnan_fix.h b/Externals/implot/implot_isnan_fix.h new file mode 100644 index 000000000000..4e89d33d22c3 --- /dev/null +++ b/Externals/implot/implot_isnan_fix.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +using std::isnan; From da22171c804a297b03aa052b8471912fa5572f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Thu, 11 Dec 2025 01:11:14 +0100 Subject: [PATCH 058/267] Build: Remove license.txt Follow up to #10039 and #9862 --- CMakeLists.txt | 3 +- Data/license.txt | 339 ------------------------ Source/Core/DolphinQt/DolphinQt.vcxproj | 7 +- 3 files changed, 7 insertions(+), 342 deletions(-) delete mode 100644 Data/license.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fa3769f8fde..7f18b609667b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -862,7 +862,8 @@ if(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin|Windows") install(DIRECTORY Data/Sys/ DESTINATION ${datadir}/sys PATTERN) endif() if(NOT CMAKE_SYSTEM_NAME MATCHES "Linux|FreeBSD|OpenBSD|Darwin") - install(FILES Data/license.txt DESTINATION ${datadir}) + install(FILES COPYING DESTINATION ${datadir}) + install(DIRECTORY LICENSES DESTINATION ${datadir}/LICENSES PATTERN) endif() if(CMAKE_SYSTEM_NAME MATCHES "Linux|FreeBSD|OpenBSD") # Install the application icon and menu item diff --git a/Data/license.txt b/Data/license.txt deleted file mode 100644 index d511905c1647..000000000000 --- a/Data/license.txt +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index f91dab20f938..09f9163036ea 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -508,15 +508,18 @@ - + + - + + + From 3bb3a05f82557284f97bfce869dcc06234781d65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Thu, 11 Dec 2025 01:11:54 +0100 Subject: [PATCH 059/267] CMake: Use rc and manifests on other targets to match VS Project --- Source/Core/DolphinNoGUI/CMakeLists.txt | 11 ++++++++++- Source/Core/DolphinTool/CMakeLists.txt | 9 ++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Source/Core/DolphinNoGUI/CMakeLists.txt b/Source/Core/DolphinNoGUI/CMakeLists.txt index 566a643c8969..9dad1b5f86b4 100644 --- a/Source/Core/DolphinNoGUI/CMakeLists.txt +++ b/Source/Core/DolphinNoGUI/CMakeLists.txt @@ -23,7 +23,16 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") target_sources(dolphin-nogui PRIVATE PlatformFBDev.cpp) endif() -set_target_properties(dolphin-nogui PROPERTIES OUTPUT_NAME dolphin-emu-nogui) +if (WIN32) + target_sources(dolphin-nogui PRIVATE DolphinNoGUI.exe.manifest DolphinNoGUI.rc) + + set_target_properties(dolphin-nogui PROPERTIES + DEBUG_POSTFIX D + OUTPUT_NAME DolphinNoGUI + ) +else() + set_target_properties(dolphin-nogui PROPERTIES OUTPUT_NAME dolphin-emu-nogui) +endif() target_link_libraries(dolphin-nogui PRIVATE diff --git a/Source/Core/DolphinTool/CMakeLists.txt b/Source/Core/DolphinTool/CMakeLists.txt index e907fb9bbdd0..562ba1dc0a51 100644 --- a/Source/Core/DolphinTool/CMakeLists.txt +++ b/Source/Core/DolphinTool/CMakeLists.txt @@ -11,7 +11,14 @@ add_executable(dolphin-tool ToolMain.cpp ) -set_target_properties(dolphin-tool PROPERTIES OUTPUT_NAME dolphin-tool) +if (WIN32) + target_sources(dolphin-tool PRIVATE DolphinTool.exe.manifest DolphinTool.rc) + + set_target_properties(dolphin-tool PROPERTIES + DEBUG_POSTFIX D + OUTPUT_NAME DolphinTool + ) +endif() target_link_libraries(dolphin-tool PRIVATE From 43564d413058c44b7ea3f5c9326765f65814111d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Thu, 11 Dec 2025 03:18:34 +0100 Subject: [PATCH 060/267] CMake: Only copy build_info.txt if autoupdate is enabled --- Source/Core/Common/CMakeLists.txt | 2 +- Source/Core/DolphinQt/CMakeLists.txt | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 2447d1ed401d..c901e2ab6c5d 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -390,7 +390,7 @@ elseif(WIN32) ) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/build_info.txt.in" - "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/build_info.txt" + "${CMAKE_BINARY_DIR}/build_info.txt" ) target_link_libraries(common PRIVATE "-INCLUDE:enableCompatPatches") diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index cd49f7f10805..0a14ee11d71e 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -522,6 +522,13 @@ if(WIN32) COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/qt.conf.win" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/qt.conf" ) + if (ENABLE_AUTOUPDATE) + # Copy build_info.txt + add_custom_command(TARGET dolphin-emu POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_BINARY_DIR}/build_info.txt" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/build_info.txt" + ) + endif() + # Delegate to Qt's official deployment binary on Windows to copy over the necessary Qt-specific libraries, etc. get_target_property(MOC_EXECUTABLE_LOCATION Qt6::moc IMPORTED_LOCATION) get_filename_component(QT_BINARY_DIRECTORY "${MOC_EXECUTABLE_LOCATION}" DIRECTORY) From ee8a27d13ce939e224789cee1cedc846f6f8acc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Thu, 11 Dec 2025 03:26:32 +0100 Subject: [PATCH 061/267] CMake: Better architecture detection --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f18b609667b..e9677681c6ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,11 +229,11 @@ if(ENABLE_GENERIC) message(STATUS "Warning! Building generic build!") set(_M_GENERIC 1) add_definitions(-D_M_GENERIC=1) -elseif(_ARCH_64 AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64") +elseif(_ARCH_64 AND CMAKE_SYSTEM_PROCESSOR MATCHES "x64|x86_64|amd64|AMD64") set(_M_X86_64 1) add_definitions(-D_M_X86_64=1) check_and_add_flag(HAVE_SSE2 -msse2) -elseif(_ARCH_64 AND CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64") +elseif(_ARCH_64 AND CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64") set(_M_ARM_64 1) add_definitions(-D_M_ARM_64=1) # CRC instruction set is used in the CRC32 hash function @@ -363,7 +363,7 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin") set(CMAKE_XCODE_ATTRIBUTE_GCC_STRICT_ALIASING NO) # Specify target CPUs. - if(_ARCH_64 AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64") + if(_ARCH_64 AND _M_X86_64) check_and_add_flag(HAVE_MSSSE3 -mssse3) check_and_add_flag(HAVE_ARCH_CORE2 -march=core2) endif() @@ -668,7 +668,7 @@ if(ENABLE_VULKAN) endif() endif() -if(NOT WIN32 OR (NOT (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64"))) +if(NOT (WIN32 AND _M_ARM_64)) # OpenGL is available on all platforms except windows-arm64 add_definitions(-DHAS_OPENGL) endif() From ec6f511c95d16a405cb0c35be5f1bc099ea1c1d6 Mon Sep 17 00:00:00 2001 From: Craig Carnell <1188869+cscd98@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:33:25 +0000 Subject: [PATCH 062/267] mingw: replace usages of Interface as clashes with existing struct --- Source/Core/Core/IOS/Network/IP/Top.cpp | 16 ++++++++-------- Source/Core/Core/IOS/USB/Common.h | 8 ++++---- Source/Core/Core/IOS/USB/Emulated/Infinity.cpp | 16 ++++++++-------- Source/Core/Core/IOS/USB/Emulated/Infinity.h | 8 ++++---- .../Core/Core/IOS/USB/Emulated/LogitechMic.cpp | 16 ++++++++-------- Source/Core/Core/IOS/USB/Emulated/LogitechMic.h | 8 ++++---- .../IOS/USB/Emulated/Skylanders/Skylander.cpp | 16 ++++++++-------- .../Core/IOS/USB/Emulated/Skylanders/Skylander.h | 8 ++++---- Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp | 16 ++++++++-------- Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h | 8 ++++---- Source/Core/Core/IOS/USB/LibusbDevice.cpp | 12 ++++++------ Source/Core/Core/IOS/USB/LibusbDevice.h | 8 ++++---- 12 files changed, 70 insertions(+), 70 deletions(-) diff --git a/Source/Core/Core/IOS/Network/IP/Top.cpp b/Source/Core/Core/IOS/Network/IP/Top.cpp index 14d90a04e111..8baa81aef770 100644 --- a/Source/Core/Core/IOS/Network/IP/Top.cpp +++ b/Source/Core/Core/IOS/Network/IP/Top.cpp @@ -786,8 +786,8 @@ IPCReply NetIPTopDevice::HandleGetPeerNameRequest(const IOCtlRequest& request) IPCReply NetIPTopDevice::HandleGetHostIDRequest(const IOCtlRequest& request) { - const DefaultInterface interface = GetSystemDefaultInterfaceOrFallback(); - const u32 host_ip = ntohl(interface.inet.s_addr); + const DefaultInterface net_interface = GetSystemDefaultInterfaceOrFallback(); + const u32 host_ip = ntohl(net_interface.inet.s_addr); INFO_LOG_FMT(IOS_NET, "IOCTL_SO_GETHOSTID = {}.{}.{}.{}", host_ip >> 24, (host_ip >> 16) & 0xFF, (host_ip >> 8) & 0xFF, host_ip & 0xFF); return IPCReply(host_ip); @@ -1159,10 +1159,10 @@ IPCReply NetIPTopDevice::HandleGetInterfaceOptRequest(const IOCtlVRequest& reque // XXX: this isn't exactly right; the buffer can be larger than 12 bytes, // in which case, depending on some interface settings, SO can write 12 more bytes memory.Write_U32(0xC, request.io_vectors[1].address); - const DefaultInterface interface = GetSystemDefaultInterfaceOrFallback(); - memory.Write_U32(ntohl(interface.inet.s_addr), request.io_vectors[0].address); - memory.Write_U32(ntohl(interface.netmask.s_addr), request.io_vectors[0].address + 4); - memory.Write_U32(ntohl(interface.broadcast.s_addr), request.io_vectors[0].address + 8); + const DefaultInterface net_interface = GetSystemDefaultInterfaceOrFallback(); + memory.Write_U32(ntohl(net_interface.inet.s_addr), request.io_vectors[0].address); + memory.Write_U32(ntohl(net_interface.netmask.s_addr), request.io_vectors[0].address + 4); + memory.Write_U32(ntohl(net_interface.broadcast.s_addr), request.io_vectors[0].address + 8); break; } @@ -1174,8 +1174,8 @@ IPCReply NetIPTopDevice::HandleGetInterfaceOptRequest(const IOCtlVRequest& reque case 0x4006: // get routing table { - const DefaultInterface interface = GetSystemDefaultInterfaceOrFallback(); - for (InterfaceRouting route : interface.routing_table) + const DefaultInterface net_interface = GetSystemDefaultInterfaceOrFallback(); + for (InterfaceRouting route : net_interface.routing_table) { memory.Write_U32(ntohl(route.destination.s_addr), request.io_vectors[0].address + param5); memory.Write_U32(ntohl(route.netmask.s_addr), request.io_vectors[0].address + param5 + 4); diff --git a/Source/Core/Core/IOS/USB/Common.h b/Source/Core/Core/IOS/USB/Common.h index cdc7c39dadfd..ae9d753c74c9 100644 --- a/Source/Core/Core/IOS/USB/Common.h +++ b/Source/Core/Core/IOS/USB/Common.h @@ -170,7 +170,7 @@ class Device virtual DeviceDescriptor GetDeviceDescriptor() const = 0; virtual std::vector GetConfigurations() const = 0; virtual std::vector GetInterfaces(u8 config) const = 0; - virtual std::vector GetEndpoints(u8 config, u8 interface, u8 alt) const = 0; + virtual std::vector GetEndpoints(u8 config, u8 iface, u8 alt) const = 0; virtual std::string GetErrorName(int error_code) const; /// Ensure the device is ready to use. @@ -179,10 +179,10 @@ class Device /// /// This may reset the active alt setting, so prefer using Attach when interface changes /// are unnecessary (e.g. for control requests). - virtual bool AttachAndChangeInterface(u8 interface) = 0; + virtual bool AttachAndChangeInterface(u8 iface) = 0; virtual int CancelTransfer(u8 endpoint) = 0; - virtual int ChangeInterface(u8 interface) = 0; - virtual int GetNumberOfAltSettings(u8 interface) = 0; + virtual int ChangeInterface(u8 iface) = 0; + virtual int GetNumberOfAltSettings(u8 iface) = 0; virtual int SetAltSetting(u8 alt_setting) = 0; virtual int SubmitTransfer(std::unique_ptr message) = 0; virtual int SubmitTransfer(std::unique_ptr message) = 0; diff --git a/Source/Core/Core/IOS/USB/Emulated/Infinity.cpp b/Source/Core/Core/IOS/USB/Emulated/Infinity.cpp index fcfa20374289..458638640427 100644 --- a/Source/Core/Core/IOS/USB/Emulated/Infinity.cpp +++ b/Source/Core/Core/IOS/USB/Emulated/Infinity.cpp @@ -168,7 +168,7 @@ std::vector InfinityUSB::GetInterfaces(u8 config) const return m_interface_descriptor; } -std::vector InfinityUSB::GetEndpoints(u8 config, u8 interface, u8 alt) const +std::vector InfinityUSB::GetEndpoints(u8 config, u8 iface, u8 alt) const { return m_endpoint_descriptor; } @@ -184,13 +184,13 @@ bool InfinityUSB::Attach() return true; } -bool InfinityUSB::AttachAndChangeInterface(const u8 interface) +bool InfinityUSB::AttachAndChangeInterface(const u8 iface) { if (!Attach()) return false; - if (interface != m_active_interface) - return ChangeInterface(interface) == 0; + if (iface != m_active_interface) + return ChangeInterface(iface) == 0; return true; } @@ -203,15 +203,15 @@ int InfinityUSB::CancelTransfer(const u8 endpoint) return IPC_SUCCESS; } -int InfinityUSB::ChangeInterface(const u8 interface) +int InfinityUSB::ChangeInterface(const u8 iface) { DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Changing interface to {}", m_vid, m_pid, - m_active_interface, interface); - m_active_interface = interface; + m_active_interface, iface); + m_active_interface = iface; return 0; } -int InfinityUSB::GetNumberOfAltSettings(u8 interface) +int InfinityUSB::GetNumberOfAltSettings(u8 iface) { return 0; } diff --git a/Source/Core/Core/IOS/USB/Emulated/Infinity.h b/Source/Core/Core/IOS/USB/Emulated/Infinity.h index 8bafefd64bb0..ebf9dd7894c4 100644 --- a/Source/Core/Core/IOS/USB/Emulated/Infinity.h +++ b/Source/Core/Core/IOS/USB/Emulated/Infinity.h @@ -37,12 +37,12 @@ class InfinityUSB final : public Device DeviceDescriptor GetDeviceDescriptor() const override; std::vector GetConfigurations() const override; std::vector GetInterfaces(u8 config) const override; - std::vector GetEndpoints(u8 config, u8 interface, u8 alt) const override; + std::vector GetEndpoints(u8 config, u8 iface, u8 alt) const override; bool Attach() override; - bool AttachAndChangeInterface(u8 interface) override; + bool AttachAndChangeInterface(u8 iface) override; int CancelTransfer(u8 endpoint) override; - int ChangeInterface(u8 interface) override; - int GetNumberOfAltSettings(u8 interface) override; + int ChangeInterface(u8 iface) override; + int GetNumberOfAltSettings(u8 iface) override; int SetAltSetting(u8 alt_setting) override; int SubmitTransfer(std::unique_ptr message) override; int SubmitTransfer(std::unique_ptr message) override; diff --git a/Source/Core/Core/IOS/USB/Emulated/LogitechMic.cpp b/Source/Core/Core/IOS/USB/Emulated/LogitechMic.cpp index 8380c533dcc9..df161803450b 100644 --- a/Source/Core/Core/IOS/USB/Emulated/LogitechMic.cpp +++ b/Source/Core/Core/IOS/USB/Emulated/LogitechMic.cpp @@ -161,13 +161,13 @@ bool LogitechMic::Attach() return true; } -bool LogitechMic::AttachAndChangeInterface(const u8 interface) +bool LogitechMic::AttachAndChangeInterface(const u8 iface) { if (!Attach()) return false; - if (interface != m_active_interface) - return ChangeInterface(interface) == 0; + if (iface != m_active_interface) + return ChangeInterface(iface) == 0; return true; } @@ -180,17 +180,17 @@ int LogitechMic::CancelTransfer(const u8 endpoint) return IPC_SUCCESS; } -int LogitechMic::ChangeInterface(const u8 interface) +int LogitechMic::ChangeInterface(const u8 iface) { DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}:{}] Changing interface to {}", m_vid, m_pid, m_index, - m_active_interface, interface); - m_active_interface = interface; + m_active_interface, iface); + m_active_interface = iface; return 0; } -int LogitechMic::GetNumberOfAltSettings(u8 interface) +int LogitechMic::GetNumberOfAltSettings(u8 iface) { - if (interface == 1) + if (iface == 1) return 2; return 0; diff --git a/Source/Core/Core/IOS/USB/Emulated/LogitechMic.h b/Source/Core/Core/IOS/USB/Emulated/LogitechMic.h index 3ae5810344c3..a8319604f49e 100644 --- a/Source/Core/Core/IOS/USB/Emulated/LogitechMic.h +++ b/Source/Core/Core/IOS/USB/Emulated/LogitechMic.h @@ -37,12 +37,12 @@ class LogitechMic final : public Device DeviceDescriptor GetDeviceDescriptor() const override; std::vector GetConfigurations() const override; std::vector GetInterfaces(u8 config) const override; - std::vector GetEndpoints(u8 config, u8 interface, u8 alt) const override; + std::vector GetEndpoints(u8 config, u8 iface, u8 alt) const override; bool Attach() override; - bool AttachAndChangeInterface(u8 interface) override; + bool AttachAndChangeInterface(u8 iface) override; int CancelTransfer(u8 endpoint) override; - int ChangeInterface(u8 interface) override; - int GetNumberOfAltSettings(u8 interface) override; + int ChangeInterface(u8 iface) override; + int GetNumberOfAltSettings(u8 iface) override; int SetAltSetting(u8 alt_setting) override; int SubmitTransfer(std::unique_ptr cmd) override; int SubmitTransfer(std::unique_ptr cmd) override; diff --git a/Source/Core/Core/IOS/USB/Emulated/Skylanders/Skylander.cpp b/Source/Core/Core/IOS/USB/Emulated/Skylanders/Skylander.cpp index 02b16194d50b..1b07002c7b44 100644 --- a/Source/Core/Core/IOS/USB/Emulated/Skylanders/Skylander.cpp +++ b/Source/Core/Core/IOS/USB/Emulated/Skylanders/Skylander.cpp @@ -644,7 +644,7 @@ std::vector SkylanderUSB::GetInterfaces(u8 config) const return m_interface_descriptor; } -std::vector SkylanderUSB::GetEndpoints(u8 config, u8 interface, u8 alt) const +std::vector SkylanderUSB::GetEndpoints(u8 config, u8 iface, u8 alt) const { return m_endpoint_descriptor; } @@ -660,13 +660,13 @@ bool SkylanderUSB::Attach() return true; } -bool SkylanderUSB::AttachAndChangeInterface(const u8 interface) +bool SkylanderUSB::AttachAndChangeInterface(const u8 iface) { if (!Attach()) return false; - if (interface != m_active_interface) - return ChangeInterface(interface) == 0; + if (iface != m_active_interface) + return ChangeInterface(iface) == 0; return true; } @@ -679,15 +679,15 @@ int SkylanderUSB::CancelTransfer(const u8 endpoint) return IPC_SUCCESS; } -int SkylanderUSB::ChangeInterface(const u8 interface) +int SkylanderUSB::ChangeInterface(const u8 iface) { DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Changing interface to {}", m_vid, m_pid, - m_active_interface, interface); - m_active_interface = interface; + m_active_interface, iface); + m_active_interface = iface; return 0; } -int SkylanderUSB::GetNumberOfAltSettings(u8 interface) +int SkylanderUSB::GetNumberOfAltSettings(u8 iface) { return 0; } diff --git a/Source/Core/Core/IOS/USB/Emulated/Skylanders/Skylander.h b/Source/Core/Core/IOS/USB/Emulated/Skylanders/Skylander.h index f9f8f8f61607..9de058f59fda 100644 --- a/Source/Core/Core/IOS/USB/Emulated/Skylanders/Skylander.h +++ b/Source/Core/Core/IOS/USB/Emulated/Skylanders/Skylander.h @@ -77,12 +77,12 @@ class SkylanderUSB final : public Device DeviceDescriptor GetDeviceDescriptor() const override; std::vector GetConfigurations() const override; std::vector GetInterfaces(u8 config) const override; - std::vector GetEndpoints(u8 config, u8 interface, u8 alt) const override; + std::vector GetEndpoints(u8 config, u8 iface, u8 alt) const override; bool Attach() override; - bool AttachAndChangeInterface(u8 interface) override; + bool AttachAndChangeInterface(u8 iface) override; int CancelTransfer(u8 endpoint) override; - int ChangeInterface(u8 interface) override; - int GetNumberOfAltSettings(u8 interface) override; + int ChangeInterface(u8 iface) override; + int GetNumberOfAltSettings(u8 iface) override; int SetAltSetting(u8 alt_setting) override; int SubmitTransfer(std::unique_ptr message) override; int SubmitTransfer(std::unique_ptr message) override; diff --git a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp index eaaadacc9452..3b519c4c6e3d 100644 --- a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp +++ b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp @@ -77,7 +77,7 @@ std::vector WiiSpeak::GetInterfaces(u8 config) const return m_interface_descriptor; } -std::vector WiiSpeak::GetEndpoints(u8 config, u8 interface, u8 alt) const +std::vector WiiSpeak::GetEndpoints(u8 config, u8 iface, u8 alt) const { return m_endpoint_descriptor; } @@ -97,13 +97,13 @@ bool WiiSpeak::Attach() return true; } -bool WiiSpeak::AttachAndChangeInterface(const u8 interface) +bool WiiSpeak::AttachAndChangeInterface(const u8 iface) { if (!Attach()) return false; - if (interface != m_active_interface) - return ChangeInterface(interface) == 0; + if (iface != m_active_interface) + return ChangeInterface(iface) == 0; return true; } @@ -116,15 +116,15 @@ int WiiSpeak::CancelTransfer(const u8 endpoint) return IPC_SUCCESS; } -int WiiSpeak::ChangeInterface(const u8 interface) +int WiiSpeak::ChangeInterface(const u8 iface) { DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Changing interface to {}", m_vid, m_pid, - m_active_interface, interface); - m_active_interface = interface; + m_active_interface, iface); + m_active_interface = iface; return 0; } -int WiiSpeak::GetNumberOfAltSettings(u8 interface) +int WiiSpeak::GetNumberOfAltSettings(u8 iface) { return 0; } diff --git a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h index 9a0ae136746b..ef48883d29bc 100644 --- a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h +++ b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h @@ -40,12 +40,12 @@ class WiiSpeak final : public Device DeviceDescriptor GetDeviceDescriptor() const override; std::vector GetConfigurations() const override; std::vector GetInterfaces(u8 config) const override; - std::vector GetEndpoints(u8 config, u8 interface, u8 alt) const override; + std::vector GetEndpoints(u8 config, u8 iface, u8 alt) const override; bool Attach() override; - bool AttachAndChangeInterface(u8 interface) override; + bool AttachAndChangeInterface(u8 f) override; int CancelTransfer(u8 endpoint) override; - int ChangeInterface(u8 interface) override; - int GetNumberOfAltSettings(u8 interface) override; + int ChangeInterface(u8 iface) override; + int GetNumberOfAltSettings(u8 iface) override; int SetAltSetting(u8 alt_setting) override; int SubmitTransfer(std::unique_ptr message) override; int SubmitTransfer(std::unique_ptr message) override; diff --git a/Source/Core/Core/IOS/USB/LibusbDevice.cpp b/Source/Core/Core/IOS/USB/LibusbDevice.cpp index da127b70d578..adc23515557d 100644 --- a/Source/Core/Core/IOS/USB/LibusbDevice.cpp +++ b/Source/Core/Core/IOS/USB/LibusbDevice.cpp @@ -163,13 +163,13 @@ bool LibusbDevice::Attach() return true; } -bool LibusbDevice::AttachAndChangeInterface(const u8 interface) +bool LibusbDevice::AttachAndChangeInterface(const u8 iface) { if (!Attach()) return false; - if (interface != m_active_interface) - return ChangeInterface(interface) == LIBUSB_SUCCESS; + if (iface != m_active_interface) + return ChangeInterface(iface) == LIBUSB_SUCCESS; return true; } @@ -185,11 +185,11 @@ int LibusbDevice::CancelTransfer(const u8 endpoint) return IPC_SUCCESS; } -int LibusbDevice::ChangeInterface(const u8 interface) +int LibusbDevice::ChangeInterface(const u8 iface) { INFO_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Changing interface to {}", m_vid, m_pid, - m_active_interface, interface); - m_active_interface = interface; + m_active_interface, iface); + m_active_interface = iface; return LIBUSB_SUCCESS; } diff --git a/Source/Core/Core/IOS/USB/LibusbDevice.h b/Source/Core/Core/IOS/USB/LibusbDevice.h index e6151b11e2bc..1e0207b9de3d 100644 --- a/Source/Core/Core/IOS/USB/LibusbDevice.h +++ b/Source/Core/Core/IOS/USB/LibusbDevice.h @@ -31,13 +31,13 @@ class LibusbDevice final : public Device DeviceDescriptor GetDeviceDescriptor() const override; std::vector GetConfigurations() const override; std::vector GetInterfaces(u8 config) const override; - std::vector GetEndpoints(u8 config, u8 interface, u8 alt) const override; + std::vector GetEndpoints(u8 config, u8 iface, u8 alt) const override; std::string GetErrorName(int error_code) const override; bool Attach() override; - bool AttachAndChangeInterface(u8 interface) override; + bool AttachAndChangeInterface(u8 iface) override; int CancelTransfer(u8 endpoint) override; - int ChangeInterface(u8 interface) override; - int GetNumberOfAltSettings(u8 interface) override; + int ChangeInterface(u8 iface) override; + int GetNumberOfAltSettings(u8 iface) override; int SetAltSetting(u8 alt_setting) override; int SubmitTransfer(std::unique_ptr message) override; int SubmitTransfer(std::unique_ptr message) override; From 1c157d1fc8b0ea2ca69fc2029c844c0cc5eb6db7 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Fri, 12 Dec 2025 00:53:45 +0000 Subject: [PATCH 063/267] GekkoDisassembler: fix conditional twi opcode --- Source/Core/Common/GekkoDisassembler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Common/GekkoDisassembler.cpp b/Source/Core/Common/GekkoDisassembler.cpp index 18ed219e643f..71217d62695e 100644 --- a/Source/Core/Common/GekkoDisassembler.cpp +++ b/Source/Core/Common/GekkoDisassembler.cpp @@ -493,7 +493,7 @@ void GekkoDisassembler::trapi(u32 in, unsigned char dmode) if (cnd != nullptr) { - m_opcode = fmt::format("t{}{}", dmode ? 'd' : 'w', cnd); + m_opcode = fmt::format("t{}{}i", dmode ? 'd' : 'w', cnd); } else { From df7caeab3fb17648785ad86777acd194330c0117 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Fri, 12 Dec 2025 01:00:36 +0000 Subject: [PATCH 064/267] GekkoDisassembler: fix ps_sel operands --- Source/Core/Common/GekkoDisassembler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Common/GekkoDisassembler.cpp b/Source/Core/Common/GekkoDisassembler.cpp index 71217d62695e..e0786f7643f2 100644 --- a/Source/Core/Common/GekkoDisassembler.cpp +++ b/Source/Core/Common/GekkoDisassembler.cpp @@ -1094,7 +1094,7 @@ void GekkoDisassembler::ps(u32 inst) case 23: m_opcode = "ps_sel"; - m_operands = fmt::format("p{}>=0?p{}:p{}", FD, FA, FC); + m_operands = fmt::format("p{}, p{}>=0?p{}:p{}", FD, FA, FC, FB); return; case 24: From c52dd23c58b8e93a12d6be5c0fe8cc68fc11c026 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Fri, 12 Dec 2025 01:23:57 +0000 Subject: [PATCH 065/267] GekkoDisassembler: drop unsupported opcodes --- Source/Core/Common/GekkoDisassembler.cpp | 50 ------------------------ 1 file changed, 50 deletions(-) diff --git a/Source/Core/Common/GekkoDisassembler.cpp b/Source/Core/Common/GekkoDisassembler.cpp index e0786f7643f2..6dc66a8f1e33 100644 --- a/Source/Core/Common/GekkoDisassembler.cpp +++ b/Source/Core/Common/GekkoDisassembler.cpp @@ -918,16 +918,6 @@ void GekkoDisassembler::mtb(u32 in) } } -void GekkoDisassembler::sradi(u32 in) -{ - int s = (int)PPCGETD(in); - int a = (int)PPCGETA(in); - int bsh = (int)(((in & 2) << 4) + PPCGETB(in)); - - m_opcode = fmt::format("sradi{}", (in & 1) ? "." : ""); - m_operands = fmt::format("{}, {}, {}", regnames[a], regnames[s], bsh); -} - void GekkoDisassembler::ldst(u32 in, std::string_view name, char reg) { int s = (int)PPCGETD(in); @@ -1443,30 +1433,6 @@ u32* GekkoDisassembler::DoDisassembly(bool big_endian) ori(in, "andis."); break; - case 30: - switch ((in >> 2) & 0x7) - { - case 0: - rld(in, "icl", 0); // rldicl - break; - case 1: - rld(in, "icr", 0); // rldicr - break; - case 2: - rld(in, "ic", 0); // rldic - break; - case 3: - rld(in, "imi", 0); // rldimi - break; - case 4: - rld(in, in & 2 ? "cl" : "cr", 1); // rldcl, rldcr - break; - default: - ill(in); - break; - } - break; - case 31: switch (PPCGETIDX2(in)) { @@ -1813,10 +1779,6 @@ u32* GekkoDisassembler::DoDisassembly(bool big_endian) dab(in, "orc", 7, 1, 0, -1); break; - case 413: - sradi(in); // sradi - break; - case 434: if (in & (PPCDMASK | PPCAMASK)) ill(in); @@ -2291,18 +2253,6 @@ u32* GekkoDisassembler::DoDisassembly(bool big_endian) } break; - case 814: - fdabc(in, "fctid", 9); - break; - - case 815: - fdabc(in, "fctidz", 9); - break; - - case 846: - fdabc(in, "fcfid", 9); - break; - default: ill(in); break; From 0aa0071beced66637d95dd3076a84e48652033cd Mon Sep 17 00:00:00 2001 From: Filippo Tarpini Date: Sun, 21 Dec 2025 04:13:46 +0100 Subject: [PATCH 066/267] Update conversion matrix for NTSC-J These were original calculated by @EndlesslyFlowering, and they've not came up with a new version that does chromatic adaptation (D93 to D65 white point) better, hence should be more accurate. These are already in use in RenoDX: https://github.com/clshortfuse/renodx/blob/283b85902176f0eced10ef2396e9524edee51fb8/src/shaders/color.hlsl#L97C1-L103C49 --- Data/Sys/Shaders/default_pre_post_process.glsl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Data/Sys/Shaders/default_pre_post_process.glsl b/Data/Sys/Shaders/default_pre_post_process.glsl index 24fb8c409a80..b4d5266e65a0 100644 --- a/Data/Sys/Shaders/default_pre_post_process.glsl +++ b/Data/Sys/Shaders/default_pre_post_process.glsl @@ -11,9 +11,9 @@ mat3 from_NTSCM = transpose(mat3( // ARIB TR-B9 (9300K+27MPCD with chromatic adaptation) (NTSC-J) -> BT.709 mat3 from_NTSCJ = transpose(mat3( - 0.823613036967492, -0.0943227111084757, 0.00799341532931119, - 0.0289258355537324, 1.02310733489462, 0.00243547111576797, - -0.00569501554980891, 0.0161828357559315, 1.22328453915712)); + 0.768497526, -0.210804164, 0.000297427177, + 0.0397904068, 1.04825413, 0.00555809540, + 0.00147510506, 0.0328789241, 1.36515128)); // EBU - BT.470BG/BT.601 (PAL) -> BT.709 mat3 from_PAL = transpose(mat3( From 2272596ea968f658cd0e3f7e77d60054ec123d55 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 19 Nov 2025 20:46:14 -0500 Subject: [PATCH 067/267] Update rcheevos lib to current master v12.2.0, includes multiset optimization and memory access fixes --- Externals/rcheevos/rcheevos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Externals/rcheevos/rcheevos b/Externals/rcheevos/rcheevos index b443902b1cdf..926e4608f8dc 160000 --- a/Externals/rcheevos/rcheevos +++ b/Externals/rcheevos/rcheevos @@ -1 +1 @@ -Subproject commit b443902b1cdfee5a66b09fec20a94d2d2afaf2ec +Subproject commit 926e4608f8dca7989267c787bbefb3ab1c835ac5 From c55218200a05cbad8b1cfd71acab2dbb253df687 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Thu, 25 Sep 2025 13:23:26 -0500 Subject: [PATCH 068/267] WindowsDevice: Add DeviceChangeNotification class. --- Source/Core/Common/WindowsDevice.cpp | 59 ++++++++++++++++++++++++++++ Source/Core/Common/WindowsDevice.h | 29 ++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/Source/Core/Common/WindowsDevice.cpp b/Source/Core/Common/WindowsDevice.cpp index 4bbd21377499..34a540ed7bb7 100644 --- a/Source/Core/Common/WindowsDevice.cpp +++ b/Source/Core/Common/WindowsDevice.cpp @@ -90,6 +90,65 @@ NullTerminatedStringList GetDeviceInterfaceList(LPGUID iface_class_guid, } } +static __callback DWORD OnDevicesChanged(_In_ HCMNOTIFICATION notify_handle, _In_opt_ PVOID context, + _In_ CM_NOTIFY_ACTION action, + _In_reads_bytes_(event_data_size) + PCM_NOTIFY_EVENT_DATA event_data, + _In_ DWORD event_data_size) +{ + auto& callback = *static_cast(context); + switch (action) + { + case CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL: + callback(DeviceChangeNotification::EventType::Arrival); + break; + case CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL: + callback(DeviceChangeNotification::EventType::Removal); + break; + default: + break; + } + return ERROR_SUCCESS; +} + +DeviceChangeNotification::DeviceChangeNotification() = default; + +DeviceChangeNotification::~DeviceChangeNotification() +{ + Unregister(); +} + +void DeviceChangeNotification::Register(CallbackType callback) +{ + Unregister(); + m_callback = std::move(callback); + + CM_NOTIFY_FILTER notify_filter{ + .cbSize = sizeof(notify_filter), + .FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE, + .u{.DeviceInterface{.ClassGuid = GUID_DEVINTERFACE_HID}}, + }; + const CONFIGRET cfg_rv = + CM_Register_Notification(¬ify_filter, &m_callback, OnDevicesChanged, &m_notify_handle); + if (cfg_rv != CR_SUCCESS) + { + ERROR_LOG_FMT(COMMON, "CM_Register_Notification failed: {:x}", cfg_rv); + } +} + +void DeviceChangeNotification::Unregister() +{ + if (m_notify_handle == nullptr) + return; + + const CONFIGRET cfg_rv = CM_Unregister_Notification(m_notify_handle); + if (cfg_rv != CR_SUCCESS) + { + ERROR_LOG_FMT(COMMON, "CM_Unregister_Notification failed: {:x}", cfg_rv); + } + m_notify_handle = nullptr; +} + } // namespace Common #endif diff --git a/Source/Core/Common/WindowsDevice.h b/Source/Core/Common/WindowsDevice.h index 8c682ac8500d..78e8234c15a8 100644 --- a/Source/Core/Common/WindowsDevice.h +++ b/Source/Core/Common/WindowsDevice.h @@ -22,6 +22,8 @@ #include #include +#include "Common/Functional.h" + namespace Common { std::optional GetDevNodeStringProperty(DEVINST device, @@ -71,6 +73,33 @@ struct NullTerminatedStringList NullTerminatedStringList GetDeviceInterfaceList(LPGUID iface_class_guid, DEVINSTID device_id, ULONG flags); +class DeviceChangeNotification +{ +public: + enum class EventType : bool + { + Arrival, + Removal, + }; + using CallbackType = Common::MoveOnlyFunction; + + DeviceChangeNotification(); + ~DeviceChangeNotification(); + + // FYI: Currently hardcoded to a GUID_DEVINTERFACE_HID filter. + void Register(CallbackType callback); + void Unregister(); + + DeviceChangeNotification(const DeviceChangeNotification&) = delete; + DeviceChangeNotification(DeviceChangeNotification&&) = delete; + void operator=(const DeviceChangeNotification&) = delete; + void operator=(DeviceChangeNotification&&) = delete; + +private: + CallbackType m_callback{}; + HCMNOTIFICATION m_notify_handle{nullptr}; +}; + } // namespace Common #endif From fc4cbf9c6fa76862b153d72baddde11edb8a3958 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Mon, 22 Dec 2025 23:18:36 -0600 Subject: [PATCH 069/267] HW/WiimoteReal: Cache the enumerated Wii remote HID interface list between calls to FindWiimoteHIDDevices. --- Source/Core/Core/HW/WiimoteReal/IOWin.cpp | 41 ++++++++++++++++------- Source/Core/Core/HW/WiimoteReal/IOWin.h | 17 ++++++++++ 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp index e1cf4971e9f1..29a7ef2d45ba 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp @@ -24,7 +24,6 @@ #include "Common/ScopeGuard.h" #include "Common/StringUtil.h" #include "Common/Thread.h" -#include "Common/WindowsDevice.h" #include "Core/HW/WiimoteCommon/DataReport.h" #include "Core/HW/WiimoteCommon/WiimoteConstants.h" @@ -328,7 +327,12 @@ void WiimoteScannerWindows::RemoveRememberedWiimotes() NOTICE_LOG_FMT(WIIMOTE, "Removed remembered Wiimotes: {}", forget_count); } -WiimoteScannerWindows::WiimoteScannerWindows() = default; +WiimoteScannerWindows::WiimoteScannerWindows() +{ + m_device_change_notification.Register([this](Common::DeviceChangeNotification::EventType) { + m_devices_changed.store(true, std::memory_order_release); + }); +} void WiimoteScannerWindows::Update() { @@ -576,9 +580,9 @@ int WiimoteWindows::IOWrite(const u8* buf, size_t len) return write_result; } -auto WiimoteScannerWindows::FindWiimoteHIDDevices() -> FindResults +static std::vector GetAllWiimoteHIDInterfaces() { - FindResults results; + std::vector results; // Enumerate connected HID interfaces IDs. auto class_guid = GUID_DEVINTERFACE_HID; @@ -586,14 +590,6 @@ auto WiimoteScannerWindows::FindWiimoteHIDDevices() -> FindResults for (auto* hid_iface : Common::GetDeviceInterfaceList(&class_guid, nullptr, flags)) { - // TODO: WiimoteWindows::GetId() does a redundant conversion. - const auto hid_iface_utf8 = WStringToUTF8(hid_iface); - DEBUG_LOG_FMT(WIIMOTE, "Found HID interface: {}", hid_iface_utf8); - - // Are we already using this device? - if (!IsNewWiimote(hid_iface_utf8)) - continue; - // When connected via Bluetooth, this has a proper name like "Nintendo RVL-CNT-01". const auto parent_description = GetParentDeviceDescription(hid_iface); @@ -650,6 +646,27 @@ auto WiimoteScannerWindows::FindWiimoteHIDDevices() -> FindResults } // Once here, we are confident that this is a Wii device. + results.push_back({hid_iface, is_balance_board}); + } + + return results; +} + +auto WiimoteScannerWindows::FindWiimoteHIDDevices() -> FindResults +{ + if (m_devices_changed.exchange(false, std::memory_order_acquire)) + { + m_wiimote_hid_interfaces = GetAllWiimoteHIDInterfaces(); + INFO_LOG_FMT(WIIMOTE, "Found {} HID interface(s).", m_wiimote_hid_interfaces.size()); + } + + FindResults results; + + for (auto& [hid_iface, is_balance_board] : m_wiimote_hid_interfaces) + { + // Are we already using this device? + if (!IsNewWiimote(WStringToUTF8(hid_iface))) + continue; DEBUG_LOG_FMT(WIIMOTE, "Creating WiimoteWindows"); diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.h b/Source/Core/Core/HW/WiimoteReal/IOWin.h index b8bc29a86fe8..aa7b4262887f 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOWin.h +++ b/Source/Core/Core/HW/WiimoteReal/IOWin.h @@ -6,7 +6,12 @@ #ifdef _WIN32 #include +#include +#include + #include "Common/SocketContext.h" +#include "Common/WindowsDevice.h" + #include "Core/HW/WiimoteReal/WiimoteReal.h" #include "Core/USBUtils.h" @@ -50,6 +55,12 @@ class WiimoteWindows final : public Wiimote class WiimoteScannerWindows final : public WiimoteScannerBackend { public: + struct EnumeratedWiimoteInterface + { + std::wstring hid_iface; + std::optional is_balance_board; + }; + WiimoteScannerWindows(); bool IsReady() const override; @@ -64,6 +75,12 @@ class WiimoteScannerWindows final : public WiimoteScannerBackend private: FindResults FindWiimoteHIDDevices(); + + // This vector is updated after we receive a device change notification. + std::vector m_wiimote_hid_interfaces; + std::atomic_bool m_devices_changed{true}; + + Common::DeviceChangeNotification m_device_change_notification; }; } // namespace WiimoteReal From 13045fdff89a67dfaf647d77b9b4b3ec4d229966 Mon Sep 17 00:00:00 2001 From: matellush <202132988+matellush@users.noreply.github.com> Date: Tue, 23 Dec 2025 17:34:57 +0100 Subject: [PATCH 070/267] Flatpak: Update runtime to `6.10` --- Flatpak/org.DolphinEmu.dolphin-emu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flatpak/org.DolphinEmu.dolphin-emu.yml b/Flatpak/org.DolphinEmu.dolphin-emu.yml index 0bece4769bab..a636a278e775 100644 --- a/Flatpak/org.DolphinEmu.dolphin-emu.yml +++ b/Flatpak/org.DolphinEmu.dolphin-emu.yml @@ -1,6 +1,6 @@ app-id: org.DolphinEmu.dolphin-emu runtime: org.kde.Platform -runtime-version: '6.8' +runtime-version: '6.10' sdk: org.kde.Sdk command: dolphin-emu-wrapper rename-desktop-file: dolphin-emu.desktop From c884158cd9e41b8ce1e22dbc672dd33fe8bde2f0 Mon Sep 17 00:00:00 2001 From: Mrlinkwii Date: Tue, 23 Dec 2025 14:52:10 +0000 Subject: [PATCH 071/267] Externals :update SFML to 3.0.2 --- Externals/SFML/SFML | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Externals/SFML/SFML b/Externals/SFML/SFML index 016bea9491cc..0fa201c969e4 160000 --- a/Externals/SFML/SFML +++ b/Externals/SFML/SFML @@ -1 +1 @@ -Subproject commit 016bea9491ccafc3529019fe1d403885a8b3a6ae +Subproject commit 0fa201c969e48ecc253581c5841ce73f44d42f49 From f846fc0d022c6cb00700412d72df9fbd848408e5 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Wed, 24 Dec 2025 01:51:55 -0600 Subject: [PATCH 072/267] VideoCommon: clear all compiler work when resource manager shuts down --- Source/Core/VideoCommon/Resources/CustomResourceManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp b/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp index 56556285d8f5..ffb16b055a43 100644 --- a/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp +++ b/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp @@ -31,7 +31,10 @@ void CustomResourceManager::Initialize() void CustomResourceManager::Shutdown() { if (m_async_shader_compiler) + { m_async_shader_compiler->StopWorkerThreads(); + m_async_shader_compiler->ClearAllWork(); + } m_asset_cache.Shutdown(); m_worker_thread.Shutdown(); From c2176989658af19dc425668a650a95ae78bb61ad Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Thu, 27 Nov 2025 18:27:25 -0600 Subject: [PATCH 073/267] GameSettings: Added comments with the rationale for disabling ImmediateXFB for many games. --- Data/Sys/GameSettings/DLS.ini | 1 + Data/Sys/GameSettings/E62.ini | 1 + Data/Sys/GameSettings/E63.ini | 3 ++- Data/Sys/GameSettings/E6V.ini | 1 + Data/Sys/GameSettings/E6W.ini | 1 + Data/Sys/GameSettings/E6X.ini | 1 + Data/Sys/GameSettings/G2V.ini | 2 +- Data/Sys/GameSettings/G4C.ini | 1 + Data/Sys/GameSettings/G5N.ini | 1 + Data/Sys/GameSettings/G6Q.ini | 1 + Data/Sys/GameSettings/GAP.ini | 1 + Data/Sys/GameSettings/GAU.ini | 4 ++-- Data/Sys/GameSettings/GAY.ini | 1 + Data/Sys/GameSettings/GBH.ini | 2 +- Data/Sys/GameSettings/GBL.ini | 4 ++-- Data/Sys/GameSettings/GBM.ini | 3 ++- Data/Sys/GameSettings/GBV.ini | 3 ++- Data/Sys/GameSettings/GBW.ini | 2 +- Data/Sys/GameSettings/GC2.ini | 1 + Data/Sys/GameSettings/GC8JA4.ini | 1 + Data/Sys/GameSettings/GCA.ini | 1 + Data/Sys/GameSettings/GCE.ini | 1 + Data/Sys/GameSettings/GCN.ini | 1 + Data/Sys/GameSettings/GCVEEB.ini | 1 + Data/Sys/GameSettings/GDD.ini | 1 + Data/Sys/GameSettings/GDG.ini | 4 ++-- Data/Sys/GameSettings/GDT.ini | 3 ++- Data/Sys/GameSettings/GE3.ini | 1 + Data/Sys/GameSettings/GEO.ini | 3 ++- Data/Sys/GameSettings/GF4.ini | 2 +- Data/Sys/GameSettings/GFD.ini | 2 +- Data/Sys/GameSettings/GFG.ini | 1 + Data/Sys/GameSettings/GGE.ini | 1 + Data/Sys/GameSettings/GGN.ini | 3 ++- Data/Sys/GameSettings/GGR.ini | 4 ++-- Data/Sys/GameSettings/GGY.ini | 4 ++-- Data/Sys/GameSettings/GH2.ini | 4 ++-- Data/Sys/GameSettings/GHN.ini | 1 + Data/Sys/GameSettings/GHS.ini | 4 ++-- Data/Sys/GameSettings/GHY.ini | 3 ++- Data/Sys/GameSettings/GIZ.ini | 3 ++- Data/Sys/GameSettings/GJB.ini | 1 + Data/Sys/GameSettings/GJD.ini | 1 + Data/Sys/GameSettings/GJF.ini | 1 + Data/Sys/GameSettings/GKH.ini | 1 + Data/Sys/GameSettings/GKS.ini | 1 + Data/Sys/GameSettings/GKZ.ini | 3 ++- Data/Sys/GameSettings/GLR.ini | 1 + Data/Sys/GameSettings/GLS.ini | 1 + Data/Sys/GameSettings/GM3.ini | 1 + Data/Sys/GameSettings/GMD.ini | 1 + Data/Sys/GameSettings/GMX.ini | 1 + Data/Sys/GameSettings/GNE.ini | 1 + Data/Sys/GameSettings/GO2.ini | 1 + Data/Sys/GameSettings/GP2.ini | 1 + Data/Sys/GameSettings/GPK.ini | 4 ++-- Data/Sys/GameSettings/GQX.ini | 1 + Data/Sys/GameSettings/GRH.ini | 4 ++-- Data/Sys/GameSettings/GRY.ini | 2 +- Data/Sys/GameSettings/GSM.ini | 1 + Data/Sys/GameSettings/GSQ.ini | 9 +++------ Data/Sys/GameSettings/GST.ini | 1 + Data/Sys/GameSettings/GSW.ini | 1 + Data/Sys/GameSettings/GT3.ini | 1 + Data/Sys/GameSettings/GT6.ini | 1 + Data/Sys/GameSettings/GT7.ini | 4 ++-- Data/Sys/GameSettings/GTY.ini | 2 +- Data/Sys/GameSettings/GTZ.ini | 3 ++- Data/Sys/GameSettings/GVC.ini | 2 +- Data/Sys/GameSettings/GVJ.ini | 4 ++-- Data/Sys/GameSettings/GVO.ini | 3 ++- Data/Sys/GameSettings/GVR.ini | 1 + Data/Sys/GameSettings/GW7.ini | 3 ++- Data/Sys/GameSettings/GWY.ini | 3 ++- Data/Sys/GameSettings/GX3.ini | 1 + Data/Sys/GameSettings/GXM.ini | 3 ++- Data/Sys/GameSettings/GYT.ini | 3 ++- Data/Sys/GameSettings/L.ini | 1 + Data/Sys/GameSettings/LAD.ini | 1 + Data/Sys/GameSettings/LAK.ini | 1 + Data/Sys/GameSettings/LAL.ini | 1 + Data/Sys/GameSettings/LAO.ini | 1 + Data/Sys/GameSettings/LAP.ini | 3 ++- Data/Sys/GameSettings/MAK.ini | 5 ++--- Data/Sys/GameSettings/MBA.ini | 1 + Data/Sys/GameSettings/MCD.ini | 5 ++--- Data/Sys/GameSettings/MCS.ini | 5 ++--- Data/Sys/GameSettings/MCT.ini | 1 + Data/Sys/GameSettings/MCW.ini | 5 ++--- Data/Sys/GameSettings/MCY.ini | 1 + Data/Sys/GameSettings/MCZ.ini | 3 ++- Data/Sys/GameSettings/PGS.ini | 3 ++- Data/Sys/GameSettings/R2G.ini | 4 ++-- Data/Sys/GameSettings/R7G.ini | 4 ++-- Data/Sys/GameSettings/RBO.ini | 1 + Data/Sys/GameSettings/RG6.ini | 1 + Data/Sys/GameSettings/RGW.ini | 1 + Data/Sys/GameSettings/RH8.ini | 2 +- Data/Sys/GameSettings/RJ2.ini | 3 ++- Data/Sys/GameSettings/RLJ.ini | 3 ++- Data/Sys/GameSettings/RM9.ini | 1 + Data/Sys/GameSettings/RO3.ini | 2 +- Data/Sys/GameSettings/RSX.ini | 1 + Data/Sys/GameSettings/RT3.ini | 8 +++----- Data/Sys/GameSettings/RTZ.ini | 4 ++-- Data/Sys/GameSettings/RXX.ini | 1 + Data/Sys/GameSettings/RYI.ini | 1 + Data/Sys/GameSettings/SDM.ini | 1 + Data/Sys/GameSettings/SGV.ini | 1 + Data/Sys/GameSettings/SLW.ini | 1 + Data/Sys/GameSettings/SOJ.ini | 1 + Data/Sys/GameSettings/SOM.ini | 1 + Data/Sys/GameSettings/SU7.ini | 8 +++----- Data/Sys/GameSettings/SVZ.ini | 1 + Data/Sys/GameSettings/W3M.ini | 3 ++- Data/Sys/GameSettings/WA2.ini | 3 ++- Data/Sys/GameSettings/WB2.ini | 8 +++----- Data/Sys/GameSettings/WB3.ini | 8 +++----- Data/Sys/GameSettings/WB6.ini | 8 +++----- Data/Sys/GameSettings/WB7.ini | 3 ++- Data/Sys/GameSettings/WB8.ini | 3 ++- Data/Sys/GameSettings/WBX.ini | 8 +++----- Data/Sys/GameSettings/WBY.ini | 8 +++----- Data/Sys/GameSettings/WBZ.ini | 8 +++----- Data/Sys/GameSettings/WCH.ini | 3 ++- Data/Sys/GameSettings/WDO.ini | 3 ++- Data/Sys/GameSettings/WFH.ini | 3 ++- Data/Sys/GameSettings/WFU.ini | 8 +++----- Data/Sys/GameSettings/WGG.ini | 3 ++- Data/Sys/GameSettings/WGL.ini | 1 + Data/Sys/GameSettings/WHF.ini | 3 ++- Data/Sys/GameSettings/WHP.ini | 1 + Data/Sys/GameSettings/WIB.ini | 1 + Data/Sys/GameSettings/WJA.ini | 3 ++- Data/Sys/GameSettings/WKD.ini | 3 ++- Data/Sys/GameSettings/WLE.ini | 11 ++--------- Data/Sys/GameSettings/WLN.ini | 11 ++--------- Data/Sys/GameSettings/WLZ.ini | 3 ++- Data/Sys/GameSettings/WMA.ini | 1 + Data/Sys/GameSettings/WMB.ini | 4 ++-- Data/Sys/GameSettings/WMG.ini | 1 + Data/Sys/GameSettings/WOY.ini | 9 +++------ Data/Sys/GameSettings/WP4.ini | 14 ++------------ Data/Sys/GameSettings/WR2.ini | 1 + Data/Sys/GameSettings/WSR.ini | 1 + Data/Sys/GameSettings/WW2.ini | 3 ++- Data/Sys/GameSettings/WW3.ini | 3 ++- Data/Sys/GameSettings/WWA.ini | 1 + Data/Sys/GameSettings/WWI.ini | 3 ++- Data/Sys/GameSettings/WXR.ini | 3 ++- Data/Sys/GameSettings/WZI.ini | 3 ++- Data/Sys/GameSettings/XHR.ini | 5 +++++ Data/Sys/GameSettings/XIN.ini | 5 +++++ Data/Sys/GameSettings/XIO.ini | 5 +++++ Data/Sys/GameSettings/XIP.ini | 5 +++++ 155 files changed, 252 insertions(+), 176 deletions(-) create mode 100644 Data/Sys/GameSettings/XHR.ini create mode 100644 Data/Sys/GameSettings/XIN.ini create mode 100644 Data/Sys/GameSettings/XIO.ini create mode 100644 Data/Sys/GameSettings/XIP.ini diff --git a/Data/Sys/GameSettings/DLS.ini b/Data/Sys/GameSettings/DLS.ini index 8e4e3addcfd2..dd526a78e7a9 100644 --- a/Data/Sys/GameSettings/DLS.ini +++ b/Data/Sys/GameSettings/DLS.ini @@ -16,4 +16,5 @@ MMU = True [Video_Hacks] EFBToTextureEnable = False +# Avoids majorly corrupted graphics in menus. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/E62.ini b/Data/Sys/GameSettings/E62.ini index c5511f837896..e51aab17f4f8 100644 --- a/Data/Sys/GameSettings/E62.ini +++ b/Data/Sys/GameSettings/E62.ini @@ -14,4 +14,5 @@ CPUThread = False SafeTextureCacheColorSamples = 0 [Video_Hacks] +# Avoids majorly corrupted screen edges. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/E63.ini b/Data/Sys/GameSettings/E63.ini index d3b516299d6f..13bcbd859dbf 100644 --- a/Data/Sys/GameSettings/E63.ini +++ b/Data/Sys/GameSettings/E63.ini @@ -1,4 +1,4 @@ -# E63E8P - Shinobi +# E63E8P, E63P8P, E63J8P - Shinobi [Core] # Values set here will override the main Dolphin settings. @@ -14,4 +14,5 @@ CPUThread = False SafeTextureCacheColorSamples = 0 [Video_Hacks] +# Avoids majorly corrupted screen edges. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/E6V.ini b/Data/Sys/GameSettings/E6V.ini index 18ab424e44d9..2ba892fdc569 100644 --- a/Data/Sys/GameSettings/E6V.ini +++ b/Data/Sys/GameSettings/E6V.ini @@ -13,4 +13,5 @@ SafeTextureCacheColorSamples = 0 [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/E6W.ini b/Data/Sys/GameSettings/E6W.ini index baec48c40e69..0d7098155503 100644 --- a/Data/Sys/GameSettings/E6W.ini +++ b/Data/Sys/GameSettings/E6W.ini @@ -14,4 +14,5 @@ CPUThread = False SafeTextureCacheColorSamples = 0 [Video_Hacks] +# Avoids majorly corrupted screen edges. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/E6X.ini b/Data/Sys/GameSettings/E6X.ini index f50445f8347e..a8470581465c 100644 --- a/Data/Sys/GameSettings/E6X.ini +++ b/Data/Sys/GameSettings/E6X.ini @@ -14,4 +14,5 @@ CPUThread = False SafeTextureCacheColorSamples = 0 [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/G2V.ini b/Data/Sys/GameSettings/G2V.ini index d514c6b521f6..784840c7f613 100644 --- a/Data/Sys/GameSettings/G2V.ini +++ b/Data/Sys/GameSettings/G2V.ini @@ -10,5 +10,5 @@ # Add action replay cheats here. [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/G4C.ini b/Data/Sys/GameSettings/G4C.ini index a8c75d7fd39e..b27ba4ac53c8 100644 --- a/Data/Sys/GameSettings/G4C.ini +++ b/Data/Sys/GameSettings/G4C.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/G5N.ini b/Data/Sys/GameSettings/G5N.ini index 509b466777c9..f4948b25d72b 100644 --- a/Data/Sys/GameSettings/G5N.ini +++ b/Data/Sys/GameSettings/G5N.ini @@ -13,4 +13,5 @@ SafeTextureCacheColorSamples = 0 [Video_Hacks] +# Avoids flickering during initial loading screen and terrible pacing during game selection. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/G6Q.ini b/Data/Sys/GameSettings/G6Q.ini index afe1c66dcb30..b205f2692318 100644 --- a/Data/Sys/GameSettings/G6Q.ini +++ b/Data/Sys/GameSettings/G6Q.ini @@ -13,4 +13,5 @@ SafeTextureCacheColorSamples = 0 [Video_Hacks] +# Avoids stuck screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GAP.ini b/Data/Sys/GameSettings/GAP.ini index 594df5adeb6f..8944cf281e5b 100644 --- a/Data/Sys/GameSettings/GAP.ini +++ b/Data/Sys/GameSettings/GAP.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GAU.ini b/Data/Sys/GameSettings/GAU.ini index e424907df514..ceafa32032e9 100644 --- a/Data/Sys/GameSettings/GAU.ini +++ b/Data/Sys/GameSettings/GAU.ini @@ -1,4 +1,4 @@ -# GAUE08, GAUJ08 - auto modellista +# GAUE08, GAUJ08 - Auto Modellista [Core] # Values set here will override the main Dolphin settings. @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids constant flickering while in game. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GAY.ini b/Data/Sys/GameSettings/GAY.ini index ef9cb81b8db1..46dcb0b37410 100644 --- a/Data/Sys/GameSettings/GAY.ini +++ b/Data/Sys/GameSettings/GAY.ini @@ -13,4 +13,5 @@ SafeTextureCacheColorSamples = 0 [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GBH.ini b/Data/Sys/GameSettings/GBH.ini index 47f5878bd13a..2df1c0de1e70 100644 --- a/Data/Sys/GameSettings/GBH.ini +++ b/Data/Sys/GameSettings/GBH.ini @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GBL.ini b/Data/Sys/GameSettings/GBL.ini index 9e369dfd2cad..db92817cc7d8 100644 --- a/Data/Sys/GameSettings/GBL.ini +++ b/Data/Sys/GameSettings/GBL.ini @@ -1,4 +1,4 @@ -# GBLE52, GBLP52 - BLOODY ROAR(R): PRIMAL FURY +# GBLE52, GBLP52, GBRJ18 - Bloody Roar: Primal Fury [Core] # Values set here will override the main Dolphin settings. @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens in opening cinematics. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GBM.ini b/Data/Sys/GameSettings/GBM.ini index 5e08dd1797ca..e370ff515e25 100644 --- a/Data/Sys/GameSettings/GBM.ini +++ b/Data/Sys/GameSettings/GBM.ini @@ -1,4 +1,4 @@ -# GBME7F, GBMJ28, GBMP7F - BATMAN: DARK TOMORROW +# GBME7F, GBMJ28, GBMP7F - Batman: Dark Tomorrow [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GBV.ini b/Data/Sys/GameSettings/GBV.ini index 410933988716..02b81b12c4c4 100644 --- a/Data/Sys/GameSettings/GBV.ini +++ b/Data/Sys/GameSettings/GBV.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] -ImmediateXFBEnable = False \ No newline at end of file +# Avoids black screens during FMVs. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GBW.ini b/Data/Sys/GameSettings/GBW.ini index f723f50d751e..d6e125b6cccb 100644 --- a/Data/Sys/GameSettings/GBW.ini +++ b/Data/Sys/GameSettings/GBW.ini @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck screens during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GC2.ini b/Data/Sys/GameSettings/GC2.ini index 77e6ab51d831..6bfee54a3aa3 100644 --- a/Data/Sys/GameSettings/GC2.ini +++ b/Data/Sys/GameSettings/GC2.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GC8JA4.ini b/Data/Sys/GameSettings/GC8JA4.ini index 68f5247e3c2b..6b4a9ff712f8 100644 --- a/Data/Sys/GameSettings/GC8JA4.ini +++ b/Data/Sys/GameSettings/GC8JA4.ini @@ -18,6 +18,7 @@ $Fix C4 texture tiling (used for buttons and some character icons) [Video_Settings] [Video_Hacks] +# Avoids black screen FMVs, flickering in menus, and broken loading screens. ImmediateXFBEnable = False [AR_RetroAchievements_Verified] diff --git a/Data/Sys/GameSettings/GCA.ini b/Data/Sys/GameSettings/GCA.ini index 7c40a9a9687a..92b6581fb8e8 100644 --- a/Data/Sys/GameSettings/GCA.ini +++ b/Data/Sys/GameSettings/GCA.ini @@ -10,4 +10,5 @@ # Add action replay cheats here. [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GCE.ini b/Data/Sys/GameSettings/GCE.ini index acaf8cc25de2..06c5aa370a88 100644 --- a/Data/Sys/GameSettings/GCE.ini +++ b/Data/Sys/GameSettings/GCE.ini @@ -4,4 +4,5 @@ [ActionReplay] [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GCN.ini b/Data/Sys/GameSettings/GCN.ini index 5fcad61ff5e7..2d894502fcfb 100644 --- a/Data/Sys/GameSettings/GCN.ini +++ b/Data/Sys/GameSettings/GCN.ini @@ -18,6 +18,7 @@ $Fix C4 texture tiling (used for buttons and some character icons) [Video_Settings] [Video_Hacks] +# Avoids black screen FMVs, flickering in menus, and broken loading screens. ImmediateXFBEnable = False [AR_RetroAchievements_Verified] diff --git a/Data/Sys/GameSettings/GCVEEB.ini b/Data/Sys/GameSettings/GCVEEB.ini index ddcdb12d8714..7577f1c9edef 100644 --- a/Data/Sys/GameSettings/GCVEEB.ini +++ b/Data/Sys/GameSettings/GCVEEB.ini @@ -4,6 +4,7 @@ # Add memory patches to be applied every frame here. [Video_Hacks] +# Avoids shifted screen. ImmediateXFBEnable = False [ActionReplay] diff --git a/Data/Sys/GameSettings/GDD.ini b/Data/Sys/GameSettings/GDD.ini index e622fd586f71..b00489c1bff8 100644 --- a/Data/Sys/GameSettings/GDD.ini +++ b/Data/Sys/GameSettings/GDD.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GDG.ini b/Data/Sys/GameSettings/GDG.ini index 27c2f4d1031f..fc71f8b61e4a 100644 --- a/Data/Sys/GameSettings/GDG.ini +++ b/Data/Sys/GameSettings/GDG.ini @@ -1,4 +1,4 @@ -# GDGE7H, GDGP78 - Dragon's Lair 3D +# GDGE7H, GDGP78 - Dragon's Lair 3D: Return to the Lair [Core] # Values set here will override the main Dolphin settings. @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck screens during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GDT.ini b/Data/Sys/GameSettings/GDT.ini index 56a77d17d239..030ec0246eb3 100644 --- a/Data/Sys/GameSettings/GDT.ini +++ b/Data/Sys/GameSettings/GDT.ini @@ -1,4 +1,4 @@ -# GDTE69, GDTP69 - Def Jam VENDETTA +# GDTE69, GDTP69 - Def Jam Vendetta [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GE3.ini b/Data/Sys/GameSettings/GE3.ini index 9528536dc513..b7d6b6dc9218 100644 --- a/Data/Sys/GameSettings/GE3.ini +++ b/Data/Sys/GameSettings/GE3.ini @@ -13,4 +13,5 @@ SafeTextureCacheColorSamples = 0 [Video_Hacks] +# Intro FMVs are uncapped and slow to emulate. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GEO.ini b/Data/Sys/GameSettings/GEO.ini index 378abdec39ef..385e8edcde33 100644 --- a/Data/Sys/GameSettings/GEO.ini +++ b/Data/Sys/GameSettings/GEO.ini @@ -1,4 +1,4 @@ -# GEOE08, GEOP08 - CAPCOM VS. SNK 2 EO +# GEOE08, GEOP08 - Capcom vs. SNK 2 EO [Core] # Values set here will override the main Dolphin settings. @@ -13,4 +13,5 @@ SafeTextureCacheColorSamples = 512 [Video_Hacks] +# Avoids subtle flickering in menu and severe flickering in game. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GF4.ini b/Data/Sys/GameSettings/GF4.ini index f23b1d82f701..72ccfa0d6011 100644 --- a/Data/Sys/GameSettings/GF4.ini +++ b/Data/Sys/GameSettings/GF4.ini @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids extraneous frames with terrible pacing and flickering in the UI. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GFD.ini b/Data/Sys/GameSettings/GFD.ini index ef4d314aa815..52c95732c455 100644 --- a/Data/Sys/GameSettings/GFD.ini +++ b/Data/Sys/GameSettings/GFD.ini @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids shifted display and constant black flickering. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GFG.ini b/Data/Sys/GameSettings/GFG.ini index 0adb66c07699..6bebb1bfdfcb 100644 --- a/Data/Sys/GameSettings/GFG.ini +++ b/Data/Sys/GameSettings/GFG.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GGE.ini b/Data/Sys/GameSettings/GGE.ini index 94bbb23e4fa5..6973902b75bb 100644 --- a/Data/Sys/GameSettings/GGE.ini +++ b/Data/Sys/GameSettings/GGE.ini @@ -14,4 +14,5 @@ [Video_Hacks] [Video_Hacks] +# Avoids extraneous frames with terrible pacing. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GGN.ini b/Data/Sys/GameSettings/GGN.ini index 3e7b6d6378d5..318021cae91c 100644 --- a/Data/Sys/GameSettings/GGN.ini +++ b/Data/Sys/GameSettings/GGN.ini @@ -1,4 +1,4 @@ -# GGNE5D - The Grim Adventures of Billy & Mandy +# GGNE5D - The Grim Adventures of Billy & Mandy (GC) [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GGR.ini b/Data/Sys/GameSettings/GGR.ini index 8f70a01a2b3f..32e43f379efc 100644 --- a/Data/Sys/GameSettings/GGR.ini +++ b/Data/Sys/GameSettings/GGR.ini @@ -1,4 +1,4 @@ -# GGRE41 - TOM CLANCY'S GHOST RECON +# GGRE41, GGRP41, GGRD41 - Tom Clancy's Ghost Recon (GC) [Core] # Values set here will override the main Dolphin settings. @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GGY.ini b/Data/Sys/GameSettings/GGY.ini index 1b3810182c5d..ea8044aeec1d 100644 --- a/Data/Sys/GameSettings/GGY.ini +++ b/Data/Sys/GameSettings/GGY.ini @@ -1,4 +1,4 @@ -# GGYE41, GGYP41 - GR2GC +# GGYE41, GGYP41 - Tom Clancy's Ghost Recon 2 [Core] # Values set here will override the main Dolphin settings. @@ -13,5 +13,5 @@ SafeTextureCacheColorSamples = 512 [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GH2.ini b/Data/Sys/GameSettings/GH2.ini index 3c9d5cb18171..9c2fca42c879 100644 --- a/Data/Sys/GameSettings/GH2.ini +++ b/Data/Sys/GameSettings/GH2.ini @@ -1,4 +1,4 @@ -# GH2E69, GH2P69 - NFS: HP2 +# GH2E69, GH2P69 - Need for Speed: Hot Pursuit 2 [Core] # Values set here will override the main Dolphin settings. @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Game runs uncapped and is slow to emulate. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GHN.ini b/Data/Sys/GameSettings/GHN.ini index 692550fe5524..5c5ef425d2ef 100644 --- a/Data/Sys/GameSettings/GHN.ini +++ b/Data/Sys/GameSettings/GHN.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck screeens before title screen. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GHS.ini b/Data/Sys/GameSettings/GHS.ini index 163f6068c95a..8a42ace87138 100644 --- a/Data/Sys/GameSettings/GHS.ini +++ b/Data/Sys/GameSettings/GHS.ini @@ -1,4 +1,4 @@ -# GHSE69, GHSJ69, GHSP69, GHSX69, GHSY69 - Harry Potter COS +# GHSE69, GHSJ69, GHSP69, GHSX69, GHSY69 - Harry Potter and the Chamber of Secrets [Core] # Values set here will override the main Dolphin settings. @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck FMVs and flickering throughout the entire game. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GHY.ini b/Data/Sys/GameSettings/GHY.ini index 523b7cdf5420..07881e6e44f3 100644 --- a/Data/Sys/GameSettings/GHY.ini +++ b/Data/Sys/GameSettings/GHY.ini @@ -1,4 +1,4 @@ -# GHYE6S - HauntedMansion +# GHYE6S - The Haunted Mansion [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GIZ.ini b/Data/Sys/GameSettings/GIZ.ini index 856d200d679c..cae96d9c36bb 100644 --- a/Data/Sys/GameSettings/GIZ.ini +++ b/Data/Sys/GameSettings/GIZ.ini @@ -1,4 +1,4 @@ -# GIZE52 - TY the Tasmanian Tiger 3: Night of the Quinkan +# GIZE52 - Ty the Tasmanian Tiger 3: Night of the Quinkan [Core] # Values set here will override the main Dolphin settings. @@ -13,6 +13,7 @@ SafeTextureCacheColorSamples = 512 [Video_Hacks] +# Avoids shifted screen. ImmediateXFBEnable = False # Fixes missing splash logo at boot. EFBAccessEnable = True diff --git a/Data/Sys/GameSettings/GJB.ini b/Data/Sys/GameSettings/GJB.ini index e36dab918c7e..13a368f03ac1 100644 --- a/Data/Sys/GameSettings/GJB.ini +++ b/Data/Sys/GameSettings/GJB.ini @@ -13,5 +13,6 @@ SafeTextureCacheColorSamples = 512 [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GJD.ini b/Data/Sys/GameSettings/GJD.ini index 4312948d643a..29ba77bfec30 100644 --- a/Data/Sys/GameSettings/GJD.ini +++ b/Data/Sys/GameSettings/GJD.ini @@ -1,4 +1,5 @@ # GJDX7D, GJDE5S, GJDY7D - Judge Dredd: Dredd vs. Death [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GJF.ini b/Data/Sys/GameSettings/GJF.ini index 6f14276b354b..094b6e839e7b 100644 --- a/Data/Sys/GameSettings/GJF.ini +++ b/Data/Sys/GameSettings/GJF.ini @@ -13,6 +13,7 @@ SafeTextureCacheColorSamples = 512 [Video_Hacks] +# Avoids shifted screen. ImmediateXFBEnable = False # Fixes missing splash logo at boot. EFBAccessEnable = True diff --git a/Data/Sys/GameSettings/GKH.ini b/Data/Sys/GameSettings/GKH.ini index 932e6d711979..dafa54dfc04b 100644 --- a/Data/Sys/GameSettings/GKH.ini +++ b/Data/Sys/GameSettings/GKH.ini @@ -10,6 +10,7 @@ # Add action replay cheats here. [Video_Hacks] +# Avoids shifted screen. ImmediateXFBEnable = False # Fixes missing splash logo at boot. EFBAccessEnable = True diff --git a/Data/Sys/GameSettings/GKS.ini b/Data/Sys/GameSettings/GKS.ini index a2dd40b5d368..a2b363af2bae 100644 --- a/Data/Sys/GameSettings/GKS.ini +++ b/Data/Sys/GameSettings/GKS.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GKZ.ini b/Data/Sys/GameSettings/GKZ.ini index d4cb20af1a9a..1834fb6bd9ae 100644 --- a/Data/Sys/GameSettings/GKZ.ini +++ b/Data/Sys/GameSettings/GKZ.ini @@ -1,4 +1,4 @@ -# GKZD9G, GKZE9G, GKZF9G, GKZP54, GKZP9G - Codename: Kids Next Door +# GKZD9G, GKZE9G, GKZF9G, GKZP54, GKZP9G - Codename: Kids Next Door - Operation: V.I.D.E.O.G.A.M.E. [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GLR.ini b/Data/Sys/GameSettings/GLR.ini index 71381da14709..1f72e2d58a2c 100644 --- a/Data/Sys/GameSettings/GLR.ini +++ b/Data/Sys/GameSettings/GLR.ini @@ -16,5 +16,6 @@ MMU = True [Video_Hacks] EFBToTextureEnable = False +# Avoids majorly corrupted graphics in menus. ImmediateXFBEnable = False DeferEFBCopies = False diff --git a/Data/Sys/GameSettings/GLS.ini b/Data/Sys/GameSettings/GLS.ini index 4053751ec51c..9724b88c9393 100644 --- a/Data/Sys/GameSettings/GLS.ini +++ b/Data/Sys/GameSettings/GLS.ini @@ -13,4 +13,5 @@ CPUThread = False [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GM3.ini b/Data/Sys/GameSettings/GM3.ini index 51772982bc2e..b7a47d96d103 100644 --- a/Data/Sys/GameSettings/GM3.ini +++ b/Data/Sys/GameSettings/GM3.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs and flickering in menus. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GMD.ini b/Data/Sys/GameSettings/GMD.ini index 6f887d5de890..6cb0649d173d 100644 --- a/Data/Sys/GameSettings/GMD.ini +++ b/Data/Sys/GameSettings/GMD.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck periwinkle screens during FMVs and flickering in menus. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GMX.ini b/Data/Sys/GameSettings/GMX.ini index 9046c4c08fcd..c60afc251d74 100644 --- a/Data/Sys/GameSettings/GMX.ini +++ b/Data/Sys/GameSettings/GMX.ini @@ -15,4 +15,5 @@ EFBToTextureEnable = False [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GNE.ini b/Data/Sys/GameSettings/GNE.ini index 30e4051eb490..8354da0afc91 100644 --- a/Data/Sys/GameSettings/GNE.ini +++ b/Data/Sys/GameSettings/GNE.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GO2.ini b/Data/Sys/GameSettings/GO2.ini index 787c7e2fec78..838161010e3a 100644 --- a/Data/Sys/GameSettings/GO2.ini +++ b/Data/Sys/GameSettings/GO2.ini @@ -14,4 +14,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck screens before the title screen. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GP2.ini b/Data/Sys/GameSettings/GP2.ini index 069e3a755f42..fee2349d6fdc 100644 --- a/Data/Sys/GameSettings/GP2.ini +++ b/Data/Sys/GameSettings/GP2.ini @@ -12,5 +12,6 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GPK.ini b/Data/Sys/GameSettings/GPK.ini index 5a7bab56c9ea..29d36b96f58f 100644 --- a/Data/Sys/GameSettings/GPK.ini +++ b/Data/Sys/GameSettings/GPK.ini @@ -1,4 +1,4 @@ -# GPKE41 - DISNEY'S PK: OUT OF THE SHADOWS +# GPKE41, GDOP41 - Disney's PK: Out of the Shadows [Core] # Values set here will override the main Dolphin settings. @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GQX.ini b/Data/Sys/GameSettings/GQX.ini index 81f13b4e89b5..0b977e93970f 100644 --- a/Data/Sys/GameSettings/GQX.ini +++ b/Data/Sys/GameSettings/GQX.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck white screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GRH.ini b/Data/Sys/GameSettings/GRH.ini index 780a9f898c11..ab09e3f6e728 100644 --- a/Data/Sys/GameSettings/GRH.ini +++ b/Data/Sys/GameSettings/GRH.ini @@ -1,4 +1,4 @@ -# GRHE41, GRHP41 - RAYMAN 3 HOODLUM HAVOC +# GRHE41, GRHP41 - Rayman 3: Hoodlum Havoc [Core] # Values set here will override the main Dolphin settings. @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids flickering during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GRY.ini b/Data/Sys/GameSettings/GRY.ini index 466970da077e..02c51e397081 100644 --- a/Data/Sys/GameSettings/GRY.ini +++ b/Data/Sys/GameSettings/GRY.ini @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck screens during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GSM.ini b/Data/Sys/GameSettings/GSM.ini index 9ccb572795df..4190a2fcd5ff 100644 --- a/Data/Sys/GameSettings/GSM.ini +++ b/Data/Sys/GameSettings/GSM.ini @@ -15,4 +15,5 @@ SuggestedAspectRatio = 2 [Video_Hacks] +# Avoids stuck FMVs and black screen flickering while in game. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GSQ.ini b/Data/Sys/GameSettings/GSQ.ini index 9202b06bd583..8489e4c02aa1 100644 --- a/Data/Sys/GameSettings/GSQ.ini +++ b/Data/Sys/GameSettings/GSQ.ini @@ -1,8 +1,5 @@ -# GSQE78, GSQP78 - SpongeBob SquarePants ROTFD -[Core] -[OnFrame] -[ActionReplay] -[Gecko] -[Video_Settings] +# GSQE78, GSQP78 - SpongeBob SquarePants: Revenge of the Flying Dutchman + [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GST.ini b/Data/Sys/GameSettings/GST.ini index a62023a80b46..144c31f97c9a 100644 --- a/Data/Sys/GameSettings/GST.ini +++ b/Data/Sys/GameSettings/GST.ini @@ -15,4 +15,5 @@ MemoryCardSize = 2 [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GSW.ini b/Data/Sys/GameSettings/GSW.ini index dfd4a93c717d..cd0c1a34b7ce 100644 --- a/Data/Sys/GameSettings/GSW.ini +++ b/Data/Sys/GameSettings/GSW.ini @@ -17,4 +17,5 @@ MMU = True [Video_Hacks] EFBToTextureEnable = False EFBEmulateFormatChanges = True +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GT3.ini b/Data/Sys/GameSettings/GT3.ini index 4a26fc2553e9..54ccc1b5acf9 100644 --- a/Data/Sys/GameSettings/GT3.ini +++ b/Data/Sys/GameSettings/GT3.ini @@ -15,4 +15,5 @@ CPUThread = False [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GT6.ini b/Data/Sys/GameSettings/GT6.ini index 12cf82d82f5e..c374fde2ecd4 100644 --- a/Data/Sys/GameSettings/GT6.ini +++ b/Data/Sys/GameSettings/GT6.ini @@ -10,4 +10,5 @@ # Add action replay cheats here. [Video_Hacks] +# Avoids flickering in pause menu and in game. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GT7.ini b/Data/Sys/GameSettings/GT7.ini index 982b349153f0..4183c7143642 100644 --- a/Data/Sys/GameSettings/GT7.ini +++ b/Data/Sys/GameSettings/GT7.ini @@ -1,4 +1,4 @@ -# GT7E41, GT7P41, GT7X41 - TOM CLANCY'S SPLINTER CELL PANDORA TOMORROW +# GT7E41, GT7P41, GT7X41 - Tom Clancy's Splinter Cell: Pandora Tomorrow [Core] # Values set here will override the main Dolphin settings. @@ -13,5 +13,5 @@ SafeTextureCacheColorSamples = 512 [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GTY.ini b/Data/Sys/GameSettings/GTY.ini index ff325b24daf0..7492a5819c3e 100644 --- a/Data/Sys/GameSettings/GTY.ini +++ b/Data/Sys/GameSettings/GTY.ini @@ -1,4 +1,4 @@ -# GYTE69, GYTP69 - TY the Tasmanian Tiger +# GYTE69, GYTP69 - Ty the Tasmanian Tiger [Core] # Values set here will override the main Dolphin settings. diff --git a/Data/Sys/GameSettings/GTZ.ini b/Data/Sys/GameSettings/GTZ.ini index ab27ff1e0440..c7f8a0b2e1a3 100644 --- a/Data/Sys/GameSettings/GTZ.ini +++ b/Data/Sys/GameSettings/GTZ.ini @@ -1,4 +1,4 @@ -# GTZE41, GTZP41 - DISNEY'S TARZAN +# GTZE41, GTZP41 - Disney's Tarzan Untamed [Core] # Values set here will override the main Dolphin settings. @@ -12,5 +12,6 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GVC.ini b/Data/Sys/GameSettings/GVC.ini index 1fc9f78f14de..1b44e3f06cc4 100644 --- a/Data/Sys/GameSettings/GVC.ini +++ b/Data/Sys/GameSettings/GVC.ini @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GVJ.ini b/Data/Sys/GameSettings/GVJ.ini index 01085eb483bf..2599e365f7e8 100644 --- a/Data/Sys/GameSettings/GVJ.ini +++ b/Data/Sys/GameSettings/GVJ.ini @@ -1,4 +1,4 @@ -# GVJE08, GVJJ08, GVJP08 - VIEWTIFUL JOE +# GVJE08, GVJJ08, GVJP08 - Viewtiful Joe [Core] # Values set here will override the main Dolphin settings. @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/GVO.ini b/Data/Sys/GameSettings/GVO.ini index 90f10c432383..38755e4353e9 100644 --- a/Data/Sys/GameSettings/GVO.ini +++ b/Data/Sys/GameSettings/GVO.ini @@ -1,4 +1,4 @@ -# GVOE69, GVOP69 - BIONICLE +# GVOE69, GVOP69 - Bionicle: The Game [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GVR.ini b/Data/Sys/GameSettings/GVR.ini index 6274b0d6787a..259184d58035 100644 --- a/Data/Sys/GameSettings/GVR.ini +++ b/Data/Sys/GameSettings/GVR.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids constant flickering while in game. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GW7.ini b/Data/Sys/GameSettings/GW7.ini index 1cd8b5ba8bd8..4757067af5ec 100644 --- a/Data/Sys/GameSettings/GW7.ini +++ b/Data/Sys/GameSettings/GW7.ini @@ -1,4 +1,4 @@ -# GW7D69, GW7E69, GW7F69, GW7P69 - 007: Agent Under Fire (tm) +# GW7D69, GW7E69, GW7F69, GW7P69 - 007: Agent Under Fire [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids flashes of green and cyan frames during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GWY.ini b/Data/Sys/GameSettings/GWY.ini index 0cb0958467c4..91ab3f8c4442 100644 --- a/Data/Sys/GameSettings/GWY.ini +++ b/Data/Sys/GameSettings/GWY.ini @@ -1,4 +1,4 @@ -# GWYE41, GWYX41 - Tom Clancy's Splinter Cell Double Agent +# GWYE41, GWYX41 - Tom Clancy's Splinter Cell Double Agent (GC) [Core] # Values set here will override the main Dolphin settings. @@ -16,5 +16,6 @@ MMU = True SafeTextureCacheColorSamples = 512 [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False EFBToTextureEnable = False diff --git a/Data/Sys/GameSettings/GX3.ini b/Data/Sys/GameSettings/GX3.ini index ca96afb1e08d..0d8d0a90e029 100644 --- a/Data/Sys/GameSettings/GX3.ini +++ b/Data/Sys/GameSettings/GX3.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GXM.ini b/Data/Sys/GameSettings/GXM.ini index 862f6f27c8ae..5ab29e9f2c95 100644 --- a/Data/Sys/GameSettings/GXM.ini +++ b/Data/Sys/GameSettings/GXM.ini @@ -1,4 +1,4 @@ -# GXME52, GXMF52, GXMP52 - X-Men Next Dimension +# GXME52, GXMF52, GXMP52 - X-Men: Next Dimension [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GYT.ini b/Data/Sys/GameSettings/GYT.ini index 343d60b3bc79..a18ce04826e0 100644 --- a/Data/Sys/GameSettings/GYT.ini +++ b/Data/Sys/GameSettings/GYT.ini @@ -1,4 +1,4 @@ -# GYTE69, GYTP69 - TY the Tasmanian Tiger 2: Bush Rescue +# GYTE69, GYTP69 - Ty the Tasmanian Tiger 2: Bush Rescue [Core] # Values set here will override the main Dolphin settings. @@ -10,6 +10,7 @@ # Add action replay cheats here. [Video_Hacks] +# Avoids shifted screen. ImmediateXFBEnable = False # Fixes missing splash logo at boot. EFBAccessEnable = True diff --git a/Data/Sys/GameSettings/L.ini b/Data/Sys/GameSettings/L.ini index 75d4996f923d..19a67d4322ad 100644 --- a/Data/Sys/GameSettings/L.ini +++ b/Data/Sys/GameSettings/L.ini @@ -8,4 +8,5 @@ SuggestedAspectRatio = 2 SafeTextureCacheColorSamples = 0 [Video_Hacks] +# Avoids shifted and/or improperly-scaled screen. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/LAD.ini b/Data/Sys/GameSettings/LAD.ini index 315051140a05..ad056308797b 100644 --- a/Data/Sys/GameSettings/LAD.ini +++ b/Data/Sys/GameSettings/LAD.ini @@ -3,4 +3,5 @@ [Video_Hacks] # Fixes purple screen. XFBToTextureEnable = False +# Avoids shifted screen. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/LAK.ini b/Data/Sys/GameSettings/LAK.ini index 35488a56d45d..82c7634c8499 100644 --- a/Data/Sys/GameSettings/LAK.ini +++ b/Data/Sys/GameSettings/LAK.ini @@ -3,4 +3,5 @@ [Video_Hacks] # Fixes purple screen. XFBToTextureEnable = False +# Avoids shifted screen. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/LAL.ini b/Data/Sys/GameSettings/LAL.ini index 38ac8e87c929..7b5f28567d3d 100644 --- a/Data/Sys/GameSettings/LAL.ini +++ b/Data/Sys/GameSettings/LAL.ini @@ -3,4 +3,5 @@ [Video_Hacks] # Fixes purple screen. XFBToTextureEnable = False +# Avoids shifted screen. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/LAO.ini b/Data/Sys/GameSettings/LAO.ini index ab8e956abc3a..aba13e4038be 100644 --- a/Data/Sys/GameSettings/LAO.ini +++ b/Data/Sys/GameSettings/LAO.ini @@ -3,4 +3,5 @@ [Video_Hacks] # Fixes purple screen. XFBToTextureEnable = False +# Avoids shifted screen. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/LAP.ini b/Data/Sys/GameSettings/LAP.ini index 986060e1d63d..fb784a03eea4 100644 --- a/Data/Sys/GameSettings/LAP.ini +++ b/Data/Sys/GameSettings/LAP.ini @@ -1,6 +1,7 @@ -# LAPP8P, LAPE8P Wonder Boy III: The Dragon's Trap +# LAPP8P, LAPE8P - Wonder Boy III: The Dragon's Trap [Video_Hacks] # Fixes purple screen. XFBToTextureEnable = False +# Avoids shifted screen. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MAK.ini b/Data/Sys/GameSettings/MAK.ini index 918c8e7ef8a3..27ba22b87d0c 100644 --- a/Data/Sys/GameSettings/MAK.ini +++ b/Data/Sys/GameSettings/MAK.ini @@ -1,6 +1,5 @@ -# MAKE8P - Shadow Dancer - -[Video_Settings] +# MAKE8P, MAKJ8P, MAKP8P - Shadow Dancer: The Secret of Shinobi [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MBA.ini b/Data/Sys/GameSettings/MBA.ini index 8c7cfa9ccf2f..5fc6032776b1 100644 --- a/Data/Sys/GameSettings/MBA.ini +++ b/Data/Sys/GameSettings/MBA.ini @@ -5,4 +5,5 @@ CPUThread = False [Video_Hacks] +# Avoids majorly corrupted screen edges. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MCD.ini b/Data/Sys/GameSettings/MCD.ini index b79bdbc02eb1..24ffb2c5c3f4 100644 --- a/Data/Sys/GameSettings/MCD.ini +++ b/Data/Sys/GameSettings/MCD.ini @@ -1,6 +1,5 @@ -# MCDE8P - Sonic & Knuckles - -[Video_Settings] +# MCDP8P, MCDE8P, MCDJ8P - Sonic & Knuckles [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MCS.ini b/Data/Sys/GameSettings/MCS.ini index e0adac7c87a0..38df077b6d20 100644 --- a/Data/Sys/GameSettings/MCS.ini +++ b/Data/Sys/GameSettings/MCS.ini @@ -1,6 +1,5 @@ -# MCSN8P - Monster Lair - -[Video_Settings] +# MCSN8P, MCSP8P, MCSJ8P - Wonder Boy III: Monster Lair [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MCT.ini b/Data/Sys/GameSettings/MCT.ini index c461ac16c9ed..d77df2c613e6 100644 --- a/Data/Sys/GameSettings/MCT.ini +++ b/Data/Sys/GameSettings/MCT.ini @@ -3,4 +3,5 @@ [Video_Hacks] # Fixes purple screen. XFBToTextureEnable = False +# Avoids shifted screen. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MCW.ini b/Data/Sys/GameSettings/MCW.ini index 71a66b9ade83..137d9337c9bc 100644 --- a/Data/Sys/GameSettings/MCW.ini +++ b/Data/Sys/GameSettings/MCW.ini @@ -1,6 +1,5 @@ -# MCWE8P - Galaxy Force II - -[Video_Settings] +# MCWE8P, MCWJ8P, MCWP8P - Galaxy Force II [Video_Hacks] +# Avoids majorly corrupted screen edges. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MCY.ini b/Data/Sys/GameSettings/MCY.ini index 97a6116b567b..d9b8d6a4badc 100644 --- a/Data/Sys/GameSettings/MCY.ini +++ b/Data/Sys/GameSettings/MCY.ini @@ -5,4 +5,5 @@ CPUThread = False [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/MCZ.ini b/Data/Sys/GameSettings/MCZ.ini index 79a6d49741d9..01484c56b004 100644 --- a/Data/Sys/GameSettings/MCZ.ini +++ b/Data/Sys/GameSettings/MCZ.ini @@ -1,7 +1,8 @@ -# MCZE8P - Shanghai II +# MCZP8P, MCZE8P - Shanghai II: Dragon's Eye [Video_Settings] SafeTextureCacheColorSamples = 0 [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/PGS.ini b/Data/Sys/GameSettings/PGS.ini index 863edac2c73a..c8d86c010705 100644 --- a/Data/Sys/GameSettings/PGS.ini +++ b/Data/Sys/GameSettings/PGS.ini @@ -1,4 +1,4 @@ -# PGSJ01 - METAL GEAR SOLID Special Disc +# PGSJ01 - Metal Gear Solid: Special Disc [Core] # Values set here will override the main Dolphin settings. @@ -10,6 +10,7 @@ # Add action replay cheats here. [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False [Video_Settings] diff --git a/Data/Sys/GameSettings/R2G.ini b/Data/Sys/GameSettings/R2G.ini index cb92094ad5ff..a895ccef3991 100644 --- a/Data/Sys/GameSettings/R2G.ini +++ b/Data/Sys/GameSettings/R2G.ini @@ -1,4 +1,4 @@ -# R2GEXJ, R2GJAF, R2GP99 - FRAGILE DREAMS +# R2GEXJ, R2GJAF, R2GP99 - Fragile Dreams: Farewell Ruins of the Moon [Core] # Values set here will override the main Dolphin settings. @@ -13,5 +13,5 @@ [Video_Hacks] EFBEmulateFormatChanges = True +# Avoids constant black flickering. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/R7G.ini b/Data/Sys/GameSettings/R7G.ini index 6bb4b7019369..144e688ff26f 100644 --- a/Data/Sys/GameSettings/R7G.ini +++ b/Data/Sys/GameSettings/R7G.ini @@ -1,4 +1,4 @@ -# R7GEAF, R7GJAF, R7GPAF - DragonBall +# R7GEAF, R7GJAF, R7GPAF - Dragon Ball: Revenge of King Piccolo [Core] # Values set here will override the main Dolphin settings. @@ -13,5 +13,5 @@ AccurateNaNs = True [Video_Settings] [Video_Hacks] +# Avoids constant black flickering. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/RBO.ini b/Data/Sys/GameSettings/RBO.ini index d01bbed817aa..5cc0a310fd6b 100644 --- a/Data/Sys/GameSettings/RBO.ini +++ b/Data/Sys/GameSettings/RBO.ini @@ -15,4 +15,5 @@ ForceTextureFiltering = 0 [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RG6.ini b/Data/Sys/GameSettings/RG6.ini index 06d850465a11..6f213984b8d1 100644 --- a/Data/Sys/GameSettings/RG6.ini +++ b/Data/Sys/GameSettings/RG6.ini @@ -10,4 +10,5 @@ # Add action replay cheats here. [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RGW.ini b/Data/Sys/GameSettings/RGW.ini index 0915a82ad991..af427d726bb4 100644 --- a/Data/Sys/GameSettings/RGW.ini +++ b/Data/Sys/GameSettings/RGW.ini @@ -18,6 +18,7 @@ SafeTextureCacheColorSamples = 0 [Video_Hacks] # Fixes visible lines in air vents/fans. VertexRounding = True +# Intro FMVs are uncapped and very slow to emulate. ImmediateXFBEnable = False # Fixes rabbid tattoo textures saving as black. EFBToTextureEnable = False diff --git a/Data/Sys/GameSettings/RH8.ini b/Data/Sys/GameSettings/RH8.ini index ae46dd3ca255..e34c3b4916d0 100644 --- a/Data/Sys/GameSettings/RH8.ini +++ b/Data/Sys/GameSettings/RH8.ini @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck black screens before the title screen. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/RJ2.ini b/Data/Sys/GameSettings/RJ2.ini index b4f4634f7c20..cc117ecf95ca 100644 --- a/Data/Sys/GameSettings/RJ2.ini +++ b/Data/Sys/GameSettings/RJ2.ini @@ -1,4 +1,4 @@ -# RJ2E52 - Quantum of Solace +# RJ2JGD, RJ2P52, RJ2E52 - Quantum of Solace [Core] # Values set here will override the main Dolphin settings. @@ -16,4 +16,5 @@ SafeTextureCacheColorSamples = 0 ForceTextureFiltering = 0 [Video_Hacks] +# Introduction is uncapped and slow to emulate. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RLJ.ini b/Data/Sys/GameSettings/RLJ.ini index 1d6283cc5340..9478e10c21a3 100644 --- a/Data/Sys/GameSettings/RLJ.ini +++ b/Data/Sys/GameSettings/RLJ.ini @@ -1,4 +1,4 @@ -# RLJPKM - Line Rider Freestyle +# RLJEHJ, RLJPKM - Line Rider: Freestyle [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck screen during opening FMV. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RM9.ini b/Data/Sys/GameSettings/RM9.ini index c1688e10c343..fe77cc8a15d8 100644 --- a/Data/Sys/GameSettings/RM9.ini +++ b/Data/Sys/GameSettings/RM9.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck screens during FMVs. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RO3.ini b/Data/Sys/GameSettings/RO3.ini index b41db11a972e..8c41b838fd59 100644 --- a/Data/Sys/GameSettings/RO3.ini +++ b/Data/Sys/GameSettings/RO3.ini @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids constant flickering. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/RSX.ini b/Data/Sys/GameSettings/RSX.ini index 4f249caf856d..d2b4fc4862d9 100644 --- a/Data/Sys/GameSettings/RSX.ini +++ b/Data/Sys/GameSettings/RSX.ini @@ -14,4 +14,5 @@ [Video_Hacks] [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RT3.ini b/Data/Sys/GameSettings/RT3.ini index 0c90538e5d8e..8164dc17b9ae 100644 --- a/Data/Sys/GameSettings/RT3.ini +++ b/Data/Sys/GameSettings/RT3.ini @@ -1,7 +1,5 @@ -# RT3E54, RT3JEL, RT3P54 - Rockstar Games presents Table Tennis -[Core] -[OnFrame] -[ActionReplay] -[Video_Settings] +# RT3E54, RT3JEL, RT3P54 - Rockstar Games Presents Table Tennis + [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RTZ.ini b/Data/Sys/GameSettings/RTZ.ini index 1865de7aacb7..c40bde31ccdc 100644 --- a/Data/Sys/GameSettings/RTZ.ini +++ b/Data/Sys/GameSettings/RTZ.ini @@ -1,4 +1,4 @@ -# RTZE08, RTZJ08, RTZK08, RTZP08 - Zack and Wiki: Quest for Barbaros' Treasure +# RTZE08, RTZJ08, RTZK08, RTZP08 - Zack & Wiki: Quest for Barbaros' Treasure [Core] # Values set here will override the main Dolphin settings. @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids constant flickering. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/RXX.ini b/Data/Sys/GameSettings/RXX.ini index bfffcbeb8c44..0b55248830b4 100644 --- a/Data/Sys/GameSettings/RXX.ini +++ b/Data/Sys/GameSettings/RXX.ini @@ -13,4 +13,5 @@ [Video_Hacks] EFBEmulateFormatChanges = True +# Avoids constant black flickering. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RYI.ini b/Data/Sys/GameSettings/RYI.ini index b3fedbbdd23a..92c3b03bb8b5 100644 --- a/Data/Sys/GameSettings/RYI.ini +++ b/Data/Sys/GameSettings/RYI.ini @@ -1,6 +1,7 @@ # RYIE9B, RYIPNK - SPRay [Video_Hacks] +# Avoids constant flickering. ImmediateXFBEnable = False [Video_Settings] diff --git a/Data/Sys/GameSettings/SDM.ini b/Data/Sys/GameSettings/SDM.ini index 0f14a0a822fe..9dd91367e727 100644 --- a/Data/Sys/GameSettings/SDM.ini +++ b/Data/Sys/GameSettings/SDM.ini @@ -13,4 +13,5 @@ [Video_Hacks] EFBToTextureEnable = False +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SGV.ini b/Data/Sys/GameSettings/SGV.ini index 16576592e777..b156c594038b 100644 --- a/Data/Sys/GameSettings/SGV.ini +++ b/Data/Sys/GameSettings/SGV.ini @@ -10,4 +10,5 @@ # Add action replay cheats here. [Video_Hacks] +# Avoids extra/incomplete frames in some minigames. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SLW.ini b/Data/Sys/GameSettings/SLW.ini index 4ef3eb3f52a1..bebdcafb7caf 100644 --- a/Data/Sys/GameSettings/SLW.ini +++ b/Data/Sys/GameSettings/SLW.ini @@ -14,4 +14,5 @@ SuggestedAspectRatio = 2 [Video_Hacks] ImmediateXFBEnable = False +# Avoids invisible cursor. XFBToTextureEnable = False diff --git a/Data/Sys/GameSettings/SOJ.ini b/Data/Sys/GameSettings/SOJ.ini index 4ad4d801ffc6..abb96e9b2b17 100644 --- a/Data/Sys/GameSettings/SOJ.ini +++ b/Data/Sys/GameSettings/SOJ.ini @@ -13,4 +13,5 @@ ForceTextureFiltering = 0 [Video_Hacks] +# Avoids incorrect aspect ratio in 4:3 mode. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SOM.ini b/Data/Sys/GameSettings/SOM.ini index b3bc682e6cf9..d662642771ad 100644 --- a/Data/Sys/GameSettings/SOM.ini +++ b/Data/Sys/GameSettings/SOM.ini @@ -10,5 +10,6 @@ # Add action replay cheats here. [Video_Hacks] +# Avoids "issues in some levels". ImmediateXFBEnable = False EFBToTextureEnable = False diff --git a/Data/Sys/GameSettings/SU7.ini b/Data/Sys/GameSettings/SU7.ini index b1e9656cb00f..48b6925fa4d4 100644 --- a/Data/Sys/GameSettings/SU7.ini +++ b/Data/Sys/GameSettings/SU7.ini @@ -1,7 +1,5 @@ -# SU7EG9, SU7PAF - RISE OF THE GUARDIANS -[Core] -[OnFrame] -[ActionReplay] -[Video_Settings] +# SU7EG9, SU7PAF - Rise of the Guardians + [Video_Hacks] +# Avoids constant flickering. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SVZ.ini b/Data/Sys/GameSettings/SVZ.ini index 241a8186cc49..8e6d0ff75eb6 100644 --- a/Data/Sys/GameSettings/SVZ.ini +++ b/Data/Sys/GameSettings/SVZ.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids constant black frame flickering. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/W3M.ini b/Data/Sys/GameSettings/W3M.ini index 15b1dde2c005..f89b3a3c1583 100644 --- a/Data/Sys/GameSettings/W3M.ini +++ b/Data/Sys/GameSettings/W3M.ini @@ -1,4 +1,4 @@ -# W3MELJ - The Three Musketeers +# W3MELJ, W3MPLJ - The Three Musketeers: One for all! [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids flickering HUD. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WA2.ini b/Data/Sys/GameSettings/WA2.ini index 373eec944a4f..9eac10608bec 100644 --- a/Data/Sys/GameSettings/WA2.ini +++ b/Data/Sys/GameSettings/WA2.ini @@ -1,4 +1,4 @@ -# WA2E01 - Magnetica Twist +# WA2P01, WA2E01, WA2J01 - Magnetica Twist [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WB2.ini b/Data/Sys/GameSettings/WB2.ini index 1a800abb0ae0..eae1258ac0c9 100644 --- a/Data/Sys/GameSettings/WB2.ini +++ b/Data/Sys/GameSettings/WB2.ini @@ -1,7 +1,5 @@ -# WB2ETL - Dangeresque 3 -[Core] -[OnFrame] -[ActionReplay] -[Video_Settings] +# WB2ETL, WB2PTL - Strong Bad's Cool Game for Attractive People - Episode 4: Dangeresque 3: The Criminal Projective + [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WB3.ini b/Data/Sys/GameSettings/WB3.ini index 2ff7fe68886f..f045307f9ca3 100644 --- a/Data/Sys/GameSettings/WB3.ini +++ b/Data/Sys/GameSettings/WB3.ini @@ -1,7 +1,5 @@ -# WB3ETL - 8-Bit Is Enough -[Core] -[OnFrame] -[ActionReplay] -[Video_Settings] +# WB3ETL, WB3PTL - Strong Bad's Cool Game for Attractive People - Episode 5: 8-Bit Is Enough + [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WB6.ini b/Data/Sys/GameSettings/WB6.ini index 172b232ba071..4013d8a6a819 100644 --- a/Data/Sys/GameSettings/WB6.ini +++ b/Data/Sys/GameSettings/WB6.ini @@ -1,7 +1,5 @@ -# WB6EGL - TV Show King -[Core] -[OnFrame] -[ActionReplay] -[Video_Settings] +# WB6PGL, WB6EGL, WB6JGL - TV Show King + [Video_Hacks] +# Avoids flickering. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WB7.ini b/Data/Sys/GameSettings/WB7.ini index dd4126ffdbc5..3b56c3b2bd25 100644 --- a/Data/Sys/GameSettings/WB7.ini +++ b/Data/Sys/GameSettings/WB7.ini @@ -1,4 +1,4 @@ -# WB7EGL - Midnight Pool +# WB7PGL, WB7JGL, WB7EGL - Midnight Pool [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WB8.ini b/Data/Sys/GameSettings/WB8.ini index 059f7388b162..b96e7db65f1a 100644 --- a/Data/Sys/GameSettings/WB8.ini +++ b/Data/Sys/GameSettings/WB8.ini @@ -1,4 +1,4 @@ -# WB8EGL, WB8PGL - Midnight Bowling +# WB8EGL, WB8PGL, WB8JGL - Midnight Bowling [Core] # Values set here will override the main Dolphin settings. @@ -10,4 +10,5 @@ # Add action replay cheats here. [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WBX.ini b/Data/Sys/GameSettings/WBX.ini index 0543fdec797e..f2e2773a077b 100644 --- a/Data/Sys/GameSettings/WBX.ini +++ b/Data/Sys/GameSettings/WBX.ini @@ -1,7 +1,5 @@ -# WBXETL - Homestar Ruiner -[Core] -[OnFrame] -[ActionReplay] -[Video_Settings] +# WBXETL, WBXPTL - Strong Bad's Cool Game for Attractive People - Episode 1: Homestar Ruiner + [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WBY.ini b/Data/Sys/GameSettings/WBY.ini index 62d3cbe121fa..dae8e017261f 100644 --- a/Data/Sys/GameSettings/WBY.ini +++ b/Data/Sys/GameSettings/WBY.ini @@ -1,7 +1,5 @@ -# WBYETL - StrongBadia the Free -[Core] -[OnFrame] -[ActionReplay] -[Video_Settings] +# WBYETL, WBYPTL - Strong Bad's Cool Game for Attractive People - Episode 2: Strong Badia the Free + [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WBZ.ini b/Data/Sys/GameSettings/WBZ.ini index c6922625d833..c85b12e88c4b 100644 --- a/Data/Sys/GameSettings/WBZ.ini +++ b/Data/Sys/GameSettings/WBZ.ini @@ -1,7 +1,5 @@ -# WBZETL - Baddest of the Bands -[Core] -[OnFrame] -[ActionReplay] -[Video_Settings] +# WBZETL, WBZPTL - Strong Bad's Cool Game for Attractive People - Episode 3: Baddest of the Bands + [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WCH.ini b/Data/Sys/GameSettings/WCH.ini index ff5bed4d0b53..bad837967080 100644 --- a/Data/Sys/GameSettings/WCH.ini +++ b/Data/Sys/GameSettings/WCH.ini @@ -1,4 +1,4 @@ -# WCHEJS - Chess Challenge! +# WCHPJS, WCHEJS - Chess Challenge! [Core] @@ -14,4 +14,5 @@ EFBToTextureEnable = False SuggestedAspectRatio = 2 [Video_Hacks] +# Avoids flickering. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WDO.ini b/Data/Sys/GameSettings/WDO.ini index 614e415d7c06..e3c00da66c44 100644 --- a/Data/Sys/GameSettings/WDO.ini +++ b/Data/Sys/GameSettings/WDO.ini @@ -1,4 +1,4 @@ -# WDOEA4 - Driift Mania +# WDOEA4, WDOPA4 - Driift Mania [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WFH.ini b/Data/Sys/GameSettings/WFH.ini index e712fe1ecebc..9064178fd12f 100644 --- a/Data/Sys/GameSettings/WFH.ini +++ b/Data/Sys/GameSettings/WFH.ini @@ -1,4 +1,4 @@ -# WFHEPT - Flight Control +# WFHEPT, WFHPPT - Flight Control [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids constant flickering. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WFU.ini b/Data/Sys/GameSettings/WFU.ini index 3b99b7e91344..84526b9ec593 100644 --- a/Data/Sys/GameSettings/WFU.ini +++ b/Data/Sys/GameSettings/WFU.ini @@ -1,7 +1,5 @@ -# WFUEQQ - Furry Legends -[Core] -[OnFrame] -[ActionReplay] -[Video_Settings] +# WFUEQQ, WFUPQQ - Furry Legends + [Video_Hacks] +# Avoids majorly broken graphics when in game. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WGG.ini b/Data/Sys/GameSettings/WGG.ini index 58799515f1b5..2c8fcd97ef2b 100644 --- a/Data/Sys/GameSettings/WGG.ini +++ b/Data/Sys/GameSettings/WGG.ini @@ -1,4 +1,4 @@ -# WGGEE9 - Gabrielle's Ghostly +# WGGEE9, WGGPE9, WGGJQ2 - Gabrielle's Ghostly Groove: Monster Mix [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids constant flickering. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WGL.ini b/Data/Sys/GameSettings/WGL.ini index 15c6cc16268b..d93d38ebfe0e 100644 --- a/Data/Sys/GameSettings/WGL.ini +++ b/Data/Sys/GameSettings/WGL.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WHF.ini b/Data/Sys/GameSettings/WHF.ini index 25e94f44fecd..7ce3d7aa922b 100644 --- a/Data/Sys/GameSettings/WHF.ini +++ b/Data/Sys/GameSettings/WHF.ini @@ -1,4 +1,4 @@ -# WHFETY - Heavy Fire Special Operations +# WHFETY, WHFPTY - Heavy Fire: Special Operations [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Game is uncapped and slow to emulate. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WHP.ini b/Data/Sys/GameSettings/WHP.ini index 04700b0466ad..ad449fc5b17a 100644 --- a/Data/Sys/GameSettings/WHP.ini +++ b/Data/Sys/GameSettings/WHP.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids extraneous frames with terrible pacing. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WIB.ini b/Data/Sys/GameSettings/WIB.ini index 26ba5827634d..d8ad73ed973d 100644 --- a/Data/Sys/GameSettings/WIB.ini +++ b/Data/Sys/GameSettings/WIB.ini @@ -14,4 +14,5 @@ [Video_Settings] [Video_Hacks] +# Avoids constant flickering. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WJA.ini b/Data/Sys/GameSettings/WJA.ini index 55b91d17f7e3..314eeff9eccf 100644 --- a/Data/Sys/GameSettings/WJA.ini +++ b/Data/Sys/GameSettings/WJA.ini @@ -1,4 +1,4 @@ -# WJAEYJ - Jam City Rollergirls +# WJAPYJ, WJAEYJ, XI8EYJ - Jam City Rollergirls [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WKD.ini b/Data/Sys/GameSettings/WKD.ini index 8b815321c337..2cd8c4656abd 100644 --- a/Data/Sys/GameSettings/WKD.ini +++ b/Data/Sys/GameSettings/WKD.ini @@ -1,4 +1,4 @@ -# WKDEGN - Pirates +# WKDEGN, WBRPGN - Pirates: The Key of Dreams [Core] # Values set here will override the main Dolphin settings. @@ -13,4 +13,5 @@ SuggestedAspectRatio = 2 [Video_Hacks] +# Avoids flickering UI elements. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WLE.ini b/Data/Sys/GameSettings/WLE.ini index daffb6432549..f7af8e51a340 100644 --- a/Data/Sys/GameSettings/WLE.ini +++ b/Data/Sys/GameSettings/WLE.ini @@ -1,12 +1,5 @@ -# WLEELU - PooYoos Episode 1 - -[Core] - -[OnFrame] - -[ActionReplay] - -[Video_Settings] +# WLEELU, WLEPLU, WLEJ2L - Learning with The PooYoos: Episode 1 [Video_Hacks] +# Avoids flickering elements. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WLN.ini b/Data/Sys/GameSettings/WLN.ini index 21664bb6b150..6237db5d4dcb 100644 --- a/Data/Sys/GameSettings/WLN.ini +++ b/Data/Sys/GameSettings/WLN.ini @@ -1,12 +1,5 @@ -# WLNELU - PooYoos Episode 2 - -[Core] - -[OnFrame] - -[ActionReplay] - -[Video_Settings] +# WLNELU, WLNPLU - Learning with The PooYoos: Episode 2 [Video_Hacks] +# Avoids flickering elements. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WLZ.ini b/Data/Sys/GameSettings/WLZ.ini index b3fa14f46d63..f14c62f63732 100644 --- a/Data/Sys/GameSettings/WLZ.ini +++ b/Data/Sys/GameSettings/WLZ.ini @@ -1,4 +1,4 @@ -# WLZEXY - lilt line +# WLZEXY, WLZPXY, XIAEXY - lilt line [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WMA.ini b/Data/Sys/GameSettings/WMA.ini index 816ee5d5f208..d572d0f0b165 100644 --- a/Data/Sys/GameSettings/WMA.ini +++ b/Data/Sys/GameSettings/WMA.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids flickering on the Wii strap screen and extraneous frames with bad pacing. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WMB.ini b/Data/Sys/GameSettings/WMB.ini index 80962f23aa94..8b685f5123e7 100644 --- a/Data/Sys/GameSettings/WMB.ini +++ b/Data/Sys/GameSettings/WMB.ini @@ -1,4 +1,4 @@ -# WMBE01, WMBP01 - Maboshi's Arcade +# WMBP01, WMBE01, WMBJ01 - Maboshi's Arcade [Core] # Values set here will override the main Dolphin settings. @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/WMG.ini b/Data/Sys/GameSettings/WMG.ini index efb396b3e11d..07662cdf932d 100644 --- a/Data/Sys/GameSettings/WMG.ini +++ b/Data/Sys/GameSettings/WMG.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WOY.ini b/Data/Sys/GameSettings/WOY.ini index ebd5a95be104..e2094a71132a 100644 --- a/Data/Sys/GameSettings/WOY.ini +++ b/Data/Sys/GameSettings/WOY.ini @@ -1,8 +1,5 @@ -# WOYEPS - Bit Boy!! -[Core] -[OnFrame] -[ActionReplay] -[Gecko] -[Video_Settings] +# WOYEPS, WOYPPS, WOYJ99 - Bit Boy!! + [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WP4.ini b/Data/Sys/GameSettings/WP4.ini index 0a90073d3fd7..130f1ee65c9b 100644 --- a/Data/Sys/GameSettings/WP4.ini +++ b/Data/Sys/GameSettings/WP4.ini @@ -1,15 +1,5 @@ -# WP4ELU - PooYoos - Episode 3 - -[Core] -# Values set here will override the main Dolphin settings. - -[OnFrame] -# Add memory patches to be applied every frame here. - -[ActionReplay] -# Add action replay cheats here. - -[Video_Settings] +# WP4ELU, WP4PLU - Learning with The PooYoos: Episode 3 [Video_Hacks] +# Avoids flickering elements. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WR2.ini b/Data/Sys/GameSettings/WR2.ini index 3c4a3f1a0fda..48885be4be0d 100644 --- a/Data/Sys/GameSettings/WR2.ini +++ b/Data/Sys/GameSettings/WR2.ini @@ -18,6 +18,7 @@ SafeTextureCacheColorSamples = 0 [Video_Hacks] # Fixes visible lines in air vents/fans. VertexRounding = True +# This game runs with an uncapped framerate. ImmediateXFBEnable = False # Fixes rabbid tattoo textures saving as black. EFBToTextureEnable = False diff --git a/Data/Sys/GameSettings/WSR.ini b/Data/Sys/GameSettings/WSR.ini index e186f5319eca..9a9d70b2e8b7 100644 --- a/Data/Sys/GameSettings/WSR.ini +++ b/Data/Sys/GameSettings/WSR.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids constant flickering. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WW2.ini b/Data/Sys/GameSettings/WW2.ini index e0c69b08f3af..e49648f8a49e 100644 --- a/Data/Sys/GameSettings/WW2.ini +++ b/Data/Sys/GameSettings/WW2.ini @@ -1,8 +1,9 @@ -# WW2P - Where's Wally? Fantastic Journey 2 +# WW2PQV - Where's Wally? Fantastic Journey 2 [Video_Settings] SuggestedAspectRatio = 2 [Video_Hacks] XFBToTextureEnable = False +# Avoids invisible cursor. ImmediateXFBenable = False diff --git a/Data/Sys/GameSettings/WW3.ini b/Data/Sys/GameSettings/WW3.ini index 77914a0e28f7..4768d48a4453 100644 --- a/Data/Sys/GameSettings/WW3.ini +++ b/Data/Sys/GameSettings/WW3.ini @@ -1,8 +1,9 @@ -# WW3P - Where's Wally? Fantastic Journey 3 +# WW3PQV - Where's Wally? Fantastic Journey 3 [Video_Settings] SuggestedAspectRatio = 2 [Video_Hacks] XFBToTextureEnable = False +# Avoids invisible cursor. ImmediateXFBenable = False diff --git a/Data/Sys/GameSettings/WWA.ini b/Data/Sys/GameSettings/WWA.ini index 2ed8576975d9..ebca42c6954d 100644 --- a/Data/Sys/GameSettings/WWA.ini +++ b/Data/Sys/GameSettings/WWA.ini @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids constant flickering. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WWI.ini b/Data/Sys/GameSettings/WWI.ini index 38333161946f..0864f3a6ee28 100644 --- a/Data/Sys/GameSettings/WWI.ini +++ b/Data/Sys/GameSettings/WWI.ini @@ -1,8 +1,9 @@ -# WWIP - Where's Wally? Fantastic Journey 1 +# WWIPQV - Where's Wally? Fantastic Journey 1 [Video_Settings] SuggestedAspectRatio = 2 [Video_Hacks] XFBToTextureEnable = False +# Avoids invisible cursor. ImmediateXFBenable = False diff --git a/Data/Sys/GameSettings/WXR.ini b/Data/Sys/GameSettings/WXR.ini index 9bfb8ef58b23..5c8c87aaa5b9 100644 --- a/Data/Sys/GameSettings/WXR.ini +++ b/Data/Sys/GameSettings/WXR.ini @@ -1,4 +1,4 @@ -# WXREE9 - RF Ocean Challenge +# WXREE9, WXRPE9 - Reel Fishing Ocean Challenge [Core] # Values set here will override the main Dolphin settings. @@ -13,4 +13,5 @@ SafeTextureCacheColorSamples = 0 [Video_Hacks] +# Avoids extraneous frames with terrible pacing. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WZI.ini b/Data/Sys/GameSettings/WZI.ini index 0a693081a30c..dc2ad22a7270 100644 --- a/Data/Sys/GameSettings/WZI.ini +++ b/Data/Sys/GameSettings/WZI.ini @@ -1,4 +1,4 @@ -# WZIPTW - Rubik's: Rush +# WZIPTW, WZIETW - Rubik's Puzzle Galaxy: Rush [Core] # Values set here will override the main Dolphin settings. @@ -12,4 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids majorly corrupted graphics. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/XHR.ini b/Data/Sys/GameSettings/XHR.ini new file mode 100644 index 000000000000..70692145298d --- /dev/null +++ b/Data/Sys/GameSettings/XHR.ini @@ -0,0 +1,5 @@ +# XHREQQ, XHRPQQ - Furry Legends + +[Video_Hacks] +# Avoids majorly broken graphics when in game. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/XIN.ini b/Data/Sys/GameSettings/XIN.ini new file mode 100644 index 000000000000..a8c04e6dc61f --- /dev/null +++ b/Data/Sys/GameSettings/XIN.ini @@ -0,0 +1,5 @@ +# XINPLU, XINELU - Learning with The PooYoos: Episode 1 + +[Video_Hacks] +# Avoids flickering elements. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/XIO.ini b/Data/Sys/GameSettings/XIO.ini new file mode 100644 index 000000000000..5594ec2e9218 --- /dev/null +++ b/Data/Sys/GameSettings/XIO.ini @@ -0,0 +1,5 @@ +# XIOPLU, XIOELU - Learning with The PooYoos: Episode 2 + +[Video_Hacks] +# Avoids flickering elements. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/XIP.ini b/Data/Sys/GameSettings/XIP.ini new file mode 100644 index 000000000000..f5edc7d53e7d --- /dev/null +++ b/Data/Sys/GameSettings/XIP.ini @@ -0,0 +1,5 @@ +# XIPPLU, XIPELU - Learning with The PooYoos: Episode 3 + +[Video_Hacks] +# Avoids flickering elements. +ImmediateXFBEnable = False From a01bf63665b3057b79d747d1496bfde94149b750 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Thu, 27 Nov 2025 18:27:38 -0600 Subject: [PATCH 074/267] GameSettings: Disable ImmediateXFB for many games where significantly problematic. --- Data/Sys/GameSettings/GDJ.ini | 5 +++++ Data/Sys/GameSettings/GE9.ini | 5 ++++- Data/Sys/GameSettings/GJU.ini | 5 +++++ Data/Sys/GameSettings/GMK.ini | 5 +++++ Data/Sys/GameSettings/GOF.ini | 5 +++++ Data/Sys/GameSettings/GRN.ini | 5 +++++ Data/Sys/GameSettings/GUZ.ini | 2 +- Data/Sys/GameSettings/R2P.ini | 6 +++++- Data/Sys/GameSettings/R3P.ini | 5 +++++ Data/Sys/GameSettings/R3X.ini | 5 +++++ Data/Sys/GameSettings/R79.ini | 4 ++++ Data/Sys/GameSettings/RC2.ini | 5 +++++ Data/Sys/GameSettings/RCA.ini | 5 +++++ Data/Sys/GameSettings/RGM.ini | 6 +++++- Data/Sys/GameSettings/RLS.ini | 3 ++- Data/Sys/GameSettings/RM4.ini | 5 +++++ Data/Sys/GameSettings/RM6.ini | 5 +++++ Data/Sys/GameSettings/ROQ.ini | 5 +++++ Data/Sys/GameSettings/RPY.ini | 6 +++++- Data/Sys/GameSettings/RQN.ini | 5 +++++ Data/Sys/GameSettings/RTC.ini | 5 +++++ Data/Sys/GameSettings/SAK.ini | 2 ++ Data/Sys/GameSettings/SCY.ini | 4 ++++ Data/Sys/GameSettings/{SDAE5G.ini => SDA.ini} | 4 ++++ Data/Sys/GameSettings/SEM.ini | 3 ++- Data/Sys/GameSettings/SJ2.ini | 5 +++++ Data/Sys/GameSettings/SQI.ini | 4 ++++ Data/Sys/GameSettings/STS.ini | 4 ++++ Data/Sys/GameSettings/SX3.ini | 5 ++++- Data/Sys/GameSettings/WHY.ini | 5 +++++ Data/Sys/GameSettings/WPK.ini | 5 +++++ 31 files changed, 135 insertions(+), 8 deletions(-) create mode 100644 Data/Sys/GameSettings/GDJ.ini create mode 100644 Data/Sys/GameSettings/GJU.ini create mode 100644 Data/Sys/GameSettings/GMK.ini create mode 100644 Data/Sys/GameSettings/GOF.ini create mode 100644 Data/Sys/GameSettings/GRN.ini create mode 100644 Data/Sys/GameSettings/R3P.ini create mode 100644 Data/Sys/GameSettings/R3X.ini create mode 100644 Data/Sys/GameSettings/RC2.ini create mode 100644 Data/Sys/GameSettings/RCA.ini create mode 100644 Data/Sys/GameSettings/RM4.ini create mode 100644 Data/Sys/GameSettings/RM6.ini create mode 100644 Data/Sys/GameSettings/ROQ.ini create mode 100644 Data/Sys/GameSettings/RQN.ini create mode 100644 Data/Sys/GameSettings/RTC.ini rename Data/Sys/GameSettings/{SDAE5G.ini => SDA.ini} (93%) create mode 100644 Data/Sys/GameSettings/SJ2.ini create mode 100644 Data/Sys/GameSettings/WHY.ini create mode 100644 Data/Sys/GameSettings/WPK.ini diff --git a/Data/Sys/GameSettings/GDJ.ini b/Data/Sys/GameSettings/GDJ.ini new file mode 100644 index 000000000000..6b27ce67fbb4 --- /dev/null +++ b/Data/Sys/GameSettings/GDJ.ini @@ -0,0 +1,5 @@ +# GDJEB2, GDJJB2 - Digimon World 4 + +[Video_Hacks] +# Avoids constant black flickering. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GE9.ini b/Data/Sys/GameSettings/GE9.ini index 781f2bb04b22..ea8c314514da 100644 --- a/Data/Sys/GameSettings/GE9.ini +++ b/Data/Sys/GameSettings/GE9.ini @@ -1,4 +1,4 @@ -# GE9E5D - Ed, Edd n Eddy +# GE9E5D - Ed, Edd n Eddy: The Mis-Edventures [Core] # Values set here will override the main Dolphin settings. @@ -16,3 +16,6 @@ HLE_BS2 = True [Video_Settings] SafeTextureCacheColorSamples = 512 +[Video_Hacks] +# Avoids shifted screen. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GJU.ini b/Data/Sys/GameSettings/GJU.ini new file mode 100644 index 000000000000..eb88311dbeb9 --- /dev/null +++ b/Data/Sys/GameSettings/GJU.ini @@ -0,0 +1,5 @@ +# GJUF78, GJUE78, GJUD78, GJUP78 - Tak and the Power of Juju + +[Video_Hacks] +# Avoids constant black flickering. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GMK.ini b/Data/Sys/GameSettings/GMK.ini new file mode 100644 index 000000000000..a8c8b92b0f2f --- /dev/null +++ b/Data/Sys/GameSettings/GMK.ini @@ -0,0 +1,5 @@ +# GMKE5D, GMKP5D, GMKD5D - Mortal Kombat: Deadly Alliance + +[Video_Hacks] +# Avoids stuck black screens during FMVs. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GOF.ini b/Data/Sys/GameSettings/GOF.ini new file mode 100644 index 000000000000..893c46286eb7 --- /dev/null +++ b/Data/Sys/GameSettings/GOF.ini @@ -0,0 +1,5 @@ +# GOFE7L, GOFP6S - Outlaw Golf + +[Video_Hacks] +# Avoids stuck black FMVs and loading screens. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GRN.ini b/Data/Sys/GameSettings/GRN.ini new file mode 100644 index 000000000000..9a8af763dc11 --- /dev/null +++ b/Data/Sys/GameSettings/GRN.ini @@ -0,0 +1,5 @@ +# GRNP52, GRNE52, GRNJCQ - Lost Kingdoms + +[Video_Hacks] +# Avoids stuck black screens during FMVs. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/GUZ.ini b/Data/Sys/GameSettings/GUZ.ini index 67db3ba33204..12d92f61b0b0 100644 --- a/Data/Sys/GameSettings/GUZ.ini +++ b/Data/Sys/GameSettings/GUZ.ini @@ -12,5 +12,5 @@ [Video_Settings] [Video_Hacks] +# Avoids stuck screens during FMVs. ImmediateXFBEnable = False - diff --git a/Data/Sys/GameSettings/R2P.ini b/Data/Sys/GameSettings/R2P.ini index e7aef5c46f82..ee9668f623a7 100644 --- a/Data/Sys/GameSettings/R2P.ini +++ b/Data/Sys/GameSettings/R2P.ini @@ -1,4 +1,8 @@ -# R2PE9B, R2PJ9B, R2PKZ4, R2PP99 - Super Swing Golf Season 2 +# R2PP9B, R2PP99, R2PJ9B, R2PKZ4, R2PE9B - Super Swing Golf Season 2 [Video_Settings] SuggestedAspectRatio = 2 + +[Video_Hacks] +# Avoids constant black flickering. +ImmediateXFBenable = False diff --git a/Data/Sys/GameSettings/R3P.ini b/Data/Sys/GameSettings/R3P.ini new file mode 100644 index 000000000000..54a61bc97e8d --- /dev/null +++ b/Data/Sys/GameSettings/R3P.ini @@ -0,0 +1,5 @@ +# R3PEWR, R3PJ52, R3PPWR - Speed Racer + +[Video_Hacks] +# Avoids constant black flickering. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/R3X.ini b/Data/Sys/GameSettings/R3X.ini new file mode 100644 index 000000000000..af7eb19394a5 --- /dev/null +++ b/Data/Sys/GameSettings/R3X.ini @@ -0,0 +1,5 @@ +# R3XE6U, R3XP6V - Sam & Max: Season One + +[Video_Hacks] +# Avoids majorly corrupted graphics. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/R79.ini b/Data/Sys/GameSettings/R79.ini index 9c07d610c2b5..72eae594a8a6 100644 --- a/Data/Sys/GameSettings/R79.ini +++ b/Data/Sys/GameSettings/R79.ini @@ -2,3 +2,7 @@ [Video_Settings] SuggestedAspectRatio = 2 + +[Video_Hacks] +# Avoids black flickering while in game. +ImmediateXFBenable = False diff --git a/Data/Sys/GameSettings/RC2.ini b/Data/Sys/GameSettings/RC2.ini new file mode 100644 index 000000000000..4112894effef --- /dev/null +++ b/Data/Sys/GameSettings/RC2.ini @@ -0,0 +1,5 @@ +# RC2E78, RC2P78, RC2X78, RC2Y78 - Cars Mater-National Championship + +[Video_Hacks] +# Avoids stuck black screens during FMVs. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RCA.ini b/Data/Sys/GameSettings/RCA.ini new file mode 100644 index 000000000000..45b12d273109 --- /dev/null +++ b/Data/Sys/GameSettings/RCA.ini @@ -0,0 +1,5 @@ +# RCAJ78, RCAE78, RCAP78, RCAX78, RCAY78 - Cars (Wii) + +[Video_Hacks] +# Avoids stuck black screens during FMVs. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RGM.ini b/Data/Sys/GameSettings/RGM.ini index 9b3e5659560c..c75fe4426545 100644 --- a/Data/Sys/GameSettings/RGM.ini +++ b/Data/Sys/GameSettings/RGM.ini @@ -1,4 +1,4 @@ -# RGME5D, RGMP5D - The Grim Adventures of Billy & Mandy +# RGME5D, RGMP5D - The Grim Adventures of Billy & Mandy (Wii) [Core] # Values set here will override the main Dolphin settings. @@ -11,3 +11,7 @@ [Video_Settings] SuggestedAspectRatio = 2 + +[Video_Hacks] +# Avoids stuck black screens during FMVs. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RLS.ini b/Data/Sys/GameSettings/RLS.ini index a89ed5c7b94a..a443a71acac4 100644 --- a/Data/Sys/GameSettings/RLS.ini +++ b/Data/Sys/GameSettings/RLS.ini @@ -1,4 +1,4 @@ -# RLSE8P - Alien Syndrome +# RLSE8P, RLSP8P - Alien Syndrome [Core] # Values set here will override the main Dolphin settings. @@ -17,4 +17,5 @@ EFBToTextureEnable = False [Video_Settings] [Video_Hacks] +# Avoids constant flickering. ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RM4.ini b/Data/Sys/GameSettings/RM4.ini new file mode 100644 index 000000000000..35bd77adc0b6 --- /dev/null +++ b/Data/Sys/GameSettings/RM4.ini @@ -0,0 +1,5 @@ +# RM4J41, RM4E41, RM4P41 - Monster 4x4: World Circuit + +[Video_Hacks] +# Avoids shifted screen and terrible frame pacing. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RM6.ini b/Data/Sys/GameSettings/RM6.ini new file mode 100644 index 000000000000..f60a40b539b8 --- /dev/null +++ b/Data/Sys/GameSettings/RM6.ini @@ -0,0 +1,5 @@ +# RM6EEB, RM6P99 - Baroque + +[Video_Hacks] +# Avoids constant flickering. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/ROQ.ini b/Data/Sys/GameSettings/ROQ.ini new file mode 100644 index 000000000000..bbafbc32ac9d --- /dev/null +++ b/Data/Sys/GameSettings/ROQ.ini @@ -0,0 +1,5 @@ +# ROQJEP - Baroque + +[Video_Hacks] +# Avoids constant flickering. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RPY.ini b/Data/Sys/GameSettings/RPY.ini index 727dbb8e4337..1cd647ef5d18 100644 --- a/Data/Sys/GameSettings/RPY.ini +++ b/Data/Sys/GameSettings/RPY.ini @@ -1,4 +1,4 @@ -# RPYP9B - Pangya! Golf with Style +# RPYE9B, RPYJ9B, RPYP9B - Super Swing Golf [Core] # Values set here will override the main Dolphin settings. @@ -12,3 +12,7 @@ FPRF = True [Video_Settings] SuggestedAspectRatio = 2 + +[Video_Hacks] +# Avoids constant black flickering. +ImmediateXFBenable = False diff --git a/Data/Sys/GameSettings/RQN.ini b/Data/Sys/GameSettings/RQN.ini new file mode 100644 index 000000000000..4d25d2a9778b --- /dev/null +++ b/Data/Sys/GameSettings/RQN.ini @@ -0,0 +1,5 @@ +# RQNEWR, RQNPWR - Scooby-Doo! First Frights + +[Video_Hacks] +# Avoids majorly corrupted graphics. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/RTC.ini b/Data/Sys/GameSettings/RTC.ini new file mode 100644 index 000000000000..d38b29d16a73 --- /dev/null +++ b/Data/Sys/GameSettings/RTC.ini @@ -0,0 +1,5 @@ +# RTCE41, RTCP41 - Tom Clancy's Splinter Cell Double Agent (Wii) + +[Video_Hacks] +# Avoids stuck black screens during FMVs. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SAK.ini b/Data/Sys/GameSettings/SAK.ini index 6ee72bff3fd4..7c2edf9adec7 100644 --- a/Data/Sys/GameSettings/SAK.ini +++ b/Data/Sys/GameSettings/SAK.ini @@ -11,6 +11,8 @@ [Video_Hacks] EFBToTextureEnable = False +# Avoids constant black flickering. +ImmediateXFBenable = False [Video_Settings] SafeTextureCacheColorSamples = 512 diff --git a/Data/Sys/GameSettings/SCY.ini b/Data/Sys/GameSettings/SCY.ini index 70f952ae463e..f2311e3fb4f7 100644 --- a/Data/Sys/GameSettings/SCY.ini +++ b/Data/Sys/GameSettings/SCY.ini @@ -12,3 +12,7 @@ LowDCBZHack = True [Video_Settings] SafeTextureCacheColorSamples = 2048 + +[Video_Hacks] +# Avoids constant black flickering. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SDAE5G.ini b/Data/Sys/GameSettings/SDA.ini similarity index 93% rename from Data/Sys/GameSettings/SDAE5G.ini rename to Data/Sys/GameSettings/SDA.ini index a6f6abc8c8b6..21f1666d9282 100644 --- a/Data/Sys/GameSettings/SDAE5G.ini +++ b/Data/Sys/GameSettings/SDA.ini @@ -33,3 +33,7 @@ $Fix startup crash 0x801C9E5C:dword:0x48032C75 [OnFrame_Enabled] $Fix startup crash + +[Video_Hacks] +# Avoids majorly corrupted graphics. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SEM.ini b/Data/Sys/GameSettings/SEM.ini index 391fc38641b4..1b923e03601d 100644 --- a/Data/Sys/GameSettings/SEM.ini +++ b/Data/Sys/GameSettings/SEM.ini @@ -16,4 +16,5 @@ SafeTextureCacheColorSamples = 0 ForceTextureFiltering = 0 [Video_Hacks] - +# Avoids constant black flickering. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SJ2.ini b/Data/Sys/GameSettings/SJ2.ini new file mode 100644 index 000000000000..261f1504010a --- /dev/null +++ b/Data/Sys/GameSettings/SJ2.ini @@ -0,0 +1,5 @@ +# SJ2EWR, SJ2PWR - Scooby-Doo! And the Spooky Swamp + +[Video_Hacks] +# Avoids majorly corrupted graphics. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SQI.ini b/Data/Sys/GameSettings/SQI.ini index 99a662264cc7..0b65c7e8ee3f 100644 --- a/Data/Sys/GameSettings/SQI.ini +++ b/Data/Sys/GameSettings/SQI.ini @@ -12,3 +12,7 @@ LowDCBZHack = True [Video_Settings] SafeTextureCacheColorSamples = 2048 + +[Video_Hacks] +# Avoids constant black flickering. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/STS.ini b/Data/Sys/GameSettings/STS.ini index 1823d1d21184..0139cf71ff59 100644 --- a/Data/Sys/GameSettings/STS.ini +++ b/Data/Sys/GameSettings/STS.ini @@ -13,3 +13,7 @@ [Video_Settings] SafeTextureCacheColorSamples = 512 + +[Video_Hacks] +# Avoids constant black flickering. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/SX3.ini b/Data/Sys/GameSettings/SX3.ini index 462bd3ae782a..78fd2c811174 100644 --- a/Data/Sys/GameSettings/SX3.ini +++ b/Data/Sys/GameSettings/SX3.ini @@ -1,4 +1,4 @@ -# SX3J01, SX3P01 - Pandora s Tower +# SX3J01, SX3P01 - Pandora's Tower [Core] # Values set here will override the main Dolphin settings. @@ -12,3 +12,6 @@ [Video_Settings] SafeTextureCacheColorSamples = 0 +[Video_Hacks] +# Avoids shifted screen. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WHY.ini b/Data/Sys/GameSettings/WHY.ini new file mode 100644 index 000000000000..497f9f53c108 --- /dev/null +++ b/Data/Sys/GameSettings/WHY.ini @@ -0,0 +1,5 @@ +# WHYETY - Heavy Fire: Black Arms + +[Video_Hacks] +# Game is uncapped and slow to emulate. +ImmediateXFBEnable = False diff --git a/Data/Sys/GameSettings/WPK.ini b/Data/Sys/GameSettings/WPK.ini new file mode 100644 index 000000000000..85cb70d363c9 --- /dev/null +++ b/Data/Sys/GameSettings/WPK.ini @@ -0,0 +1,5 @@ +# WPKEGL, WPKPGL - Texas Hold'em Poker + +[Video_Hacks] +# Avoids majorly corrupted graphics. +ImmediateXFBEnable = False From 34b402b631738c546fb2c59bbb791c124f4633d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Wed, 24 Dec 2025 06:40:50 +0100 Subject: [PATCH 075/267] Externals: Update zlib-ng to v2.3.2 --- Externals/zlib-ng/CMakeLists.txt | 14 ++++---- Externals/zlib-ng/zconf.h | 19 +++++++--- Externals/zlib-ng/zlib-ng | 2 +- Externals/zlib-ng/zlib-ng.vcxproj | 57 +++++++++++++++++++----------- Externals/zlib-ng/zlib.h | 58 +++++++++++++++++-------------- Source/Core/Common/CMakeLists.txt | 1 + 6 files changed, 90 insertions(+), 61 deletions(-) diff --git a/Externals/zlib-ng/CMakeLists.txt b/Externals/zlib-ng/CMakeLists.txt index 2b686c0b12ef..2119a3998336 100644 --- a/Externals/zlib-ng/CMakeLists.txt +++ b/Externals/zlib-ng/CMakeLists.txt @@ -1,15 +1,13 @@ -set(ZLIB_ENABLE_TESTS OFF) +set(BUILD_TESTING OFF) set(ZLIB_COMPAT ON) -set(SKIP_INSTALL_ALL ON) - -option(BUILD_SHARED_LIBS "Build shared library" OFF) +set(INSTALL_UTILS OFF) +set(BUILD_SHARED_LIBS OFF) add_subdirectory(zlib-ng) # Set ZLIB variables for find_package used by other projects -set(ZLIB_INCLUDE_DIR ${CMAKE_BINARY_DIR}/zlib-ng CACHE STRING "Path to zlib include directory") +set(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/zlib-ng CACHE STRING "Path to zlib include directory") set(ZLIB_LIBRARY ZLIB::ZLIB CACHE STRING "Path to zlib library") -# Setup zlib alias project so FindZLIB doesn't recreate it -add_library(ZLIB::ZLIB ALIAS zlib) -dolphin_disable_warnings(zlib) +add_library(ZLIB::ZLIB ALIAS zlib-ng) +dolphin_disable_warnings(zlib-ng) diff --git a/Externals/zlib-ng/zconf.h b/Externals/zlib-ng/zconf.h index f3691639ef31..8dd6b82c867d 100644 --- a/Externals/zlib-ng/zconf.h +++ b/Externals/zlib-ng/zconf.h @@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -35,6 +35,9 @@ * created by gzip. (Files created by minigzip can still be extracted by * gzip.) */ +#ifndef MIN_WBITS +# define MIN_WBITS 8 /* 256 LZ77 window */ +#endif #ifndef MAX_WBITS # define MAX_WBITS 15 /* 32K LZ77 window */ #endif @@ -79,6 +82,9 @@ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ #if defined(ZLIB_WINAPI) && defined(_WIN32) +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ @@ -110,8 +116,11 @@ #ifndef ZEXPORTVA # define ZEXPORTVA Z_EXPORTVA #endif +#ifndef FAR +# define FAR +#endif -/* Fallback for something that includes us. */ +/* Legacy zlib typedefs for backwards compatibility. Don't assume stdint.h is defined. */ typedef unsigned char Byte; typedef Byte Bytef; @@ -127,9 +136,9 @@ typedef void const *voidpc; typedef void *voidpf; typedef void *voidp; -typedef uint32_t z_crc_t; +typedef unsigned int z_crc_t; -#if 0 /* was set to #if 0 by configure/cmake/etc */ +#if 0 /* was set to #if 1 by configure/cmake/etc */ # define Z_HAVE_UNISTD_H #endif @@ -192,4 +201,6 @@ typedef PTRDIFF_TYPE ptrdiff_t; # endif #endif +typedef size_t z_size_t; + #endif /* ZCONF_H */ diff --git a/Externals/zlib-ng/zlib-ng b/Externals/zlib-ng/zlib-ng index ce01b1e41da2..6d9f3dc07236 160000 --- a/Externals/zlib-ng/zlib-ng +++ b/Externals/zlib-ng/zlib-ng @@ -1 +1 @@ -Subproject commit ce01b1e41da298334f8214389cc9369540a7560f +Subproject commit 6d9f3dc072369dc719a5fbe71d4e086a96a680bd diff --git a/Externals/zlib-ng/zlib-ng.vcxproj b/Externals/zlib-ng/zlib-ng.vcxproj index 1366e1da77b9..bf9b34cd1fcd 100644 --- a/Externals/zlib-ng/zlib-ng.vcxproj +++ b/Externals/zlib-ng/zlib-ng.vcxproj @@ -31,14 +31,17 @@ - + + + + - + + - - - + + @@ -48,20 +51,24 @@ - - + + + + + + + + + + - - - - - + @@ -74,12 +81,10 @@ - - @@ -89,44 +94,54 @@ - - + + + + - + + - + + + + + + + - + - + - + + diff --git a/Externals/zlib-ng/zlib.h b/Externals/zlib-ng/zlib.h index e595aa88de7d..41ade9965c90 100644 --- a/Externals/zlib-ng/zlib.h +++ b/Externals/zlib-ng/zlib.h @@ -1,9 +1,9 @@ #ifndef ZLIB_H_ #define ZLIB_H_ /* zlib.h -- interface of the 'zlib-ng' compression library - Forked from and compatible with zlib 1.2.12 + Forked from and compatible with zlib 1.3.1 - Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -49,20 +49,21 @@ extern "C" { #endif -#define ZLIBNG_VERSION "2.1.0.devel" -#define ZLIBNG_VERNUM 0x02010000L /* MMNNRRMS: major minor revision status modified */ +#define ZLIBNG_VERSION "2.3.2" +#define ZLIBNG_VERNUM 0x020302F0L /* MMNNRRSM: major minor revision status modified */ #define ZLIBNG_VER_MAJOR 2 -#define ZLIBNG_VER_MINOR 1 -#define ZLIBNG_VER_REVISION 0 -#define ZLIBNG_VER_STATUS 0 /* 0=devel, 1-E=beta, F=Release */ +#define ZLIBNG_VER_MINOR 3 +#define ZLIBNG_VER_REVISION 2 +#define ZLIBNG_VER_STATUS F /* 0=devel, 1-E=beta, F=Release (DEPRECATED) */ +#define ZLIBNG_VER_STATUSH 0xF /* Hex values: 0=devel, 1-9=beta, A-E=Release Candidate, F=Release */ #define ZLIBNG_VER_MODIFIED 0 /* non-zero if modified externally from zlib-ng */ -#define ZLIB_VERSION "1.2.12.zlib-ng" -#define ZLIB_VERNUM 0x12cf +#define ZLIB_VERSION "1.3.1.zlib-ng" +#define ZLIB_VERNUM 0x131f #define ZLIB_VER_MAJOR 1 -#define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 12 -#define ZLIB_VER_SUBREVISION 0 +#define ZLIB_VER_MINOR 3 +#define ZLIB_VER_REVISION 1 +#define ZLIB_VER_SUBREVISION 15 /* 15=fork (0xf) */ /* The 'zlib' compression library provides in-memory compression and @@ -219,7 +220,7 @@ typedef gz_header *gz_headerp; #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ -#define Z_NULL NULL /* for compatibility with zlib, was for initializing zalloc, zfree, opaque */ +#define Z_NULL 0 /* for compatibility with zlib, was for initializing zalloc, zfree, opaque */ #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ @@ -239,8 +240,8 @@ Z_EXTERN int Z_EXPORT deflateInit (z_stream *strm, int level); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If - zalloc and zfree are set to NULL, deflateInit updates them to use default - allocation functions. + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. total_in, total_out, adler, and msg are initialized. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all @@ -330,8 +331,8 @@ Z_EXTERN int Z_EXPORT deflate(z_stream *strm, int flush); with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. + avail_out is greater than six when the flush marker begins, in order to avoid + repeated flush markers upon calling deflate() again when avail_out == 0. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was @@ -392,8 +393,9 @@ Z_EXTERN int Z_EXPORT inflateInit (z_stream *strm); the caller. In the current version of inflate, the provided input is not read or consumed. The allocation of a sliding window will be deferred to the first call of inflate (if the decompression does not complete on the - first call). If zalloc and zfree are set to NULL, inflateInit updates - them to use default allocation functions. + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. total_in, total_out, adler, and + msg are initialized. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the @@ -703,7 +705,7 @@ Z_EXTERN int Z_EXPORT deflateReset(z_stream *strm); This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate the internal compression state. The stream will leave the compression level and any other attributes that may have been - set unchanged. + set unchanged. total_in, total_out, adler, and msg are initialized. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being NULL). @@ -734,7 +736,7 @@ Z_EXTERN int Z_EXPORT deflateParams(z_stream *strm, int level, int strategy); Then no more input data should be provided before the deflateParams() call. If this is done, the old level and strategy will be applied to the data compressed before deflateParams(), and the new level and strategy will be - applied to the the data compressed after deflateParams(). + applied to the data compressed after deflateParams(). deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if @@ -816,8 +818,9 @@ Z_EXTERN int Z_EXPORT deflateSetHeader(z_stream *strm, gz_headerp head); gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). + the time set to zero, and os set to the current operating system, with no + extra, name, or comment fields. The gzip header is returned to the default + state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. @@ -887,7 +890,7 @@ Z_EXTERN int Z_EXPORT inflateSetDictionary(z_stream *strm, const unsigned char * deflateSetDictionary). For raw inflate, this function can be called at any time to set the dictionary. If the provided dictionary is smaller than the window and there is already data in the window, then the provided dictionary - will amend what's there. The application must insure that the dictionary + will amend what's there. The application must ensure that the dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a @@ -924,7 +927,7 @@ Z_EXTERN int Z_EXPORT inflateSync(z_stream *strm); inflateSync returns Z_OK if a possible full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. - In the success case, the application may save the current current value of + In the success case, the application may save the current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. @@ -950,6 +953,7 @@ Z_EXTERN int Z_EXPORT inflateReset(z_stream *strm); This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. + total_in, total_out, adler, and msg are initialized. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being NULL). @@ -1728,14 +1732,14 @@ Z_EXTERN unsigned long Z_EXPORT crc32_combine(unsigned long crc1, unsigned long seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. + len2. len2 must be non-negative. */ /* Z_EXTERN unsigned long Z_EXPORT crc32_combine_gen(z_off_t len2); Return the operator corresponding to length len2, to be used with - crc32_combine_op(). + crc32_combine_op(). len2 must be non-negative. */ Z_EXTERN unsigned long Z_EXPORT crc32_combine_op(unsigned long crc1, unsigned long crc2, diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 33a03729ca4a..7580cded5d45 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -191,6 +191,7 @@ PRIVATE FatFs spng::spng watcher + ZLIB::ZLIB ${VTUNE_LIBRARIES} ) From 66c392f72980298ffbcc68e90d27d0022b56721b Mon Sep 17 00:00:00 2001 From: iwubcode Date: Wed, 24 Dec 2025 15:21:48 -0600 Subject: [PATCH 076/267] VideoCommon: initialize stored viewport to 0, fixes a crash in debug mode for d3d --- Source/Core/VideoCommon/AbstractGfx.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Core/VideoCommon/AbstractGfx.h b/Source/Core/VideoCommon/AbstractGfx.h index b1528b3bb12d..3a3c72c68439 100644 --- a/Source/Core/VideoCommon/AbstractGfx.h +++ b/Source/Core/VideoCommon/AbstractGfx.h @@ -129,12 +129,12 @@ class AbstractGfx struct ViewportAndScissor { MathUtil::Rectangle scissor_rect; - float viewport_x; - float viewport_y; - float viewport_width; - float viewport_height; - float viewport_near_depth; - float viewport_far_depth; + float viewport_x = 0; + float viewport_y = 0; + float viewport_width = 0; + float viewport_height = 0; + float viewport_near_depth = 0; + float viewport_far_depth = 0; }; // Stores the last viewport and scissor, the stored data is restored in 'EndUtilityDrawing' From c9ef05c4b37e837f5c18fca6068681066fb63d53 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Wed, 24 Dec 2025 15:32:42 -0600 Subject: [PATCH 077/267] Common: update Flags to allow const object usage Co-authored-by: Jordan Woyak --- Source/Core/Common/BitUtils.h | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/Source/Core/Common/BitUtils.h b/Source/Core/Common/BitUtils.h index e052c8aeff4b..9385b9d8d942 100644 --- a/Source/Core/Common/BitUtils.h +++ b/Source/Core/Common/BitUtils.h @@ -13,6 +13,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/EnumUtils.h" namespace Common { @@ -208,23 +209,20 @@ template class FlagBit { public: - FlagBit(std::underlying_type_t& bits, T bit) : m_bits(bits), m_bit(bit) {} - explicit operator bool() const - { - return (m_bits & static_cast>(m_bit)) != 0; - } - FlagBit& operator=(const bool rhs) + FlagBit(T* bits, std::type_identity_t bit) : m_bits(*bits), m_bit(bit) {} + explicit operator bool() const { return (m_bits & m_bit) != 0; } + FlagBit& operator=(const bool rhs) requires(!std::is_const_v) { if (rhs) - m_bits |= static_cast>(m_bit); + m_bits |= m_bit; else - m_bits &= ~static_cast>(m_bit); + m_bits &= ~m_bit; return *this; } private: - std::underlying_type_t& m_bits; - T m_bit; + T& m_bits; + const T m_bit; }; template @@ -239,7 +237,8 @@ class Flags m_hex |= static_cast>(bit); } } - FlagBit operator[](T bit) { return FlagBit(m_hex, bit); } + auto operator[](T bit) { return FlagBit(&m_hex, Common::ToUnderlying(bit)); } + auto operator[](T bit) const { return FlagBit(&m_hex, Common::ToUnderlying(bit)); } std::underlying_type_t m_hex = 0; }; From 1b3485b6fd711d15586d009e90f0a862070478a8 Mon Sep 17 00:00:00 2001 From: Sintendo <3380580+Sintendo@users.noreply.github.com> Date: Fri, 26 Dec 2025 23:15:17 +0100 Subject: [PATCH 078/267] VideoCommon: Fix ShaderResource init order warning --- Source/Core/VideoCommon/Resources/ShaderResource.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Source/Core/VideoCommon/Resources/ShaderResource.cpp b/Source/Core/VideoCommon/Resources/ShaderResource.cpp index e1aecd355c21..47600f2c6abd 100644 --- a/Source/Core/VideoCommon/Resources/ShaderResource.cpp +++ b/Source/Core/VideoCommon/Resources/ShaderResource.cpp @@ -167,9 +167,8 @@ ShaderResource::ShaderResource(Resource::ResourceContext resource_context, const GXPipelineUid& pipeline_uid, const std::string& preprocessor_setting, const ShaderHostConfig& shader_host_config) - : Resource(std::move(resource_context)), m_uid(pipeline_uid), - m_preprocessor_settings(preprocessor_setting), - m_shader_host_config{.bits = shader_host_config.bits} + : Resource(std::move(resource_context)), m_shader_host_config{.bits = shader_host_config.bits}, + m_uid(pipeline_uid), m_preprocessor_settings(preprocessor_setting) { m_shader_asset = m_resource_context.asset_cache->CreateAsset( m_resource_context.primary_asset_id, m_resource_context.asset_library, this); From 35c6a6e61283bdf71a3f46faf6ba53976e4f0a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Sat, 27 Dec 2025 09:07:42 +0100 Subject: [PATCH 079/267] CustomPipeline: Remove unused functions --- .../Runtime/CustomPipeline.cpp | 32 +++---------------- .../Runtime/CustomPipeline.h | 10 +----- 2 files changed, 5 insertions(+), 37 deletions(-) diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.cpp index aa392f0a9662..bb09a8432855 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.cpp +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.cpp @@ -3,35 +3,11 @@ #include "VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.h" -#include -#include -#include +#include +#include -#include "Common/Contains.h" -#include "Common/Logging/Log.h" -#include "Common/VariantUtil.h" - -#include "VideoCommon/AbstractGfx.h" - -namespace -{ -bool IsQualifier(std::string_view value) -{ - static constexpr std::array qualifiers = { - "attribute", "const", "highp", "lowp", "mediump", "uniform", "varying", - }; - return Common::Contains(qualifiers, value); -} - -bool IsBuiltInMacro(std::string_view value) -{ - static constexpr std::array built_in = { - "__LINE__", "__FILE__", "__VERSION__", "GL_core_profile", "GL_compatibility_profile", - }; - return Common::Contains(built_in, value); -} - -} // namespace +#include "Common/CommonTypes.h" +#include "VideoCommon/Assets/CustomAssetLibrary.h" void CustomPipeline::UpdatePixelData(std::shared_ptr, std::span, diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.h b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.h index 7165c9291fd4..3aa7b6641c6c 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.h +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.h @@ -4,18 +4,10 @@ #pragma once #include -#include #include -#include -#include -#include -#include "VideoCommon/AbstractTexture.h" +#include "Common/CommonTypes.h" #include "VideoCommon/Assets/CustomAssetLibrary.h" -#include "VideoCommon/Assets/MaterialAsset.h" -#include "VideoCommon/Assets/ShaderAsset.h" -#include "VideoCommon/Assets/TextureAsset.h" -#include "VideoCommon/ShaderGenCommon.h" struct CustomPipeline { From 9fae55e0982fe45c906b514d24eb831f4ed3b266 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Sun, 28 Dec 2025 14:47:27 -0500 Subject: [PATCH 080/267] RetroAchievements - Corrected MEM2 Alignment rcheevos expects Wii MEM2 to be aligned to 0x10000000 in recent updates; this corrects AchievementManager to do so. --- Source/Core/Core/AchievementManager.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index 4dc581d12595..285715ae52ca 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -1334,8 +1334,6 @@ u32 AchievementManager::MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_ return 0u; auto& system = Core::System::GetInstance(); Core::CPUThreadGuard thread_guard(system); - if (address > MEM1_SIZE) - address += (MEM2_START - MEM1_SIZE); for (u32 num_read = 0; num_read < num_bytes; num_read++) { auto value = system.GetMMU().HostTryRead(thread_guard, address + num_read, @@ -1561,10 +1559,7 @@ void AchievementManager::MemoryPoker(u32 address, u8* buffer, u32 num_bytes, rc_ if (!system) return; Core::CPUThreadGuard thread_guard(*system); - if (address < MEM1_SIZE) - system->GetMemory().CopyToEmu(address, buffer, num_bytes); - else - system->GetMemory().CopyToEmu(address - MEM1_SIZE + MEM2_START, buffer, num_bytes); + system->GetMemory().CopyToEmu(address, buffer, num_bytes); } void AchievementManager::GameTitleEstimateHandler(char* buffer, u32 buffer_size, From f9fe82f19ec4b85ff901e268dc3fff98b3e5255a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Sat, 27 Dec 2025 10:26:00 +0100 Subject: [PATCH 081/267] ShaderAsset: Fix shadowed variable `samplers` is a member defined in ShaderAsset.h --- Source/Core/VideoCommon/Assets/ShaderAsset.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoCommon/Assets/ShaderAsset.cpp b/Source/Core/VideoCommon/Assets/ShaderAsset.cpp index 99c9ed4ab086..04a91392125c 100644 --- a/Source/Core/VideoCommon/Assets/ShaderAsset.cpp +++ b/Source/Core/VideoCommon/Assets/ShaderAsset.cpp @@ -256,7 +256,7 @@ bool RasterSurfaceShaderData::FromJson(const VideoCommon::CustomAssetLibrary::As const auto parse_samplers = [&](const char* name, - std::vector* samplers) -> bool { + std::vector* samplers_out) -> bool { const auto samplers_iter = json.find(name); if (samplers_iter == json.end()) { @@ -309,7 +309,7 @@ bool RasterSurfaceShaderData::FromJson(const VideoCommon::CustomAssetLibrary::As asset_id); return false; } - samplers->push_back(std::move(sampler)); + samplers_out->push_back(std::move(sampler)); } return true; From 74b1930da4ea0dd62c91c4a0b677d14dc75093d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Sat, 27 Dec 2025 10:47:14 +0100 Subject: [PATCH 082/267] JitArm64_RegCache: Fix is always true warnings --- .../Core/PowerPC/JitArm64/JitArm64_RegCache.cpp | 13 +++++-------- .../Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h | 13 +++++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp index 8ba7a6a3be4e..308c14fddefe 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp @@ -182,12 +182,9 @@ Arm64GPRCache::GuestRegInfo Arm64GPRCache::GetGuestCR(size_t preg) Arm64GPRCache::GuestRegInfo Arm64GPRCache::GetGuestByIndex(size_t index) { - // We do not need to test for `index >= GUEST_GPR_OFFSET` because - // GUEST_GPR_OFFSET is always 0. This otherwise raises a warning. - static_assert(GUEST_GPR_OFFSET == 0); - if (index < GUEST_GPR_OFFSET + GUEST_GPR_COUNT) + if (IsIndexGPR(index)) return GetGuestGPR(index - GUEST_GPR_OFFSET); - if (index >= GUEST_CR_OFFSET && index < GUEST_CR_OFFSET + GUEST_CR_COUNT) + if (IsIndexCR(index)) return GetGuestCR(index - GUEST_CR_OFFSET); ASSERT_MSG(DYNA_REC, false, "Invalid index for guest register"); return GetGuestGPR(0); @@ -198,7 +195,7 @@ void Arm64GPRCache::FlushRegister(size_t index, FlushMode mode, ARM64Reg tmp_reg GuestRegInfo guest_reg = GetGuestByIndex(index); OpArg& reg = guest_reg.reg; size_t bitsize = guest_reg.bitsize; - const bool is_gpr = index >= GUEST_GPR_OFFSET && index < GUEST_GPR_OFFSET + GUEST_GPR_COUNT; + const bool is_gpr = IsIndexGPR(index); if (reg.IsInHostRegister()) { @@ -349,7 +346,7 @@ ARM64Reg Arm64GPRCache::BindForRead(size_t index) GuestRegInfo guest_reg = GetGuestByIndex(index); OpArg& reg = guest_reg.reg; size_t bitsize = guest_reg.bitsize; - const bool is_gpr = index >= GUEST_GPR_OFFSET && index < GUEST_GPR_OFFSET + GUEST_GPR_COUNT; + const bool is_gpr = IsIndexGPR(index); IncrementAllUsed(); reg.ResetLastUsed(); @@ -392,7 +389,7 @@ void Arm64GPRCache::BindForWrite(size_t index, bool will_read, bool will_write) GuestRegInfo guest_reg = GetGuestByIndex(index); OpArg& reg = guest_reg.reg; const size_t bitsize = guest_reg.bitsize; - const bool is_gpr = index >= GUEST_GPR_OFFSET && index < GUEST_GPR_OFFSET + GUEST_GPR_COUNT; + const bool is_gpr = IsIndexGPR(index); reg.ResetLastUsed(); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h index d547ee9d4eed..f801829b2c92 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.h @@ -419,6 +419,19 @@ class Arm64GPRCache : public Arm64RegCache GuestRegInfo GetGuestCR(size_t preg); GuestRegInfo GetGuestByIndex(size_t index); + constexpr bool IsIndexGPR(size_t index) + { + // We do not need to test for `index >= GUEST_GPR_OFFSET` because + // GUEST_GPR_OFFSET is always 0. This otherwise raises a warning. + static_assert(GUEST_GPR_OFFSET == 0); + return index < GUEST_GPR_OFFSET + GUEST_GPR_COUNT; + } + + constexpr bool IsIndexCR(size_t index) + { + return index >= GUEST_CR_OFFSET && index < GUEST_CR_OFFSET + GUEST_CR_COUNT; + } + Arm64Gen::ARM64Reg BindForRead(size_t index); void SetImmediateInternal(size_t index, u32 imm, bool dirty); void BindForWrite(size_t index, bool will_read, bool will_write = true); From 84247df6819eaea743cf9e47b26f1ec007f8091f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Vanda=C3=ABle?= Date: Tue, 30 Dec 2025 19:48:45 +0100 Subject: [PATCH 083/267] curl: Disable manual This also fixes a configure-time warning if perl is not present --- Externals/curl/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Externals/curl/CMakeLists.txt b/Externals/curl/CMakeLists.txt index d48eafefcc76..55f010fb15bf 100644 --- a/Externals/curl/CMakeLists.txt +++ b/Externals/curl/CMakeLists.txt @@ -6,6 +6,7 @@ set(BUILD_SHARED_LIBS OFF) set(BUILD_STATIC_LIBS ON) set(BUILD_TESTING OFF) set(CURL_ENABLE_EXPORT_TARGET OFF) +set(ENABLE_CURL_MANUAL OFF) set(HTTP_ONLY ON) From 2e1170b054a648073540782f8061e9fe0cb51343 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Wed, 31 Dec 2025 20:49:12 -0600 Subject: [PATCH 084/267] Externals: Update SDL to release-3.4.0. --- Externals/SDL/CMakeLists.txt | 6 ++-- Externals/SDL/SDL | 2 +- Externals/SDL/SDL3.vcxproj | 54 ++++++++++++++++++++++++------------ 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/Externals/SDL/CMakeLists.txt b/Externals/SDL/CMakeLists.txt index 9e054f77d9b2..712b9fac9522 100644 --- a/Externals/SDL/CMakeLists.txt +++ b/Externals/SDL/CMakeLists.txt @@ -8,14 +8,12 @@ set(SDL_INSTALL_TESTS OFF) set(SDL_UNIX_CONSOLE_BUILD ON) set(SDL_AUDIO OFF) -if (NOT APPLE) - # Working around cocoa/SDL_tray.m linker errors. - set(SDL_VIDEO OFF) -endif() +set(SDL_VIDEO OFF) set(SDL_GPU OFF) set(SDL_RENDER OFF) set(SDL_CAMERA OFF) set(SDL_DIALOG OFF) +set(SDL_TRAY OFF) add_subdirectory(SDL) diff --git a/Externals/SDL/SDL b/Externals/SDL/SDL index 7f3ae3d57459..a962f40bbba1 160000 --- a/Externals/SDL/SDL +++ b/Externals/SDL/SDL @@ -1 +1 @@ -Subproject commit 7f3ae3d57459e59943a4ecfefc8f6277ec6bf540 +Subproject commit a962f40bbba175e9716557a25d5d7965f134a3d3 diff --git a/Externals/SDL/SDL3.vcxproj b/Externals/SDL/SDL3.vcxproj index 63e0f81b8a08..d2515630ec14 100644 --- a/Externals/SDL/SDL3.vcxproj +++ b/Externals/SDL/SDL3.vcxproj @@ -22,18 +22,21 @@ - - - + + + + + + @@ -43,9 +46,11 @@ - - + + + + @@ -53,11 +58,13 @@ + + @@ -76,7 +83,6 @@ - @@ -98,6 +104,7 @@ + @@ -113,6 +120,7 @@ + @@ -145,13 +153,16 @@ + + + @@ -186,7 +197,6 @@ - @@ -266,9 +276,11 @@ + + @@ -313,19 +325,14 @@ - + - - NotUsing - NotUsing - NotUsing - NotUsing - + @@ -345,28 +352,39 @@ + + - + + + + + + + + + + @@ -380,6 +398,7 @@ + @@ -408,7 +427,6 @@ - @@ -479,6 +497,7 @@ + @@ -486,12 +505,11 @@ - - + From af0d03b399d4d23152e713585a75b4880ec925d8 Mon Sep 17 00:00:00 2001 From: Leonardo Ledda Date: Thu, 1 Jan 2026 13:43:38 +0100 Subject: [PATCH 085/267] Android: Use compilerOptions block to specify JVM version * Fixes deprecation warning Signed-off-by: Leonardo Ledda --- Source/Android/app/build.gradle.kts | 8 ++++++-- Source/Android/benchmark/build.gradle.kts | 7 +++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Source/Android/app/build.gradle.kts b/Source/Android/app/build.gradle.kts index 2beaad255118..64d909423c1f 100644 --- a/Source/Android/app/build.gradle.kts +++ b/Source/Android/app/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { id("com.android.application") id("org.jetbrains.kotlin.android") @@ -23,8 +25,10 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = "17" + kotlin { + compilerOptions { + jvmTarget = JvmTarget.fromTarget("17") + } } lint { diff --git a/Source/Android/benchmark/build.gradle.kts b/Source/Android/benchmark/build.gradle.kts index 06267c42e565..242aff8f8606 100644 --- a/Source/Android/benchmark/build.gradle.kts +++ b/Source/Android/benchmark/build.gradle.kts @@ -1,4 +1,5 @@ import com.android.build.api.dsl.ManagedVirtualDevice +import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { id("com.android.test") @@ -15,8 +16,10 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = "17" + kotlin { + compilerOptions { + jvmTarget = JvmTarget.fromTarget("17") + } } defaultConfig { From 593c9f3836d2dab05cdd74272dda4a3addaa8ebd Mon Sep 17 00:00:00 2001 From: Leonardo Ledda Date: Thu, 1 Jan 2026 14:11:37 +0100 Subject: [PATCH 086/267] Android: Switch to Theme.Material3.DynamicColors * This fixes some UI elements (3-dot menu background, status bar when scrolling down in settings) not following Material You colors. * It doesn't cause any issues on Android versions without dynamic colors (tested on Android 9, 11, 16) Signed-off-by: Leonardo Ledda --- Source/Android/app/src/main/res/values/themes.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Android/app/src/main/res/values/themes.xml b/Source/Android/app/src/main/res/values/themes.xml index e2e24397b90c..efd994af8e05 100644 --- a/Source/Android/app/src/main/res/values/themes.xml +++ b/Source/Android/app/src/main/res/values/themes.xml @@ -13,7 +13,7 @@ -