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
This commit is contained in:
Exzap 2022-09-04 01:27:44 +02:00 committed by GitHub
parent 8dd1688ca7
commit 33167196d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 135 additions and 148 deletions

View File

@ -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;
}

View File

@ -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<FileStream> fs_rules(FileStream::openFile2(rulesPath));
if (!fs_rules)
return;
std::vector<uint8> 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);
}
}
}
}

View File

@ -1,4 +0,0 @@
#define GP_LEGACY_VERSION (2)
void graphicPack_loadAll();
void graphicPack_activateForCurrentTitle(uint64 titleId);

View File

@ -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<GraphicPackPtr> GraphicPack2::s_graphic_packs;
std::vector<GraphicPackPtr> 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<FileStream> fs_rules(FileStream::openFile2(rulesPath));
if (!fs_rules)
return;
std::vector<uint8> 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<GraphicPack2>& graphic_pack)
@ -94,12 +156,65 @@ bool GraphicPack2::DeactivateGraphicPack(const std::shared_ptr<GraphicPack2>& 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))
{

View File

@ -159,18 +159,26 @@ public:
LatteTextureView::MagFilter GetDownscalingMagFilter() const { return m_output_settings.downscale_filter; }
// static methods
static void LoadAll();
static const std::vector<std::shared_ptr<GraphicPack2>>& GetGraphicPacks() { return s_graphic_packs; }
static const std::vector<std::shared_ptr<GraphicPack2>>& 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<GraphicPack2>& graphic_pack);
static bool DeactivateGraphicPack(const std::shared_ptr<GraphicPack2>& 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<std::shared_ptr<GraphicPack2>> s_graphic_packs;
static std::vector<std::shared_ptr<GraphicPack2>> s_active_graphic_packs;
static std::atomic_bool s_isReady;
template<typename TType>
void FillPresetConstants(TExpressionParser<TType>& parser) const

View File

@ -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"

View File

@ -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)

View File

@ -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();

View File

@ -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);

View File

@ -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
{

View File

@ -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<wxTreeItemId>& ids, s
void GraphicPacksWindow2::RefreshGraphicPacks()
{
GraphicPack2::ClearGraphicPacks();
graphicPack_loadAll();
GraphicPack2::LoadAll();
}
GraphicPacksWindow2::GraphicPacksWindow2(wxWindow* parent, uint64_t title_id_filter)

View File

@ -34,7 +34,6 @@
#include "gui/TitleManager.h"
#include "Cafe/CafeSystem.h"
#include "Cafe/GraphicPack/GraphicPack.h"
#include "Cafe/TitleList/GameInfo.h"
#include <boost/algorithm/string.hpp>

View File

@ -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();
}