From 33167196d950ec5858cdaf327dd0a5d35a60dfb9 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sun, 4 Sep 2022 01:27:44 +0200 Subject: [PATCH] Wait for gfx pack init before loading shaders (#168) 2.0 introduced a race condition where the shader cache loading screen could load shaders before the graphic packs finished activating, potentially bypassing custom shaders. Also removed legacy GraphicPack interface (GraphicPack.cpp/.h) since it was only kept around for Cemuhook and removed u8string variant of cemuLog_force since it's no longer used --- src/Cafe/CafeSystem.cpp | 5 +- src/Cafe/GraphicPack/GraphicPack.cpp | 127 -------------------- src/Cafe/GraphicPack/GraphicPack.h | 4 - src/Cafe/GraphicPack/GraphicPack2.cpp | 119 +++++++++++++++++- src/Cafe/GraphicPack/GraphicPack2.h | 8 ++ src/Cafe/HW/Latte/Core/LatteShaderCache.cpp | 1 - src/Cafe/HW/Latte/Core/LatteTextureView.cpp | 1 - src/Cafe/HW/Latte/Core/LatteThread.cpp | 3 + src/Cemu/Logging/CemuLogging.h | 5 - src/gui/DownloadGraphicPacksWindow.cpp | 2 +- src/gui/GraphicPacksWindow2.cpp | 3 +- src/gui/MainWindow.cpp | 1 - src/main.cpp | 4 +- 13 files changed, 135 insertions(+), 148 deletions(-) delete mode 100644 src/Cafe/GraphicPack/GraphicPack.cpp delete mode 100644 src/Cafe/GraphicPack/GraphicPack.h diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index add9d1c6..bfa5d822 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -10,7 +10,7 @@ #include "config/ActiveSettings.h" #include "Cafe/TitleList/GameInfo.h" #include "util/helpers/SystemException.h" -#include "Cafe/GraphicPack/GraphicPack.h" +#include "Cafe/GraphicPack/GraphicPack2.h" #include "input/InputManager.h" @@ -399,7 +399,7 @@ void cemu_initForGame() debugger_handleEntryBreakpoint(_entryPoint); // load graphic packs forceLog_printf("------- Activate graphic packs -------"); - graphicPack_activateForCurrentTitle(CafeSystem::GetForegroundTitleId()); + GraphicPack2::ActivateForCurrentTitle(); // print audio log IAudioAPI::PrintLogging(); // everything initialized @@ -766,6 +766,7 @@ namespace CafeSystem iosu::act::Stop(); iosu::mcp::Shutdown(); iosu::fsa::Shutdown(); + GraphicPack2::Reset(); UnmountCurrentTitle(); sSystemRunning = false; } diff --git a/src/Cafe/GraphicPack/GraphicPack.cpp b/src/Cafe/GraphicPack/GraphicPack.cpp deleted file mode 100644 index c41ca944..00000000 --- a/src/Cafe/GraphicPack/GraphicPack.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "gui/wxgui.h" -#include "GraphicPack.h" - -#include "config/ActiveSettings.h" -#include "Cafe/GraphicPack/GraphicPack2.h" - -/* - * Loads the graphic pack if the titleId is referenced in rules.ini - */ -void graphicPack_loadGraphicPack(wchar_t* graphicPackPath) -{ - fs::path rulesPath = fs::path(graphicPackPath); - rulesPath.append("rules.txt"); - std::unique_ptr fs_rules(FileStream::openFile2(rulesPath)); - if (!fs_rules) - return; - std::vector rulesData; - fs_rules->extract(rulesData); - IniParser iniParser(rulesData, rulesPath.string()); - - if (!iniParser.NextSection()) - { - cemuLog_force(u8"{}: Does not contain any sections", rulesPath.generic_u8string()); - return; - } - if (!boost::iequals(iniParser.GetCurrentSectionName(), "Definition")) - { - cemuLog_force(u8"{}: [Definition] must be the first section", rulesPath.generic_u8string()); - return; - } - - - auto option_version = iniParser.FindOption("version"); - if (option_version) - { - sint32 versionNum = -1; - auto [ptr, ec] = std::from_chars(option_version->data(), option_version->data() + option_version->size(), versionNum); - if (ec != std::errc{}) - { - cemuLog_force(u8"{}: Unable to parse version", rulesPath.generic_u8string()); - return; - } - - if (versionNum > GP_LEGACY_VERSION) - { - GraphicPack2::LoadGraphicPack(rulesPath.generic_wstring(), iniParser); - return; - } - } - cemuLog_force(u8"{}: Outdated graphic pack", rulesPath.generic_u8string()); -} - -void graphicPack_scanForGFXPackFolders(const fs::path& currentPath, std::wstring& relativePath) -{ - // check if this directory has rules txt - fs::path rulesPath = fs::path(currentPath); - rulesPath.append("rules.txt"); - - if (fs::exists(rulesPath) && relativePath.length() != 0) - { - graphicPack_loadGraphicPack((wchar_t*)currentPath.generic_wstring().c_str()); - return; // when a rules.txt file is found stop recursion - } - - if (!fs::exists(currentPath)) - return; - - for (auto& p : fs::directory_iterator(currentPath)) - { - auto& path = p.path(); - if (fs::is_directory(p.status())) - { - // dir - sint32 origSize = relativePath.size(); - relativePath.append(L"/"); - relativePath.append(path.filename().generic_wstring()); - graphicPack_scanForGFXPackFolders(path, relativePath); - relativePath.resize(origSize); - } - } -} - -void graphicPack_loadAll() -{ - // recursively iterate all directories in graphicPacks/ folder - std::wstring graphicPackRelativePath; - graphicPack_scanForGFXPackFolders(ActiveSettings::GetPath("graphicPacks/"), graphicPackRelativePath); -} - -void graphicPack_activateForCurrentTitle(uint64 titleId) -{ - // activate graphic packs - for (const auto& gp : GraphicPack2::GetGraphicPacks()) - { - if (!gp->IsEnabled()) - continue; - - if (!gp->ContainsTitleId(titleId)) - continue; - - if(GraphicPack2::ActivateGraphicPack(gp)) - { - if (gp->GetPresets().empty()) - { - forceLog_printf("Activate graphic pack: %s", gp->GetPath().c_str()); - } - else - { - std::string logLine; - logLine.assign(fmt::format("Activate graphic pack: {} [Presets: ", gp->GetPath())); - bool isFirst = true; - for (auto& itr : gp->GetPresets()) - { - if(!itr->active) - continue; - if (isFirst) - isFirst = false; - else - logLine.append(","); - logLine.append(itr->name); - } - logLine.append("]"); - cemuLog_log(LogType::Force, logLine); - } - } - } -} \ No newline at end of file diff --git a/src/Cafe/GraphicPack/GraphicPack.h b/src/Cafe/GraphicPack/GraphicPack.h deleted file mode 100644 index 0a79ef4b..00000000 --- a/src/Cafe/GraphicPack/GraphicPack.h +++ /dev/null @@ -1,4 +0,0 @@ -#define GP_LEGACY_VERSION (2) - -void graphicPack_loadAll(); -void graphicPack_activateForCurrentTitle(uint64 titleId); \ No newline at end of file diff --git a/src/Cafe/GraphicPack/GraphicPack2.cpp b/src/Cafe/GraphicPack/GraphicPack2.cpp index 62d47388..41e33a19 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2.cpp @@ -1,6 +1,6 @@ #include "Cafe/GraphicPack/GraphicPack2.h" -#include "GraphicPack.h" #include "config/CemuConfig.h" +#include "config/ActiveSettings.h" #include "openssl/sha.h" #include "Cafe/HW/Latte/Renderer/RendererOuputShader.h" #include "Cafe/Filesystem/fsc.h" @@ -14,6 +14,69 @@ std::vector GraphicPack2::s_graphic_packs; std::vector GraphicPack2::s_active_graphic_packs; +std::atomic_bool GraphicPack2::s_isReady; + +#define GP_LEGACY_VERSION (2) + +void GraphicPack2::LoadGraphicPack(fs::path graphicPackPath) +{ + fs::path rulesPath = graphicPackPath; + rulesPath.append("rules.txt"); + std::unique_ptr fs_rules(FileStream::openFile2(rulesPath)); + if (!fs_rules) + return; + std::vector rulesData; + fs_rules->extract(rulesData); + IniParser iniParser(rulesData, rulesPath.string()); + + if (!iniParser.NextSection()) + { + cemuLog_force("{}: Does not contain any sections", _utf8Wrapper(rulesPath)); + return; + } + if (!boost::iequals(iniParser.GetCurrentSectionName(), "Definition")) + { + cemuLog_force("{}: [Definition] must be the first section", _utf8Wrapper(rulesPath)); + return; + } + + auto option_version = iniParser.FindOption("version"); + if (option_version) + { + sint32 versionNum = -1; + auto [ptr, ec] = std::from_chars(option_version->data(), option_version->data() + option_version->size(), versionNum); + if (ec != std::errc{}) + { + cemuLog_force("{}: Unable to parse version", _utf8Wrapper(rulesPath)); + return; + } + + if (versionNum > GP_LEGACY_VERSION) + { + GraphicPack2::LoadGraphicPack(rulesPath.generic_wstring(), iniParser); + return; + } + } + cemuLog_force("{}: Outdated graphic pack", _utf8Wrapper(rulesPath)); +} + +void GraphicPack2::LoadAll() +{ + std::error_code ec; + fs::path basePath = ActiveSettings::GetPath("graphicPacks"); + for (fs::recursive_directory_iterator it(basePath, ec); it != end(it); ++it) + { + if (!it->is_directory(ec)) + continue; + fs::path gfxPackPath = it->path(); + if (fs::exists(gfxPackPath / "rules.txt", ec)) + { + LoadGraphicPack(gfxPackPath); + it.disable_recursion_pending(); // dont recurse deeper in a gfx pack directory + continue; + } + } +} bool GraphicPack2::LoadGraphicPack(const std::wstring& filename, IniParser& rules) { @@ -60,7 +123,6 @@ bool GraphicPack2::LoadGraphicPack(const std::wstring& filename, IniParser& rule { return false; } - } bool GraphicPack2::ActivateGraphicPack(const std::shared_ptr& graphic_pack) @@ -94,12 +156,65 @@ bool GraphicPack2::DeactivateGraphicPack(const std::shared_ptr& gr return true; } +void GraphicPack2::ActivateForCurrentTitle() +{ + uint64 titleId = CafeSystem::GetForegroundTitleId(); + // activate graphic packs + for (const auto& gp : GraphicPack2::GetGraphicPacks()) + { + if (!gp->IsEnabled()) + continue; + + if (!gp->ContainsTitleId(titleId)) + continue; + + if (GraphicPack2::ActivateGraphicPack(gp)) + { + if (gp->GetPresets().empty()) + { + forceLog_printf("Activate graphic pack: %s", gp->GetPath().c_str()); + } + else + { + std::string logLine; + logLine.assign(fmt::format("Activate graphic pack: {} [Presets: ", gp->GetPath())); + bool isFirst = true; + for (auto& itr : gp->GetPresets()) + { + if (!itr->active) + continue; + if (isFirst) + isFirst = false; + else + logLine.append(","); + logLine.append(itr->name); + } + logLine.append("]"); + cemuLog_log(LogType::Force, logLine); + } + } + } + s_isReady = true; +} + +void GraphicPack2::Reset() +{ + s_active_graphic_packs.clear(); + s_isReady = false; +} + void GraphicPack2::ClearGraphicPacks() { s_graphic_packs.clear(); s_active_graphic_packs.clear(); } +void GraphicPack2::WaitUntilReady() +{ + while (!s_isReady) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); +} + GraphicPack2::GraphicPack2(std::wstring filename) : m_filename(std::move(filename)) { diff --git a/src/Cafe/GraphicPack/GraphicPack2.h b/src/Cafe/GraphicPack/GraphicPack2.h index 65d25f3f..4c18b5c6 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.h +++ b/src/Cafe/GraphicPack/GraphicPack2.h @@ -159,18 +159,26 @@ public: LatteTextureView::MagFilter GetDownscalingMagFilter() const { return m_output_settings.downscale_filter; } // static methods + static void LoadAll(); + static const std::vector>& GetGraphicPacks() { return s_graphic_packs; } static const std::vector>& GetActiveGraphicPacks() { return s_active_graphic_packs; } + static void LoadGraphicPack(fs::path graphicPackPath); static bool LoadGraphicPack(const std::wstring& filename, class IniParser& rules); static bool ActivateGraphicPack(const std::shared_ptr& graphic_pack); static bool DeactivateGraphicPack(const std::shared_ptr& graphic_pack); static void ClearGraphicPacks(); + static void WaitUntilReady(); // wait until all graphic packs finished activation + + static void ActivateForCurrentTitle(); + static void Reset(); private: bool Activate(); bool Deactivate(); static std::vector> s_graphic_packs; static std::vector> s_active_graphic_packs; + static std::atomic_bool s_isReady; template void FillPresetConstants(TExpressionParser& parser) const diff --git a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp index fe1388f0..bcdaffa2 100644 --- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp @@ -5,7 +5,6 @@ #include "Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h" #include "Cafe/HW/Latte/Core/FetchShader.h" #include "Cemu/FileCache/FileCache.h" -#include "Cafe/GraphicPack/GraphicPack.h" #include "Cafe/GameProfile/GameProfile.h" #include "gui/guiWrapper.h" diff --git a/src/Cafe/HW/Latte/Core/LatteTextureView.cpp b/src/Cafe/HW/Latte/Core/LatteTextureView.cpp index 8cfa11e9..cac5bcce 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureView.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTextureView.cpp @@ -1,7 +1,6 @@ #include "Cafe/HW/Latte/Core/LatteTexture.h" #include "Cafe/HW/Latte/Core/LatteTextureView.h" #include "Cafe/HW/Latte/Core/Latte.h" -#include "Cafe/GraphicPack/GraphicPack.h" #include "Cafe/GraphicPack/GraphicPack2.h" LatteTextureView::LatteTextureView(LatteTexture* texture, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, bool registerView) diff --git a/src/Cafe/HW/Latte/Core/LatteThread.cpp b/src/Cafe/HW/Latte/Core/LatteThread.cpp index 9b3dfe8a..d9b8ab94 100644 --- a/src/Cafe/HW/Latte/Core/LatteThread.cpp +++ b/src/Cafe/HW/Latte/Core/LatteThread.cpp @@ -5,6 +5,7 @@ #include "Cafe/HW/Latte/Core/LatteShader.h" #include "Cafe/HW/Latte/Core/LatteAsyncCommands.h" #include "Cafe/GameProfile/GameProfile.h" +#include "Cafe/GraphicPack/GraphicPack2.h" #include "gui/guiWrapper.h" #include "Cafe/HW/Latte/Core/LatteBufferCache.h" @@ -188,6 +189,8 @@ int Latte_ThreadEntry() g_renderer->DrawEmptyFrame(true); + // before doing anything with game specific shaders, we need to wait for graphic packs to finish loading + GraphicPack2::WaitUntilReady(); // load/init shader cache file LatteShaderCache_load(); diff --git a/src/Cemu/Logging/CemuLogging.h b/src/Cemu/Logging/CemuLogging.h index 021055d4..4238b638 100644 --- a/src/Cemu/Logging/CemuLogging.h +++ b/src/Cemu/Logging/CemuLogging.h @@ -119,11 +119,6 @@ inline bool cemuLog_force(std::string_view msg) return cemuLog_log(LogType::Force, msg); } -inline bool cemuLog_force(std::u8string_view msg) -{ - return cemuLog_log(LogType::Force, msg); -} - inline bool cemuLog_force(std::wstring_view msg) { return cemuLog_log(LogType::Force, msg); diff --git a/src/gui/DownloadGraphicPacksWindow.cpp b/src/gui/DownloadGraphicPacksWindow.cpp index 35f25225..28e5bf6b 100644 --- a/src/gui/DownloadGraphicPacksWindow.cpp +++ b/src/gui/DownloadGraphicPacksWindow.cpp @@ -92,7 +92,7 @@ void deleteDownloadedGraphicPacks() { const auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks"); std::error_code er; - if (!fs::exists(path)) + if (!fs::exists(path, er)) return; try { diff --git a/src/gui/GraphicPacksWindow2.cpp b/src/gui/GraphicPacksWindow2.cpp index a830cb72..3759580e 100644 --- a/src/gui/GraphicPacksWindow2.cpp +++ b/src/gui/GraphicPacksWindow2.cpp @@ -3,7 +3,6 @@ #include "gui/DownloadGraphicPacksWindow.h" #include "Cafe/GraphicPack/GraphicPack2.h" #include "config/CemuConfig.h" -#include "Cafe/GraphicPack/GraphicPack.h" #include "Cafe/HW/Latte/Core/LatteAsyncCommands.h" @@ -184,7 +183,7 @@ void GraphicPacksWindow2::ExpandChildren(const std::vector& ids, s void GraphicPacksWindow2::RefreshGraphicPacks() { GraphicPack2::ClearGraphicPacks(); - graphicPack_loadAll(); + GraphicPack2::LoadAll(); } GraphicPacksWindow2::GraphicPacksWindow2(wxWindow* parent, uint64_t title_id_filter) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index ff5be4f2..b23a5ca7 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -34,7 +34,6 @@ #include "gui/TitleManager.h" #include "Cafe/CafeSystem.h" -#include "Cafe/GraphicPack/GraphicPack.h" #include "Cafe/TitleList/GameInfo.h" #include diff --git a/src/main.cpp b/src/main.cpp index eac51f1f..f94b2761 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,7 +6,7 @@ #include "Cafe/OS/RPL/rpl_symbol_storage.h" #include "Cafe/OS/libs/gx2/GX2.h" #include "Cafe/GameProfile/GameProfile.h" -#include "Cafe/GraphicPack/GraphicPack.h" +#include "Cafe/GraphicPack/GraphicPack2.h" #include "config/CemuConfig.h" #include "gui/CemuApp.h" #include "Cafe/HW/Latte/Core/LatteOverlay.h" @@ -221,7 +221,7 @@ void mainEmulatorCommonInit() // static initialization IAudioAPI::InitializeStatic(); // load graphic packs (must happen before config is loaded) - graphicPack_loadAll(); + GraphicPack2::LoadAll(); // initialize file system fsc_init(); }