From 7036299a92c3a2b550be052a710ef564bfd3af0d Mon Sep 17 00:00:00 2001 From: Techjar Date: Thu, 19 Jul 2018 18:10:37 -0400 Subject: [PATCH] NetPlay: Improve settings synchronization and UI Most settings which affect determinism will now be synced on NetPlay. Additionally, there's a strict sync mode which will sync various enhancements to prevent desync in games that use EFB reads. This also adds a check for all players having the IPL.bin file, and doesn't load it for anyone if someone is missing it. This prevents desyncs caused by mismatched system fonts. Additionally, the NetPlay window was getting too wide with checkboxes, so FlowLayout has been introduced to make the checkboxes take up multiple rows dynamically. However, there's some minor vertical centering issues I haven't been able to solve, but it's better than a ridiculously wide window. --- Source/Core/Core/BootManager.cpp | 28 ++- Source/Core/Core/Config/MainSettings.cpp | 2 + Source/Core/Core/Config/MainSettings.h | 2 + .../Core/ConfigLoaders/GameConfigLoader.cpp | 3 +- .../ConfigLoaders/NetPlayConfigLoader.cpp | 51 ++++- Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp | 23 +- Source/Core/Core/HW/EXI/EXI_DeviceIPL.h | 5 +- Source/Core/Core/NetPlayClient.cpp | 44 ++++ Source/Core/Core/NetPlayProto.h | 39 ++++ Source/Core/Core/NetPlayServer.cpp | 53 +++++ Source/Core/Core/NetPlayServer.h | 2 + Source/Core/DolphinQt/CMakeLists.txt | 1 + Source/Core/DolphinQt/DolphinQt.vcxproj | 3 + .../Core/DolphinQt/NetPlay/NetPlayDialog.cpp | 133 +++++++++-- Source/Core/DolphinQt/NetPlay/NetPlayDialog.h | 1 + Source/Core/DolphinQt/QtUtils/FlowLayout.cpp | 212 ++++++++++++++++++ Source/Core/DolphinQt/QtUtils/FlowLayout.h | 84 +++++++ .../Core/DolphinQt/Settings/AdvancedPane.cpp | 7 +- Source/Core/DolphinQt/Settings/AudioPane.cpp | 3 + .../Core/DolphinQt/Settings/GameCubePane.cpp | 16 ++ .../Core/DolphinQt/Settings/GeneralPane.cpp | 4 + 21 files changed, 685 insertions(+), 31 deletions(-) create mode 100644 Source/Core/DolphinQt/QtUtils/FlowLayout.cpp create mode 100644 Source/Core/DolphinQt/QtUtils/FlowLayout.h diff --git a/Source/Core/Core/BootManager.cpp b/Source/Core/Core/BootManager.cpp index 80ee9f7348..1a6190925d 100644 --- a/Source/Core/Core/BootManager.cpp +++ b/Source/Core/Core/BootManager.cpp @@ -72,6 +72,7 @@ public: private: bool valid; bool bCPUThread; + bool bJITFollowBranch; bool bEnableCheats; bool bSyncGPUOnSkipIdleHack; bool bFPRF; @@ -81,6 +82,9 @@ private: bool bLowDCBZHack; bool m_EnableJIT; bool bSyncGPU; + int iSyncGpuMaxDistance; + int iSyncGpuMinDistance; + float fSyncGpuOverclock; bool bFastDiscSpeed; bool bDSPHLE; bool bHLE_BS2; @@ -103,6 +107,7 @@ void ConfigCache::SaveConfig(const SConfig& config) valid = true; bCPUThread = config.bCPUThread; + bJITFollowBranch = config.bJITFollowBranch; bEnableCheats = config.bEnableCheats; bSyncGPUOnSkipIdleHack = config.bSyncGPUOnSkipIdleHack; bFPRF = config.bFPRF; @@ -111,6 +116,9 @@ void ConfigCache::SaveConfig(const SConfig& config) bDCBZOFF = config.bDCBZOFF; m_EnableJIT = config.m_DSPEnableJIT; bSyncGPU = config.bSyncGPU; + iSyncGpuMaxDistance = config.iSyncGpuMaxDistance; + iSyncGpuMinDistance = config.iSyncGpuMinDistance; + fSyncGpuOverclock = config.fSyncGpuOverclock; bFastDiscSpeed = config.bFastDiscSpeed; bDSPHLE = config.bDSPHLE; bHLE_BS2 = config.bHLE_BS2; @@ -143,6 +151,7 @@ void ConfigCache::RestoreConfig(SConfig* config) valid = false; config->bCPUThread = bCPUThread; + config->bJITFollowBranch = bJITFollowBranch; config->bEnableCheats = bEnableCheats; config->bSyncGPUOnSkipIdleHack = bSyncGPUOnSkipIdleHack; config->bFPRF = bFPRF; @@ -152,6 +161,9 @@ void ConfigCache::RestoreConfig(SConfig* config) config->bLowDCBZHack = bLowDCBZHack; config->m_DSPEnableJIT = m_EnableJIT; config->bSyncGPU = bSyncGPU; + config->iSyncGpuMaxDistance = iSyncGpuMaxDistance; + config->iSyncGpuMinDistance = iSyncGpuMinDistance; + config->fSyncGpuOverclock = fSyncGpuOverclock; config->bFastDiscSpeed = bFastDiscSpeed; config->bDSPHLE = bDSPHLE; config->bHLE_BS2 = bHLE_BS2; @@ -240,7 +252,6 @@ bool BootCore(std::unique_ptr boot) IniFile::Section* controls_section = game_ini.GetOrCreateSection("Controls"); core_section->Get("CPUThread", &StartUp.bCPUThread, StartUp.bCPUThread); - core_section->Get("JITFollowBranch", &StartUp.bJITFollowBranch, StartUp.bJITFollowBranch); core_section->Get("EnableCheats", &StartUp.bEnableCheats, StartUp.bEnableCheats); core_section->Get("SyncOnSkipIdle", &StartUp.bSyncGPUOnSkipIdleHack, @@ -314,6 +325,7 @@ bool BootCore(std::unique_ptr boot) { // TODO: remove this once ConfigManager starts using OnionConfig. StartUp.bCPUThread = Config::Get(Config::MAIN_CPU_THREAD); + StartUp.bJITFollowBranch = Config::Get(Config::MAIN_JIT_FOLLOW_BRANCH); StartUp.bDSPHLE = Config::Get(Config::MAIN_DSP_HLE); StartUp.bFastDiscSpeed = Config::Get(Config::MAIN_FAST_DISC_SPEED); StartUp.cpu_core = Config::Get(Config::MAIN_CPU_CORE); @@ -353,6 +365,18 @@ bool BootCore(std::unique_ptr boot) StartUp.m_EXIDevice[1] = netplay_settings.m_EXIDevice[1]; config_cache.bSetEXIDevice[0] = true; config_cache.bSetEXIDevice[1] = true; + StartUp.bFPRF = netplay_settings.m_FPRF; + StartUp.bAccurateNaNs = netplay_settings.m_AccurateNaNs; + StartUp.bSyncGPUOnSkipIdleHack = netplay_settings.m_SyncOnSkipIdle; + StartUp.bSyncGPU = netplay_settings.m_SyncGPU; + StartUp.iSyncGpuMaxDistance = netplay_settings.m_SyncGpuMaxDistance; + StartUp.iSyncGpuMinDistance = netplay_settings.m_SyncGpuMinDistance; + StartUp.fSyncGpuOverclock = netplay_settings.m_SyncGpuOverclock; + StartUp.bJITFollowBranch = netplay_settings.m_JITFollowBranch; + StartUp.bFastDiscSpeed = netplay_settings.m_FastDiscSpeed; + StartUp.bMMU = netplay_settings.m_MMU; + StartUp.bFastmem = netplay_settings.m_Fastmem; + StartUp.bHLE_BS2 = netplay_settings.m_SkipIPL; } else { @@ -432,4 +456,4 @@ void RestoreConfig() config_cache.RestoreConfig(&SConfig::GetInstance()); } -} // namespace +} // namespace BootManager diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 027c4916a2..1c9882a951 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -16,8 +16,10 @@ namespace Config // Main.Core const ConfigInfo MAIN_SKIP_IPL{{System::Main, "Core", "SkipIPL"}, true}; +const ConfigInfo MAIN_LOAD_IPL_DUMP{{System::Main, "Core", "LoadIPLDump"}, true}; const ConfigInfo MAIN_CPU_CORE{{System::Main, "Core", "CPUCore"}, PowerPC::DefaultCPUCore()}; +const ConfigInfo MAIN_JIT_FOLLOW_BRANCH{{System::Main, "Core", "JITFollowBranch"}, true}; const ConfigInfo MAIN_FASTMEM{{System::Main, "Core", "Fastmem"}, true}; const ConfigInfo MAIN_DSP_HLE{{System::Main, "Core", "DSPHLE"}, true}; const ConfigInfo MAIN_TIMING_VARIANCE{{System::Main, "Core", "TimingVariance"}, 40}; diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index 260c16a1bc..3cfd4e3b5d 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -17,6 +17,8 @@ namespace Config { // Main.Core +extern const ConfigInfo MAIN_SKIP_IPL; +extern const ConfigInfo MAIN_LOAD_IPL_DUMP; extern const ConfigInfo MAIN_CPU_CORE; extern const ConfigInfo MAIN_JIT_FOLLOW_BRANCH; extern const ConfigInfo MAIN_FASTMEM; diff --git a/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp index 167cbecd0e..cb417d3b16 100644 --- a/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp +++ b/Source/Core/Core/ConfigLoaders/GameConfigLoader.cpp @@ -83,6 +83,7 @@ static const INIToLocationMap& GetINIToLocationMap() static const INIToSectionMap& GetINIToSectionMap() { static const INIToSectionMap ini_to_section = { + {"Core", {Config::System::Main, "Core"}}, {"Video_Hardware", {Config::System::GFX, "Hardware"}}, {"Video_Settings", {Config::System::GFX, "Settings"}}, {"Video_Enhancements", {Config::System::GFX, "Enhancements"}}, @@ -315,4 +316,4 @@ std::unique_ptr GenerateLocalGameConfigLoader(const s { return std::make_unique(id, revision, false); } -} +} // namespace ConfigLoaders diff --git a/Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp index 4f70d58399..6aa190593c 100644 --- a/Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp +++ b/Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp @@ -9,6 +9,7 @@ #include "Common/CommonPaths.h" #include "Common/Config/Config.h" #include "Common/FileUtil.h" +#include "Core/Config/GraphicsSettings.h" #include "Core/Config/MainSettings.h" #include "Core/Config/SYSCONFSettings.h" #include "Core/NetPlayProto.h" @@ -36,11 +37,57 @@ public: layer->Set(Config::MAIN_SLOT_B, static_cast(m_settings.m_EXIDevice[1])); layer->Set(Config::MAIN_WII_SD_CARD_WRITABLE, m_settings.m_WriteToMemcard); layer->Set(Config::MAIN_REDUCE_POLLING_RATE, m_settings.m_ReducePollingRate); - layer->Set(Config::MAIN_DSP_JIT, m_settings.m_DSPEnableJIT); - layer->Set(Config::SYSCONF_PROGRESSIVE_SCAN, m_settings.m_ProgressiveScan); layer->Set(Config::SYSCONF_PAL60, m_settings.m_PAL60); + layer->Set(Config::GFX_HACK_EFB_ACCESS_ENABLE, m_settings.m_EFBAccessEnable); + layer->Set(Config::GFX_HACK_BBOX_ENABLE, m_settings.m_BBoxEnable); + layer->Set(Config::GFX_HACK_FORCE_PROGRESSIVE, m_settings.m_ForceProgressive); + layer->Set(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, m_settings.m_EFBToTextureEnable); + layer->Set(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM, m_settings.m_XFBToTextureEnable); + layer->Set(Config::GFX_HACK_DISABLE_COPY_TO_VRAM, m_settings.m_DisableCopyToVRAM); + layer->Set(Config::GFX_HACK_IMMEDIATE_XFB, m_settings.m_ImmediateXFBEnable); + layer->Set(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES, m_settings.m_EFBEmulateFormatChanges); + layer->Set(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES, + m_settings.m_SafeTextureCacheColorSamples); + layer->Set(Config::GFX_PERF_QUERIES_ENABLE, m_settings.m_PerfQueriesEnable); + layer->Set(Config::MAIN_FPRF, m_settings.m_FPRF); + layer->Set(Config::MAIN_ACCURATE_NANS, m_settings.m_AccurateNaNs); + layer->Set(Config::MAIN_SYNC_ON_SKIP_IDLE, m_settings.m_SyncOnSkipIdle); + layer->Set(Config::MAIN_SYNC_GPU, m_settings.m_SyncGPU); + layer->Set(Config::MAIN_SYNC_GPU_MAX_DISTANCE, m_settings.m_SyncGpuMaxDistance); + layer->Set(Config::MAIN_SYNC_GPU_MIN_DISTANCE, m_settings.m_SyncGpuMinDistance); + layer->Set(Config::MAIN_SYNC_GPU_OVERCLOCK, m_settings.m_SyncGpuOverclock); + layer->Set(Config::MAIN_JIT_FOLLOW_BRANCH, m_settings.m_JITFollowBranch); + layer->Set(Config::MAIN_FAST_DISC_SPEED, m_settings.m_FastDiscSpeed); + layer->Set(Config::MAIN_MMU, m_settings.m_MMU); + layer->Set(Config::MAIN_FASTMEM, m_settings.m_Fastmem); + layer->Set(Config::MAIN_SKIP_IPL, m_settings.m_SkipIPL); + layer->Set(Config::MAIN_LOAD_IPL_DUMP, m_settings.m_LoadIPLDump); + + if (m_settings.m_StrictSettingsSync) + { + layer->Set(Config::GFX_HACK_VERTEX_ROUDING, m_settings.m_VertexRounding); + layer->Set(Config::GFX_EFB_SCALE, m_settings.m_InternalResolution); + layer->Set(Config::GFX_HACK_COPY_EFB_SCALED, m_settings.m_EFBScaledCopy); + layer->Set(Config::GFX_FAST_DEPTH_CALC, m_settings.m_FastDepthCalc); + layer->Set(Config::GFX_ENABLE_PIXEL_LIGHTING, m_settings.m_EnablePixelLighting); + layer->Set(Config::GFX_WIDESCREEN_HACK, m_settings.m_WidescreenHack); + layer->Set(Config::GFX_ENHANCE_FORCE_FILTERING, m_settings.m_ForceFiltering); + layer->Set(Config::GFX_ENHANCE_MAX_ANISOTROPY, m_settings.m_MaxAnisotropy); + layer->Set(Config::GFX_ENHANCE_FORCE_TRUE_COLOR, m_settings.m_ForceTrueColor); + layer->Set(Config::GFX_ENHANCE_DISABLE_COPY_FILTER, m_settings.m_DisableCopyFilter); + layer->Set(Config::GFX_DISABLE_FOG, m_settings.m_DisableFog); + layer->Set(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION, + m_settings.m_ArbitraryMipmapDetection); + layer->Set(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION_THRESHOLD, + m_settings.m_ArbitraryMipmapDetectionThreshold); + layer->Set(Config::GFX_ENABLE_GPU_TEXTURE_DECODING, m_settings.m_EnableGPUTextureDecoding); + + // Disable AA as it isn't deterministic across GPUs + layer->Set(Config::GFX_MSAA, 1); + layer->Set(Config::GFX_SSAA, false); + } if (m_settings.m_SyncSaveData) { diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp index 70355dbd62..7f2c259516 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp @@ -11,6 +11,7 @@ #include "Common/ChunkFile.h" #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" +#include "Common/Config/Config.h" #include "Common/File.h" #include "Common/FileUtil.h" #include "Common/Logging/Log.h" @@ -19,6 +20,7 @@ #include "Common/Swap.h" #include "Common/Timer.h" +#include "Core/Config/MainSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" @@ -102,7 +104,8 @@ CEXIIPL::CEXIIPL() // Load whole ROM dump // Note: The Wii doesn't have a copy of the IPL, only fonts. - if (!SConfig::GetInstance().bWii && LoadFileToIPL(SConfig::GetInstance().m_strBootROM, 0)) + if (!SConfig::GetInstance().bWii && Config::Get(Config::MAIN_LOAD_IPL_DUMP) && + LoadFileToIPL(SConfig::GetInstance().m_strBootROM, 0)) { // Descramble the encrypted section (contains BS1 and BS2) Descrambler(m_ipl + 0x100, 0x1afe00); @@ -185,6 +188,17 @@ std::string CEXIIPL::FindIPLDump(const std::string& path_prefix) return ipl_dump_path; } +bool CEXIIPL::HasIPLDump() +{ + std::string ipl_rom_path = FindIPLDump(File::GetUserPath(D_GCUSER_IDX)); + + // If not found, check again in Sys folder + if (ipl_rom_path.empty()) + ipl_rom_path = FindIPLDump(File::GetSysDirectory() + GC_SYS_DIR); + + return !ipl_rom_path.empty(); +} + void CEXIIPL::LoadFontFile(const std::string& filename, u32 offset) { // Official IPL fonts are copyrighted. Dolphin ships with a set of free font alternatives but @@ -192,6 +206,13 @@ void CEXIIPL::LoadFontFile(const std::string& filename, u32 offset) // in some titles. This function check if the user has IPL dumps available and load the fonts // from those dumps instead of loading the bundled fonts + if (!Config::Get(Config::MAIN_LOAD_IPL_DUMP)) + { + // IPL loading disabled, load bundled font instead + LoadFileToIPL(filename, offset); + return; + } + // Check for IPL dumps in User folder std::string ipl_rom_path = FindIPLDump(File::GetUserPath(D_GCUSER_IDX)); diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceIPL.h b/Source/Core/Core/HW/EXI/EXI_DeviceIPL.h index 2bbd7056ab..fec369af07 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceIPL.h +++ b/Source/Core/Core/HW/EXI/EXI_DeviceIPL.h @@ -31,6 +31,8 @@ public: static void Descrambler(u8* data, u32 size); + static bool HasIPLDump(); + private: enum { @@ -74,6 +76,7 @@ private: u32 CommandRegion() const { return (m_address & ~(1 << 31)) >> 8; } bool LoadFileToIPL(const std::string& filename, u32 offset); void LoadFontFile(const std::string& filename, u32 offset); - std::string FindIPLDump(const std::string& path_prefix); + + static std::string FindIPLDump(const std::string& path_prefix); }; } // namespace ExpansionInterface diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index d29b931ae0..c668296c4f 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -424,6 +424,11 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet) game_status_packet << static_cast(status); Send(game_status_packet); + + sf::Packet ipl_status_packet; + ipl_status_packet << static_cast(NP_MSG_IPL_STATUS); + ipl_status_packet << ExpansionInterface::CEXIIPL::HasIPLDump(); + Send(ipl_status_packet); } break; @@ -480,6 +485,45 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet) packet >> tmp; m_net_settings.m_EXIDevice[1] = static_cast(tmp); + packet >> m_net_settings.m_EFBAccessEnable; + packet >> m_net_settings.m_BBoxEnable; + packet >> m_net_settings.m_ForceProgressive; + packet >> m_net_settings.m_EFBToTextureEnable; + packet >> m_net_settings.m_XFBToTextureEnable; + packet >> m_net_settings.m_DisableCopyToVRAM; + packet >> m_net_settings.m_ImmediateXFBEnable; + packet >> m_net_settings.m_EFBEmulateFormatChanges; + packet >> m_net_settings.m_SafeTextureCacheColorSamples; + packet >> m_net_settings.m_PerfQueriesEnable; + packet >> m_net_settings.m_FPRF; + packet >> m_net_settings.m_AccurateNaNs; + packet >> m_net_settings.m_SyncOnSkipIdle; + packet >> m_net_settings.m_SyncGPU; + packet >> m_net_settings.m_SyncGpuMaxDistance; + packet >> m_net_settings.m_SyncGpuMinDistance; + packet >> m_net_settings.m_SyncGpuOverclock; + packet >> m_net_settings.m_JITFollowBranch; + packet >> m_net_settings.m_FastDiscSpeed; + packet >> m_net_settings.m_MMU; + packet >> m_net_settings.m_Fastmem; + packet >> m_net_settings.m_SkipIPL; + packet >> m_net_settings.m_LoadIPLDump; + packet >> m_net_settings.m_VertexRounding; + packet >> m_net_settings.m_InternalResolution; + packet >> m_net_settings.m_EFBScaledCopy; + packet >> m_net_settings.m_FastDepthCalc; + packet >> m_net_settings.m_EnablePixelLighting; + packet >> m_net_settings.m_WidescreenHack; + packet >> m_net_settings.m_ForceFiltering; + packet >> m_net_settings.m_MaxAnisotropy; + packet >> m_net_settings.m_ForceTrueColor; + packet >> m_net_settings.m_DisableCopyFilter; + packet >> m_net_settings.m_DisableFog; + packet >> m_net_settings.m_ArbitraryMipmapDetection; + packet >> m_net_settings.m_ArbitraryMipmapDetectionThreshold; + packet >> m_net_settings.m_EnableGPUTextureDecoding; + packet >> m_net_settings.m_StrictSettingsSync; + g_netplay_initial_rtc = Common::PacketReadU64(packet); packet >> m_net_settings.m_SyncSaveData; diff --git a/Source/Core/Core/NetPlayProto.h b/Source/Core/Core/NetPlayProto.h index 367af26872..76b098be11 100644 --- a/Source/Core/Core/NetPlayProto.h +++ b/Source/Core/Core/NetPlayProto.h @@ -37,6 +37,44 @@ struct NetSettings bool m_OCEnable; float m_OCFactor; ExpansionInterface::TEXIDevices m_EXIDevice[2]; + bool m_EFBAccessEnable; + bool m_BBoxEnable; + bool m_ForceProgressive; + bool m_EFBToTextureEnable; + bool m_XFBToTextureEnable; + bool m_DisableCopyToVRAM; + bool m_ImmediateXFBEnable; + bool m_EFBEmulateFormatChanges; + int m_SafeTextureCacheColorSamples; + bool m_PerfQueriesEnable; + bool m_FPRF; + bool m_AccurateNaNs; + bool m_SyncOnSkipIdle; + bool m_SyncGPU; + int m_SyncGpuMaxDistance; + int m_SyncGpuMinDistance; + float m_SyncGpuOverclock; + bool m_JITFollowBranch; + bool m_FastDiscSpeed; + bool m_MMU; + bool m_Fastmem; + bool m_SkipIPL; + bool m_LoadIPLDump; + bool m_VertexRounding; + int m_InternalResolution; + bool m_EFBScaledCopy; + bool m_FastDepthCalc; + bool m_EnablePixelLighting; + bool m_WidescreenHack; + bool m_ForceFiltering; + int m_MaxAnisotropy; + bool m_ForceTrueColor; + bool m_DisableCopyFilter; + bool m_DisableFog; + bool m_ArbitraryMipmapDetection; + float m_ArbitraryMipmapDetectionThreshold; + bool m_EnableGPUTextureDecoding; + bool m_StrictSettingsSync; bool m_SyncSaveData; std::string m_SaveDataRegion; bool m_IsHosting; @@ -83,6 +121,7 @@ enum NP_MSG_STOP_GAME = 0xA2, NP_MSG_DISABLE_GAME = 0xA3, NP_MSG_GAME_STATUS = 0xA4, + NP_MSG_IPL_STATUS = 0xA5, NP_MSG_TIMEBASE = 0xB0, NP_MSG_DESYNC_DETECTED = 0xB1, diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index a884aa2dce..e49626976c 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -662,6 +662,15 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player) } break; + case NP_MSG_IPL_STATUS: + { + bool status; + packet >> status; + + m_players[player.pid].has_ipl_dump = status; + } + break; + case NP_MSG_TIMEBASE: { u64 timebase = Common::PacketReadU64(packet); @@ -861,6 +870,12 @@ void NetPlayServer::SetNetSettings(const NetSettings& settings) m_settings = settings; } +bool NetPlayServer::DoAllPlayersHaveIPLDump() const +{ + return std::all_of(m_players.begin(), m_players.end(), + [](const auto& p) { return p.second.has_ipl_dump; }); +} + // called from ---GUI--- thread bool NetPlayServer::RequestStartGame() { @@ -921,6 +936,44 @@ bool NetPlayServer::StartGame() spac << m_settings.m_ReducePollingRate; spac << m_settings.m_EXIDevice[0]; spac << m_settings.m_EXIDevice[1]; + spac << m_settings.m_EFBAccessEnable; + spac << m_settings.m_BBoxEnable; + spac << m_settings.m_ForceProgressive; + spac << m_settings.m_EFBToTextureEnable; + spac << m_settings.m_XFBToTextureEnable; + spac << m_settings.m_DisableCopyToVRAM; + spac << m_settings.m_ImmediateXFBEnable; + spac << m_settings.m_EFBEmulateFormatChanges; + spac << m_settings.m_SafeTextureCacheColorSamples; + spac << m_settings.m_PerfQueriesEnable; + spac << m_settings.m_FPRF; + spac << m_settings.m_AccurateNaNs; + spac << m_settings.m_SyncOnSkipIdle; + spac << m_settings.m_SyncGPU; + spac << m_settings.m_SyncGpuMaxDistance; + spac << m_settings.m_SyncGpuMinDistance; + spac << m_settings.m_SyncGpuOverclock; + spac << m_settings.m_JITFollowBranch; + spac << m_settings.m_FastDiscSpeed; + spac << m_settings.m_MMU; + spac << m_settings.m_Fastmem; + spac << m_settings.m_SkipIPL; + spac << m_settings.m_LoadIPLDump; + spac << m_settings.m_VertexRounding; + spac << m_settings.m_InternalResolution; + spac << m_settings.m_EFBScaledCopy; + spac << m_settings.m_FastDepthCalc; + spac << m_settings.m_EnablePixelLighting; + spac << m_settings.m_WidescreenHack; + spac << m_settings.m_ForceFiltering; + spac << m_settings.m_MaxAnisotropy; + spac << m_settings.m_ForceTrueColor; + spac << m_settings.m_DisableCopyFilter; + spac << m_settings.m_DisableFog; + spac << m_settings.m_ArbitraryMipmapDetection; + spac << m_settings.m_ArbitraryMipmapDetectionThreshold; + spac << m_settings.m_EnableGPUTextureDecoding; + spac << m_settings.m_StrictSettingsSync; Common::PacketWriteU64(spac, g_netplay_initial_rtc); spac << m_settings.m_SyncSaveData; spac << region; diff --git a/Source/Core/Core/NetPlayServer.h b/Source/Core/Core/NetPlayServer.h index 9295cc9d7e..b3484e858e 100644 --- a/Source/Core/Core/NetPlayServer.h +++ b/Source/Core/Core/NetPlayServer.h @@ -40,6 +40,7 @@ public: void SetNetSettings(const NetSettings& settings); + bool DoAllPlayersHaveIPLDump() const; bool StartGame(); bool RequestStartGame(); @@ -69,6 +70,7 @@ private: std::string name; std::string revision; PlayerGameStatus game_status; + bool has_ipl_dump; ENetPeer* socket; u32 ping; diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 19a2320ebe..eff3bdd840 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -98,6 +98,7 @@ add_executable(dolphin-emu NetPlay/PadMappingDialog.cpp QtUtils/DoubleClickEventFilter.cpp QtUtils/ElidedButton.cpp + QtUtils/FlowLayout.cpp QtUtils/ImageConverter.cpp QtUtils/SignalDaemon.cpp QtUtils/WindowActivationEventFilter.cpp diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index b2aa6ae409..0228011308 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -148,6 +148,7 @@ + @@ -176,6 +177,7 @@ + @@ -351,6 +353,7 @@ + diff --git a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp index ce296acef8..956ca83e86 100644 --- a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp +++ b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp @@ -31,7 +31,10 @@ #include "Common/Config/Config.h" #include "Common/TraversalClient.h" +#include "Core/Config/GraphicsSettings.h" +#include "Core/Config/MainSettings.h" #include "Core/Config/SYSCONFSettings.h" +#include "Core/ConfigLoaders/GameConfigLoader.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/NetPlayServer.h" @@ -40,11 +43,14 @@ #include "DolphinQt/NetPlay/GameListDialog.h" #include "DolphinQt/NetPlay/MD5Dialog.h" #include "DolphinQt/NetPlay/PadMappingDialog.h" +#include "DolphinQt/QtUtils/FlowLayout.h" #include "DolphinQt/QtUtils/QueueOnObject.h" #include "DolphinQt/QtUtils/RunOnObject.h" #include "DolphinQt/Resources.h" #include "DolphinQt/Settings.h" +#include "UICommon/GameFile.h" + #include "VideoCommon/VideoConfig.h" NetPlayDialog::NetPlayDialog(QWidget* parent) @@ -89,6 +95,7 @@ void NetPlayDialog::CreateMainLayout() m_sync_save_data_box = new QCheckBox(tr("Sync Saves")); m_record_input_box = new QCheckBox(tr("Record inputs")); m_reduce_polling_rate_box = new QCheckBox(tr("Reduce Polling Rate")); + m_strict_settings_sync_box = new QCheckBox(tr("Strict Settings Sync")); m_buffer_label = new QLabel(tr("Buffer:")); m_quit_button = new QPushButton(tr("Quit")); m_splitter = new QSplitter(Qt::Horizontal); @@ -128,6 +135,10 @@ void NetPlayDialog::CreateMainLayout() m_reduce_polling_rate_box->setToolTip( tr("This will reduce bandwidth usage by polling GameCube controllers only twice per frame. " "Does not affect Wii Remotes.")); + m_strict_settings_sync_box->setToolTip( + tr("This will sync additional graphics settings, and force everyone to the same internal " + "resolution.\nMay prevent desync in some games that use EFB reads. Please ensure everyone " + "uses the same video backend.")); m_main_layout->addWidget(m_game_button, 0, 0); m_main_layout->addWidget(m_md5_button, 0, 1); @@ -136,18 +147,25 @@ void NetPlayDialog::CreateMainLayout() m_splitter->addWidget(m_chat_box); m_splitter->addWidget(m_players_box); - auto* options_widget = new QHBoxLayout; + auto* options_widget = new QGridLayout; + auto* options_boxes = new FlowLayout; + + options_widget->addWidget(m_start_button, 0, 0, Qt::AlignVCenter); + options_widget->addWidget(m_buffer_label, 0, 1, Qt::AlignVCenter); + options_widget->addWidget(m_buffer_size_box, 0, 2, Qt::AlignVCenter); + options_widget->addWidget(m_quit_button, 0, 4, Qt::AlignVCenter); + options_boxes->addWidget(m_save_sd_box); + options_boxes->addWidget(m_load_wii_box); + options_boxes->addWidget(m_sync_save_data_box); + options_boxes->addWidget(m_record_input_box); + options_boxes->addWidget(m_reduce_polling_rate_box); + options_boxes->addWidget(m_strict_settings_sync_box); + + options_widget->addLayout(options_boxes, 0, 3, Qt::AlignTop); + options_widget->setColumnStretch(3, 1000); - options_widget->addWidget(m_start_button); - options_widget->addWidget(m_buffer_label); - options_widget->addWidget(m_buffer_size_box); - options_widget->addWidget(m_save_sd_box); - options_widget->addWidget(m_load_wii_box); - options_widget->addWidget(m_sync_save_data_box); - options_widget->addWidget(m_record_input_box); - options_widget->addWidget(m_reduce_polling_rate_box); - options_widget->addWidget(m_quit_button); m_main_layout->addLayout(options_widget, 2, 0, 1, -1, Qt::AlignRight); + m_main_layout->setRowStretch(1, 1000); setLayout(m_main_layout); } @@ -289,28 +307,97 @@ void NetPlayDialog::OnStart() return; } + if (m_strict_settings_sync_box->isChecked() && Config::Get(Config::GFX_EFB_SCALE) == 0) + { + QMessageBox::critical( + this, tr("Error"), + tr("Auto internal resolution is not allowed in strict sync mode, as it depends on window " + "size.\n\nPlease select a specific internal resolution.")); + return; + } + + const auto game = FindGameFile(m_current_game); + if (!game) + { + PanicAlertT("Selected game doesn't exist in game list!"); + return; + } + NetPlay::NetSettings settings; + // Load GameINI so we can sync the settings from it + Config::AddLayer( + ConfigLoaders::GenerateGlobalGameConfigLoader(game->GetGameID(), game->GetRevision())); + Config::AddLayer( + ConfigLoaders::GenerateLocalGameConfigLoader(game->GetGameID(), game->GetRevision())); + // Copy all relevant settings - SConfig& instance = SConfig::GetInstance(); - settings.m_CPUthread = instance.bCPUThread; - settings.m_CPUcore = instance.cpu_core; - settings.m_EnableCheats = instance.bEnableCheats; - settings.m_SelectedLanguage = instance.SelectedLanguage; - settings.m_OverrideGCLanguage = instance.bOverrideGCLanguage; + settings.m_CPUthread = Config::Get(Config::MAIN_CPU_THREAD); + settings.m_CPUcore = Config::Get(Config::MAIN_CPU_CORE); + settings.m_EnableCheats = Config::Get(Config::MAIN_ENABLE_CHEATS); + settings.m_SelectedLanguage = Config::Get(Config::MAIN_GC_LANGUAGE); + settings.m_OverrideGCLanguage = Config::Get(Config::MAIN_OVERRIDE_GC_LANGUAGE); settings.m_ProgressiveScan = Config::Get(Config::SYSCONF_PROGRESSIVE_SCAN); settings.m_PAL60 = Config::Get(Config::SYSCONF_PAL60); - settings.m_DSPHLE = instance.bDSPHLE; - settings.m_DSPEnableJIT = instance.m_DSPEnableJIT; + settings.m_DSPHLE = Config::Get(Config::MAIN_DSP_HLE); + settings.m_DSPEnableJIT = Config::Get(Config::MAIN_DSP_JIT); settings.m_WriteToMemcard = m_save_sd_box->isChecked(); settings.m_CopyWiiSave = m_load_wii_box->isChecked(); - settings.m_OCEnable = instance.m_OCEnable; - settings.m_OCFactor = instance.m_OCFactor; + settings.m_OCEnable = Config::Get(Config::MAIN_OVERCLOCK_ENABLE); + settings.m_OCFactor = Config::Get(Config::MAIN_OVERCLOCK); settings.m_ReducePollingRate = m_reduce_polling_rate_box->isChecked(); - settings.m_EXIDevice[0] = instance.m_EXIDevice[0]; - settings.m_EXIDevice[1] = instance.m_EXIDevice[1]; + settings.m_EXIDevice[0] = + static_cast(Config::Get(Config::MAIN_SLOT_A)); + settings.m_EXIDevice[1] = + static_cast(Config::Get(Config::MAIN_SLOT_B)); + settings.m_EFBAccessEnable = Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE); + settings.m_BBoxEnable = Config::Get(Config::GFX_HACK_BBOX_ENABLE); + settings.m_ForceProgressive = Config::Get(Config::GFX_HACK_FORCE_PROGRESSIVE); + settings.m_EFBToTextureEnable = Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM); + settings.m_XFBToTextureEnable = Config::Get(Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM); + settings.m_DisableCopyToVRAM = Config::Get(Config::GFX_HACK_DISABLE_COPY_TO_VRAM); + settings.m_ImmediateXFBEnable = Config::Get(Config::GFX_HACK_IMMEDIATE_XFB); + settings.m_EFBEmulateFormatChanges = Config::Get(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES); + settings.m_SafeTextureCacheColorSamples = + Config::Get(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES); + settings.m_PerfQueriesEnable = Config::Get(Config::GFX_PERF_QUERIES_ENABLE); + settings.m_FPRF = Config::Get(Config::MAIN_FPRF); + settings.m_AccurateNaNs = Config::Get(Config::MAIN_ACCURATE_NANS); + settings.m_SyncOnSkipIdle = Config::Get(Config::MAIN_SYNC_ON_SKIP_IDLE); + settings.m_SyncGPU = Config::Get(Config::MAIN_SYNC_GPU); + settings.m_SyncGpuMaxDistance = Config::Get(Config::MAIN_SYNC_GPU_MAX_DISTANCE); + settings.m_SyncGpuMinDistance = Config::Get(Config::MAIN_SYNC_GPU_MIN_DISTANCE); + settings.m_SyncGpuOverclock = Config::Get(Config::MAIN_SYNC_GPU_OVERCLOCK); + settings.m_JITFollowBranch = Config::Get(Config::MAIN_JIT_FOLLOW_BRANCH); + settings.m_FastDiscSpeed = Config::Get(Config::MAIN_FAST_DISC_SPEED); + settings.m_MMU = Config::Get(Config::MAIN_MMU); + settings.m_Fastmem = Config::Get(Config::MAIN_FASTMEM); + settings.m_SkipIPL = Config::Get(Config::MAIN_SKIP_IPL) || + !Settings::Instance().GetNetPlayServer()->DoAllPlayersHaveIPLDump(); + settings.m_LoadIPLDump = Config::Get(Config::MAIN_LOAD_IPL_DUMP) && + Settings::Instance().GetNetPlayServer()->DoAllPlayersHaveIPLDump(); + settings.m_VertexRounding = Config::Get(Config::GFX_HACK_VERTEX_ROUDING); + settings.m_InternalResolution = Config::Get(Config::GFX_EFB_SCALE); + settings.m_EFBScaledCopy = Config::Get(Config::GFX_HACK_COPY_EFB_SCALED); + settings.m_FastDepthCalc = Config::Get(Config::GFX_FAST_DEPTH_CALC); + settings.m_EnablePixelLighting = Config::Get(Config::GFX_ENABLE_PIXEL_LIGHTING); + settings.m_WidescreenHack = Config::Get(Config::GFX_WIDESCREEN_HACK); + settings.m_ForceFiltering = Config::Get(Config::GFX_ENHANCE_FORCE_FILTERING); + settings.m_MaxAnisotropy = Config::Get(Config::GFX_ENHANCE_MAX_ANISOTROPY); + settings.m_ForceTrueColor = Config::Get(Config::GFX_ENHANCE_FORCE_TRUE_COLOR); + settings.m_DisableCopyFilter = Config::Get(Config::GFX_ENHANCE_DISABLE_COPY_FILTER); + settings.m_DisableFog = Config::Get(Config::GFX_DISABLE_FOG); + settings.m_ArbitraryMipmapDetection = Config::Get(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION); + settings.m_ArbitraryMipmapDetectionThreshold = + Config::Get(Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION_THRESHOLD); + settings.m_EnableGPUTextureDecoding = Config::Get(Config::GFX_ENABLE_GPU_TEXTURE_DECODING); + settings.m_StrictSettingsSync = m_strict_settings_sync_box->isChecked(); settings.m_SyncSaveData = m_sync_save_data_box->isChecked(); + // Unload GameINI to restore things to normal + Config::RemoveLayer(Config::LayerType::GlobalGame); + Config::RemoveLayer(Config::LayerType::LocalGame); + Settings::Instance().GetNetPlayServer()->SetNetSettings(settings); if (Settings::Instance().GetNetPlayServer()->RequestStartGame()) SetOptionsEnabled(false); @@ -354,6 +441,7 @@ void NetPlayDialog::show(std::string nickname, bool use_traversal) m_load_wii_box->setHidden(!is_hosting); m_sync_save_data_box->setHidden(!is_hosting); m_reduce_polling_rate_box->setHidden(!is_hosting); + m_strict_settings_sync_box->setHidden(!is_hosting); m_buffer_size_box->setHidden(!is_hosting); m_buffer_label->setHidden(!is_hosting); m_kick_button->setHidden(!is_hosting); @@ -564,6 +652,7 @@ void NetPlayDialog::SetOptionsEnabled(bool enabled) m_sync_save_data_box->setEnabled(enabled); m_assign_ports_button->setEnabled(enabled); m_reduce_polling_rate_box->setEnabled(enabled); + m_strict_settings_sync_box->setEnabled(enabled); } m_record_input_box->setEnabled(enabled); diff --git a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h index 1603bc40a8..f8f9926101 100644 --- a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h +++ b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h @@ -105,6 +105,7 @@ private: QCheckBox* m_sync_save_data_box; QCheckBox* m_record_input_box; QCheckBox* m_reduce_polling_rate_box; + QCheckBox* m_strict_settings_sync_box; QPushButton* m_quit_button; QSplitter* m_splitter; diff --git a/Source/Core/DolphinQt/QtUtils/FlowLayout.cpp b/Source/Core/DolphinQt/QtUtils/FlowLayout.cpp new file mode 100644 index 0000000000..b20d42f96e --- /dev/null +++ b/Source/Core/DolphinQt/QtUtils/FlowLayout.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "DolphinQt/QtUtils/FlowLayout.h" + +#include + +FlowLayout::FlowLayout(QWidget* parent, int margin, int h_spacing, int v_spacing) + : QLayout(parent), m_h_space(h_spacing), m_v_space(v_spacing) +{ + setContentsMargins(margin, margin, margin, margin); +} + +FlowLayout::FlowLayout(int margin, int h_spacing, int v_spacing) + : m_h_space(h_spacing), m_v_space(v_spacing) +{ + setContentsMargins(margin, margin, margin, margin); +} + +FlowLayout::~FlowLayout() +{ + QLayoutItem* item; + while ((item = takeAt(0))) + delete item; +} + +void FlowLayout::addItem(QLayoutItem* item) +{ + m_item_list.append(item); +} + +int FlowLayout::horizontalSpacing() const +{ + if (m_h_space >= 0) + { + return m_h_space; + } + else + { + return smartSpacing(QStyle::PM_LayoutHorizontalSpacing); + } +} + +int FlowLayout::verticalSpacing() const +{ + if (m_v_space >= 0) + { + return m_v_space; + } + else + { + return smartSpacing(QStyle::PM_LayoutVerticalSpacing); + } +} + +int FlowLayout::count() const +{ + return m_item_list.size(); +} + +QLayoutItem* FlowLayout::itemAt(int index) const +{ + return m_item_list.value(index); +} + +QLayoutItem* FlowLayout::takeAt(int index) +{ + if (index >= 0 && index < m_item_list.size()) + return m_item_list.takeAt(index); + else + return 0; +} + +Qt::Orientations FlowLayout::expandingDirections() const +{ + return 0; +} + +bool FlowLayout::hasHeightForWidth() const +{ + return true; +} + +int FlowLayout::heightForWidth(int width) const +{ + int height = doLayout(QRect(0, 0, width, 0), true); + return height; +} + +void FlowLayout::setGeometry(const QRect& rect) +{ + QLayout::setGeometry(rect); + doLayout(rect, false); +} + +QSize FlowLayout::sizeHint() const +{ + return minimumSize(); +} + +QSize FlowLayout::minimumSize() const +{ + QSize size; + for (const auto& item : m_item_list) + size = size.expandedTo(item->minimumSize()); + + size += QSize(2 * margin(), 2 * margin()); + return size; +} + +int FlowLayout::doLayout(const QRect& rect, bool testOnly) const +{ + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); + int x = effectiveRect.x(); + int y = effectiveRect.y(); + int lineHeight = 0; + + for (const auto& item : m_item_list) + { + QWidget* wid = item->widget(); + int spaceX = horizontalSpacing(); + if (spaceX == -1) + spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, + Qt::Horizontal); + int spaceY = verticalSpacing(); + if (spaceY == -1) + spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, + Qt::Vertical); + int nextX = x + item->sizeHint().width() + spaceX; + if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) + { + x = effectiveRect.x(); + y = y + lineHeight + spaceY; + nextX = x + item->sizeHint().width() + spaceX; + lineHeight = 0; + } + + if (!testOnly) + item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); + + x = nextX; + lineHeight = qMax(lineHeight, item->sizeHint().height()); + } + return y + lineHeight - rect.y() + bottom; +} + +int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const +{ + QObject* parent = this->parent(); + if (!parent) + { + return -1; + } + else if (parent->isWidgetType()) + { + QWidget* pw = static_cast(parent); + return pw->style()->pixelMetric(pm, 0, pw); + } + else + { + return static_cast(parent)->spacing(); + } +} diff --git a/Source/Core/DolphinQt/QtUtils/FlowLayout.h b/Source/Core/DolphinQt/QtUtils/FlowLayout.h new file mode 100644 index 0000000000..65955db960 --- /dev/null +++ b/Source/Core/DolphinQt/QtUtils/FlowLayout.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +#include +#include +#include + +class FlowLayout : public QLayout +{ +public: + explicit FlowLayout(QWidget* parent, int margin = -1, int h_spacing = -1, int v_spacing = -1); + explicit FlowLayout(int margin = -1, int h_spacing = -1, int v_spacing = -1); + ~FlowLayout(); + + void addItem(QLayoutItem* item) override; + int horizontalSpacing() const; + int verticalSpacing() const; + Qt::Orientations expandingDirections() const override; + bool hasHeightForWidth() const override; + int heightForWidth(int) const override; + int count() const override; + QLayoutItem* itemAt(int index) const override; + QSize minimumSize() const override; + void setGeometry(const QRect& rect) override; + QSize sizeHint() const override; + QLayoutItem* takeAt(int index) override; + +private: + int doLayout(const QRect& rect, bool testOnly) const; + int smartSpacing(QStyle::PixelMetric pm) const; + + QList m_item_list; + int m_h_space; + int m_v_space; +}; diff --git a/Source/Core/DolphinQt/Settings/AdvancedPane.cpp b/Source/Core/DolphinQt/Settings/AdvancedPane.cpp index 831bbb228f..3e70e385d7 100644 --- a/Source/Core/DolphinQt/Settings/AdvancedPane.cpp +++ b/Source/Core/DolphinQt/Settings/AdvancedPane.cpp @@ -13,6 +13,7 @@ #include #include +#include "Core/Config/MainSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/SystemTimers.h" @@ -101,13 +102,15 @@ void AdvancedPane::ConnectLayout() m_cpu_clock_override_checkbox->setChecked(SConfig::GetInstance().m_OCEnable); connect(m_cpu_clock_override_checkbox, &QCheckBox::toggled, [this](bool enable_clock_override) { SConfig::GetInstance().m_OCEnable = enable_clock_override; + Config::SetBaseOrCurrent(Config::MAIN_OVERCLOCK_ENABLE, enable_clock_override); Update(); }); connect(m_cpu_clock_override_slider, &QSlider::valueChanged, [this](int oc_factor) { // Vaguely exponential scaling? - SConfig::GetInstance().m_OCFactor = - std::exp2f((m_cpu_clock_override_slider->value() - 100.f) / 25.f); + const float factor = std::exp2f((m_cpu_clock_override_slider->value() - 100.f) / 25.f); + SConfig::GetInstance().m_OCFactor = factor; + Config::SetBaseOrCurrent(Config::MAIN_OVERCLOCK, factor); Update(); }); diff --git a/Source/Core/DolphinQt/Settings/AudioPane.cpp b/Source/Core/DolphinQt/Settings/AudioPane.cpp index 8a3f1fbcd6..512b06066e 100644 --- a/Source/Core/DolphinQt/Settings/AudioPane.cpp +++ b/Source/Core/DolphinQt/Settings/AudioPane.cpp @@ -19,6 +19,7 @@ #include "AudioCommon/AudioCommon.h" #include "AudioCommon/WASAPIStream.h" +#include "Core/Config/MainSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" @@ -222,7 +223,9 @@ void AudioPane::SaveSettings() // DSP SConfig::GetInstance().bDSPHLE = m_dsp_hle->isChecked(); + Config::SetBaseOrCurrent(Config::MAIN_DSP_HLE, m_dsp_hle->isChecked()); SConfig::GetInstance().m_DSPEnableJIT = m_dsp_lle->isChecked(); + Config::SetBaseOrCurrent(Config::MAIN_DSP_JIT, m_dsp_lle->isChecked()); // Backend const auto selection = diff --git a/Source/Core/DolphinQt/Settings/GameCubePane.cpp b/Source/Core/DolphinQt/Settings/GameCubePane.cpp index 4dff22c4bf..c9730e771a 100644 --- a/Source/Core/DolphinQt/Settings/GameCubePane.cpp +++ b/Source/Core/DolphinQt/Settings/GameCubePane.cpp @@ -341,8 +341,12 @@ void GameCubePane::SaveSettings() // IPL Settings params.bHLE_BS2 = m_skip_main_menu->isChecked(); + Config::SetBaseOrCurrent(Config::MAIN_SKIP_IPL, m_skip_main_menu->isChecked()); params.SelectedLanguage = m_language_combo->currentIndex(); + Config::SetBaseOrCurrent(Config::MAIN_GC_LANGUAGE, m_language_combo->currentIndex()); params.bOverrideGCLanguage = m_override_language_ntsc->isChecked(); + Config::SetBaseOrCurrent(Config::MAIN_OVERRIDE_GC_LANGUAGE, + m_override_language_ntsc->isChecked()); for (int i = 0; i < SLOT_COUNT; i++) { @@ -390,6 +394,18 @@ void GameCubePane::SaveSettings() } SConfig::GetInstance().m_EXIDevice[i] = dev; + switch (i) + { + case SLOT_A_INDEX: + Config::SetBaseOrCurrent(Config::MAIN_SLOT_A, dev); + break; + case SLOT_B_INDEX: + Config::SetBaseOrCurrent(Config::MAIN_SLOT_B, dev); + break; + case SLOT_SP1_INDEX: + Config::SetBaseOrCurrent(Config::MAIN_SERIAL_PORT_1, dev); + break; + } } LoadSettings(); } diff --git a/Source/Core/DolphinQt/Settings/GeneralPane.cpp b/Source/Core/DolphinQt/Settings/GeneralPane.cpp index 65b03b0260..3e9fe4a66c 100644 --- a/Source/Core/DolphinQt/Settings/GeneralPane.cpp +++ b/Source/Core/DolphinQt/Settings/GeneralPane.cpp @@ -19,6 +19,7 @@ #include #include "Core/Analytics.h" +#include "Core/Config/MainSettings.h" #include "Core/Config/UISettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" @@ -291,7 +292,9 @@ void GeneralPane::OnSaveConfig() Settings::Instance().SetAnalyticsEnabled(m_checkbox_enable_analytics->isChecked()); #endif settings.bCPUThread = m_checkbox_dualcore->isChecked(); + Config::SetBaseOrCurrent(Config::MAIN_CPU_THREAD, m_checkbox_dualcore->isChecked()); Settings::Instance().SetCheatsEnabled(m_checkbox_cheats->isChecked()); + Config::SetBaseOrCurrent(Config::MAIN_ENABLE_CHEATS, m_checkbox_cheats->isChecked()); settings.m_EmulationSpeed = m_combobox_speedlimit->currentIndex() * 0.1f; for (size_t i = 0; i < m_cpu_cores.size(); ++i) @@ -299,6 +302,7 @@ void GeneralPane::OnSaveConfig() if (m_cpu_cores[i]->isChecked()) { settings.cpu_core = PowerPC::AvailableCPUCores()[i]; + Config::SetBaseOrCurrent(Config::MAIN_CPU_CORE, PowerPC::AvailableCPUCores()[i]); break; } }