From d03f9032c129e440e4f07d319be8b52500798e07 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sat, 25 Jan 2025 21:49:32 -0600 Subject: [PATCH] Core / DolphinQt / InputCommon: reduce the number disk writes when using DynamicInputTextures --- .../Android/jni/Input/EmulatedController.cpp | 9 +++- Source/Core/Core/Core.cpp | 3 ++ Source/Core/Core/HW/GCKeyboard.cpp | 5 +++ Source/Core/Core/HW/GCKeyboard.h | 1 + Source/Core/Core/HW/GCPad.cpp | 5 +++ Source/Core/Core/HW/GCPad.h | 1 + Source/Core/Core/HW/Wiimote.cpp | 5 +++ Source/Core/Core/HW/Wiimote.h | 1 + .../Config/Mapping/MappingCommon.cpp | 2 + .../Config/Mapping/MappingWindow.cpp | 3 ++ .../DynamicInputTextureManager.cpp | 28 ++++++++++++- .../DynamicInputTextures/DITConfiguration.cpp | 42 +++++++------------ .../DynamicInputTextures/DITConfiguration.h | 15 ++++--- Source/Core/InputCommon/InputConfig.cpp | 23 +++++++--- Source/Core/InputCommon/InputConfig.h | 1 + 15 files changed, 102 insertions(+), 42 deletions(-) diff --git a/Source/Android/jni/Input/EmulatedController.cpp b/Source/Android/jni/Input/EmulatedController.cpp index 8a76240dfd..7cfa0dc024 100644 --- a/Source/Android/jni/Input/EmulatedController.cpp +++ b/Source/Android/jni/Input/EmulatedController.cpp @@ -71,8 +71,10 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedController_updateSingleControlReference( JNIEnv* env, jobject obj, jobject control_reference) { - return EmulatedControllerFromJava(env, obj)->UpdateSingleControlReference( - g_controller_interface, ControlReferenceFromJava(env, control_reference)); + ControllerEmu::EmulatedController* controller = EmulatedControllerFromJava(env, obj); + controller->GetConfig()->GenerateControllerTextures(); + return controller->UpdateSingleControlReference(g_controller_interface, + ControlReferenceFromJava(env, control_reference)); } JNIEXPORT void JNICALL @@ -83,6 +85,7 @@ Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedContro controller->LoadDefaults(g_controller_interface); controller->UpdateReferences(g_controller_interface); + controller->GetConfig()->GenerateControllerTextures(); } JNIEXPORT void JNICALL @@ -96,6 +99,7 @@ Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedContro controller->LoadConfig(§ion); controller->UpdateReferences(g_controller_interface); + controller->GetConfig()->GenerateControllerTextures(); } JNIEXPORT void JNICALL @@ -109,6 +113,7 @@ Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedContro controller->LoadConfig(ini.GetOrCreateSection("Profile")); controller->UpdateReferences(g_controller_interface); + controller->GetConfig()->GenerateControllerTextures(); } JNIEXPORT void JNICALL diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 6a3ebca94f..18dbcaa783 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -493,8 +493,10 @@ static void EmuThread(Core::System& system, std::unique_ptr boot g_controller_interface.ChangeWindow(wsi.render_window); Pad::LoadConfig(); + Pad::GenerateDynamicInputTextures(); Pad::LoadGBAConfig(); Keyboard::LoadConfig(); + Keyboard::GenerateDynamicInputTextures(); BootSessionData boot_session_data = std::move(boot->boot_session_data); const std::optional& savestate_path = boot_session_data.GetSavestatePath(); @@ -528,6 +530,7 @@ static void EmuThread(Core::System& system, std::unique_ptr boot if (system.IsWii() && !Config::Get(Config::MAIN_BLUETOOTH_PASSTHROUGH_ENABLED)) { Wiimote::LoadConfig(); + Wiimote::GenerateDynamicInputTextures(); } FreeLook::LoadInputConfig(); diff --git a/Source/Core/Core/HW/GCKeyboard.cpp b/Source/Core/Core/HW/GCKeyboard.cpp index 4af090de70..e677e1d6db 100644 --- a/Source/Core/Core/HW/GCKeyboard.cpp +++ b/Source/Core/Core/HW/GCKeyboard.cpp @@ -49,6 +49,11 @@ void LoadConfig() s_config.LoadConfig(); } +void GenerateDynamicInputTextures() +{ + s_config.GenerateControllerTextures(); +} + ControllerEmu::ControlGroup* GetGroup(int port, KeyboardGroup group) { return static_cast(s_config.GetController(port))->GetGroup(group); diff --git a/Source/Core/Core/HW/GCKeyboard.h b/Source/Core/Core/HW/GCKeyboard.h index c3b0a0492a..79956ed672 100644 --- a/Source/Core/Core/HW/GCKeyboard.h +++ b/Source/Core/Core/HW/GCKeyboard.h @@ -19,6 +19,7 @@ namespace Keyboard void Shutdown(); void Initialize(); void LoadConfig(); +void GenerateDynamicInputTextures(); InputConfig* GetConfig(); ControllerEmu::ControlGroup* GetGroup(int port, KeyboardGroup group); diff --git a/Source/Core/Core/HW/GCPad.cpp b/Source/Core/Core/HW/GCPad.cpp index 5450eea0c4..15b5f8b6da 100644 --- a/Source/Core/Core/HW/GCPad.cpp +++ b/Source/Core/Core/HW/GCPad.cpp @@ -46,6 +46,11 @@ void LoadConfig() s_config.LoadConfig(); } +void GenerateDynamicInputTextures() +{ + s_config.GenerateControllerTextures(); +} + bool IsInitialized() { return !s_config.ControllersNeedToBeCreated(); diff --git a/Source/Core/Core/HW/GCPad.h b/Source/Core/Core/HW/GCPad.h index f986e9395d..0ed5ff5d54 100644 --- a/Source/Core/Core/HW/GCPad.h +++ b/Source/Core/Core/HW/GCPad.h @@ -20,6 +20,7 @@ namespace Pad void Shutdown(); void Initialize(); void LoadConfig(); +void GenerateDynamicInputTextures(); bool IsInitialized(); InputConfig* GetConfig(); diff --git a/Source/Core/Core/HW/Wiimote.cpp b/Source/Core/Core/HW/Wiimote.cpp index 4b9e95e34d..b8c138091e 100644 --- a/Source/Core/Core/HW/Wiimote.cpp +++ b/Source/Core/Core/HW/Wiimote.cpp @@ -211,6 +211,11 @@ void LoadConfig() s_last_connect_request_counter.fill(0); } +void GenerateDynamicInputTextures() +{ + s_config.GenerateControllerTextures(); +} + void Resume() { WiimoteReal::Resume(); diff --git a/Source/Core/Core/HW/Wiimote.h b/Source/Core/Core/HW/Wiimote.h index 1acdc3a184..f4b34f479b 100644 --- a/Source/Core/Core/HW/Wiimote.h +++ b/Source/Core/Core/HW/Wiimote.h @@ -78,6 +78,7 @@ void Shutdown(); void Initialize(InitializeMode init_mode); void ResetAllWiimotes(); void LoadConfig(); +void GenerateDynamicInputTextures(); void Resume(); void Pause(); diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp index f1220ec29e..fd855d5d14 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingCommon.cpp @@ -16,6 +16,7 @@ #include "InputCommon/ControllerEmu/ControllerEmu.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/ControllerInterface/MappingCommon.h" +#include "InputCommon/InputConfig.h" namespace MappingCommon { @@ -135,6 +136,7 @@ public: m_parent->Save(); m_parent->GetController()->UpdateSingleControlReference(g_controller_interface, control_reference); + m_parent->GetController()->GetConfig()->GenerateControllerTextures(); } void UpdateInputDetectionStartTimer() diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp index d8eb6ec408..aab247dfa0 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingWindow.cpp @@ -322,6 +322,7 @@ void MappingWindow::OnLoadProfilePressed() m_controller->LoadConfig(ini.GetOrCreateSection("Profile")); m_controller->UpdateReferences(g_controller_interface); + m_controller->GetConfig()->GenerateControllerTextures(); const auto lock = GetController()->GetStateLock(); emit ConfigChanged(); @@ -561,6 +562,7 @@ void MappingWindow::OnDefaultFieldsPressed() { m_controller->LoadDefaults(g_controller_interface); m_controller->UpdateReferences(g_controller_interface); + m_controller->GetConfig()->GenerateControllerTextures(); const auto lock = GetController()->GetStateLock(); emit ConfigChanged(); @@ -578,6 +580,7 @@ void MappingWindow::OnClearFieldsPressed() m_controller->SetDefaultDevice(default_device); m_controller->UpdateReferences(g_controller_interface); + m_controller->GetConfig()->GenerateControllerTextures(); const auto lock = GetController()->GetStateLock(); emit ConfigChanged(); diff --git a/Source/Core/InputCommon/DynamicInputTextureManager.cpp b/Source/Core/InputCommon/DynamicInputTextureManager.cpp index fade2c05d4..af5214bd37 100644 --- a/Source/Core/InputCommon/DynamicInputTextureManager.cpp +++ b/Source/Core/InputCommon/DynamicInputTextureManager.cpp @@ -12,6 +12,7 @@ #include "Core/Core.h" #include "InputCommon/DynamicInputTextures/DITConfiguration.h" +#include "InputCommon/ImageOperations.h" #include "VideoCommon/HiresTextures.h" #include "VideoCommon/TextureCacheBase.h" @@ -42,9 +43,34 @@ void DynamicInputTextureManager::Load() void DynamicInputTextureManager::GenerateTextures(const Common::IniFile& file, const std::vector& controller_names) { + DynamicInputTextures::OutputDetails output; for (const auto& configuration : m_configuration) { - (void)configuration.GenerateTextures(file, controller_names); + configuration.GenerateTextures(file, controller_names, &output); + } + + const std::string& game_id = SConfig::GetInstance().GetGameID(); + for (const auto& [generated_folder_name, images] : output) + { + const auto hi_res_folder = File::GetUserPath(D_HIRESTEXTURES_IDX) + generated_folder_name; + + if (!File::IsDirectory(hi_res_folder)) + { + File::CreateDir(hi_res_folder); + } + + const auto game_id_folder = hi_res_folder + DIR_SEP + "gameids"; + if (!File::IsDirectory(game_id_folder)) + { + File::CreateDir(game_id_folder); + } + + File::CreateEmptyFile(game_id_folder + DIR_SEP + game_id + ".txt"); + + for (const auto& [image_name, image] : images) + { + WriteImage(hi_res_folder + DIR_SEP + image_name, image); + } } } } // namespace InputCommon diff --git a/Source/Core/InputCommon/DynamicInputTextures/DITConfiguration.cpp b/Source/Core/InputCommon/DynamicInputTextures/DITConfiguration.cpp index 870dbf9bba..cced429e81 100644 --- a/Source/Core/InputCommon/DynamicInputTextures/DITConfiguration.cpp +++ b/Source/Core/InputCommon/DynamicInputTextures/DITConfiguration.cpp @@ -10,7 +10,6 @@ #include #include "Common/CommonPaths.h" -#include "Common/FileUtil.h" #include "Common/IniFile.h" #include "Common/JsonUtil.h" #include "Common/Logging/Log.h" @@ -68,26 +67,30 @@ Configuration::Configuration(const std::string& json_path) Configuration::~Configuration() = default; -bool Configuration::GenerateTextures(const Common::IniFile& file, - const std::vector& controller_names) const +void Configuration::GenerateTextures(const Common::IniFile& file, + const std::vector& controller_names, + OutputDetails* output) const { - bool any_dirty = false; for (const auto& texture_data : m_dynamic_input_textures) { - any_dirty |= GenerateTexture(file, controller_names, texture_data); + GenerateTexture(file, controller_names, texture_data, output); } - - return any_dirty; } -bool Configuration::GenerateTexture(const Common::IniFile& file, +void Configuration::GenerateTexture(const Common::IniFile& file, const std::vector& controller_names, - const Data& texture_data) const + const Data& texture_data, OutputDetails* output) const { // Two copies of the loaded texture // The first one is used as a fallback if a key or device isn't mapped // the second one is used as the final image to write to the textures directory const auto original_image = LoadImage(m_base_path + texture_data.m_image_name); + if (!original_image) + { + ERROR_LOG_FMT(VIDEO, "Failed to load image '{}' needed for dynamic input texture generation", + texture_data.m_image_name); + return; + } auto image_to_write = original_image; bool dirty = false; @@ -179,25 +182,8 @@ bool Configuration::GenerateTexture(const Common::IniFile& file, if (dirty) { - const std::string& game_id = SConfig::GetInstance().GetGameID(); - const auto hi_res_folder = - File::GetUserPath(D_HIRESTEXTURES_IDX) + texture_data.m_generated_folder_name; - if (!File::IsDirectory(hi_res_folder)) - { - File::CreateDir(hi_res_folder); - } - WriteImage(hi_res_folder + DIR_SEP + texture_data.m_hires_texture_name, *image_to_write); - - const auto game_id_folder = hi_res_folder + DIR_SEP + "gameids"; - if (!File::IsDirectory(game_id_folder)) - { - File::CreateDir(game_id_folder); - } - File::CreateEmptyFile(game_id_folder + DIR_SEP + game_id + ".txt"); - - return true; + (*output)[texture_data.m_generated_folder_name][texture_data.m_hires_texture_name] = + std::move(*image_to_write); } - - return false; } } // namespace InputCommon::DynamicInputTextures diff --git a/Source/Core/InputCommon/DynamicInputTextures/DITConfiguration.h b/Source/Core/InputCommon/DynamicInputTextures/DITConfiguration.h index 145099ea27..68a55c2af4 100644 --- a/Source/Core/InputCommon/DynamicInputTextures/DITConfiguration.h +++ b/Source/Core/InputCommon/DynamicInputTextures/DITConfiguration.h @@ -3,11 +3,13 @@ #pragma once +#include #include #include #include "Common/CommonTypes.h" #include "InputCommon/DynamicInputTextures/DITData.h" +#include "InputCommon/ImageOperations.h" namespace Common { @@ -16,18 +18,21 @@ class IniFile; namespace InputCommon::DynamicInputTextures { +// Output folder name to image name to image data +using OutputDetails = std::map>; class Configuration { public: explicit Configuration(const std::string& json_path); ~Configuration(); - bool GenerateTextures(const Common::IniFile& file, - const std::vector& controller_names) const; + void GenerateTextures(const Common::IniFile& file, + const std::vector& controller_names, + OutputDetails* output) const; private: - bool GenerateTexture(const Common::IniFile& file, - const std::vector& controller_names, - const Data& texture_data) const; + void GenerateTexture(const Common::IniFile& file, + const std::vector& controller_names, const Data& texture_data, + OutputDetails* output) const; std::vector m_dynamic_input_textures; std::string m_base_path; diff --git a/Source/Core/InputCommon/InputConfig.cpp b/Source/Core/InputCommon/InputConfig.cpp index ff3f68acd0..2dd39f945b 100644 --- a/Source/Core/InputCommon/InputConfig.cpp +++ b/Source/Core/InputCommon/InputConfig.cpp @@ -35,8 +35,6 @@ bool InputConfig::LoadConfig() static constexpr std::array num = {"1", "2", "3", "4", "BB"}; std::string profile[MAX_BBMOTES]; - m_dynamic_input_tex_config_manager.Load(); - if (SConfig::GetInstance().GetGameID() != "00000000") { const std::string profile_directory = GetUserProfileDirectoryPath(); @@ -102,8 +100,6 @@ bool InputConfig::LoadConfig() // Next profile n++; } - - m_dynamic_input_tex_config_manager.GenerateTextures(inifile, controller_names); return true; } else @@ -139,8 +135,6 @@ void InputConfig::SaveConfig() controller_names.push_back(controller->GetName()); } - m_dynamic_input_tex_config_manager.GenerateTextures(inifile, controller_names); - inifile.Save(ini_filename); } @@ -210,6 +204,8 @@ bool InputConfig::IsControllerControlledByGamepadDevice(int index) const void InputConfig::GenerateControllerTextures(const Common::IniFile& file) { + m_dynamic_input_tex_config_manager.Load(); + std::vector controller_names; for (auto& controller : m_controllers) { @@ -218,3 +214,18 @@ void InputConfig::GenerateControllerTextures(const Common::IniFile& file) m_dynamic_input_tex_config_manager.GenerateTextures(file, controller_names); } + +void InputConfig::GenerateControllerTextures() +{ + const std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + m_ini_name + ".ini"; + + Common::IniFile inifile; + inifile.Load(ini_filename); + + for (auto& controller : m_controllers) + { + controller->SaveConfig(inifile.GetOrCreateSection(controller->GetName())); + } + + GenerateControllerTextures(inifile); +} diff --git a/Source/Core/InputCommon/InputConfig.h b/Source/Core/InputCommon/InputConfig.h index 09b9f6c182..6cd428a8d8 100644 --- a/Source/Core/InputCommon/InputConfig.h +++ b/Source/Core/InputCommon/InputConfig.h @@ -55,6 +55,7 @@ public: void UnregisterHotplugCallback(); void GenerateControllerTextures(const Common::IniFile& file); + void GenerateControllerTextures(); private: ControllerInterface::HotplugCallbackHandle m_hotplug_callback_handle;