diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index 3d06281e0..30dab1d43 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -530,7 +530,8 @@ namespace CafeSystem { // entries in this list are ordered by initialization order. Shutdown in reverse order iosu::kernel::GetModule(), - iosu::fpd::GetModule() + iosu::fpd::GetModule(), + iosu::pdm::GetModule(), }; // initialize all subsystems which are persistent and don't depend on a game running @@ -571,7 +572,6 @@ namespace CafeSystem iosu::iosuAcp_init(); iosu::boss_init(); iosu::nim::Initialize(); - iosu::pdm::Initialize(); iosu::odm::Initialize(); // init Cafe OS avm::Initialize(); @@ -840,7 +840,6 @@ namespace CafeSystem coreinit::OSSchedulerBegin(3); else coreinit::OSSchedulerBegin(1); - iosu::pdm::StartTrackingTime(GetForegroundTitleId()); } void LaunchForegroundTitle() @@ -970,8 +969,6 @@ namespace CafeSystem RPLLoader_ResetState(); for(auto it = s_iosuModules.rbegin(); it != s_iosuModules.rend(); ++it) (*it)->TitleStop(); - // stop time tracking - iosu::pdm::Stop(); // reset Cemu subsystems PPCRecompiler_Shutdown(); GraphicPack2::Reset(); diff --git a/src/Cafe/GameProfile/GameProfile.cpp b/src/Cafe/GameProfile/GameProfile.cpp index d068237e3..ee92107a7 100644 --- a/src/Cafe/GameProfile/GameProfile.cpp +++ b/src/Cafe/GameProfile/GameProfile.cpp @@ -209,7 +209,7 @@ bool GameProfile::Load(uint64_t title_id) m_gameName = std::string(game_name.begin(), game_name.end()); trim(m_gameName.value()); } - IniParser iniParser(*profileContents, gameProfilePath.string()); + IniParser iniParser(*profileContents, _pathToUtf8(gameProfilePath)); // parse ini while (iniParser.NextSection()) { diff --git a/src/Cafe/GraphicPack/GraphicPack2.cpp b/src/Cafe/GraphicPack/GraphicPack2.cpp index 72e301c4d..365e6e3ea 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2.cpp @@ -28,7 +28,7 @@ void GraphicPack2::LoadGraphicPack(fs::path graphicPackPath) return; std::vector rulesData; fs_rules->extract(rulesData); - IniParser iniParser(rulesData, rulesPath.string()); + IniParser iniParser(rulesData, _pathToUtf8(rulesPath)); if (!iniParser.NextSection()) { @@ -51,10 +51,9 @@ void GraphicPack2::LoadGraphicPack(fs::path graphicPackPath) cemuLog_log(LogType::Force, "{}: Unable to parse version", _pathToUtf8(rulesPath)); return; } - if (versionNum > GP_LEGACY_VERSION) { - GraphicPack2::LoadGraphicPack(_pathToUtf8(rulesPath), iniParser); + GraphicPack2::LoadGraphicPack(rulesPath, iniParser); return; } } @@ -79,22 +78,22 @@ void GraphicPack2::LoadAll() } } -bool GraphicPack2::LoadGraphicPack(const std::string& filename, IniParser& rules) +bool GraphicPack2::LoadGraphicPack(const fs::path& rulesPath, IniParser& rules) { try { - auto gp = std::make_shared(filename, rules); + auto gp = std::make_shared(rulesPath, rules); // check if enabled and preset set const auto& config_entries = g_config.data().graphic_pack_entries; // legacy absolute path checking for not breaking compatibility - auto file = gp->GetFilename2(); + auto file = gp->GetRulesPath(); auto it = config_entries.find(file.lexically_normal()); if (it == config_entries.cend()) { // check for relative path - it = config_entries.find(MakeRelativePath(ActiveSettings::GetUserDataPath(), gp->GetFilename2()).lexically_normal()); + it = config_entries.find(_utf8ToPath(gp->GetNormalizedPathString())); } if (it != config_entries.cend()) @@ -145,7 +144,7 @@ bool GraphicPack2::DeactivateGraphicPack(const std::shared_ptr& gr const auto it = std::find_if(s_active_graphic_packs.begin(), s_active_graphic_packs.end(), [graphic_pack](const GraphicPackPtr& gp) { - return gp->GetFilename() == graphic_pack->GetFilename(); + return gp->GetNormalizedPathString() == graphic_pack->GetNormalizedPathString(); } ); @@ -173,12 +172,12 @@ void GraphicPack2::ActivateForCurrentTitle() { if (gp->GetPresets().empty()) { - cemuLog_log(LogType::Force, "Activate graphic pack: {}", gp->GetPath()); + cemuLog_log(LogType::Force, "Activate graphic pack: {}", gp->GetVirtualPath()); } else { std::string logLine; - logLine.assign(fmt::format("Activate graphic pack: {} [Presets: ", gp->GetPath())); + logLine.assign(fmt::format("Activate graphic pack: {} [Presets: ", gp->GetVirtualPath())); bool isFirst = true; for (auto& itr : gp->GetPresets()) { @@ -249,8 +248,8 @@ std::unordered_map GraphicPack2::ParsePres return vars; } -GraphicPack2::GraphicPack2(std::string filename, IniParser& rules) - : m_filename(std::move(filename)) +GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules) + : m_rulesPath(std::move(rulesPath)) { // we're already in [Definition] auto option_version = rules.FindOption("version"); @@ -259,7 +258,7 @@ GraphicPack2::GraphicPack2(std::string filename, IniParser& rules) m_version = StringHelpers::ToInt(*option_version, -1); if (m_version < 0) { - cemuLog_log(LogType::Force, "{}: Invalid version", m_filename); + cemuLog_log(LogType::Force, "{}: Invalid version", _pathToUtf8(m_rulesPath)); throw std::exception(); } @@ -305,7 +304,7 @@ GraphicPack2::GraphicPack2(std::string filename, IniParser& rules) cemuLog_log(LogType::Force, "[Definition] section from '{}' graphic pack must contain option: path", gp_name_log.has_value() ? *gp_name_log : "Unknown"); throw std::exception(); } - m_path = *option_path; + m_virtualPath = *option_path; auto option_gp_name = rules.FindOption("name"); if (option_gp_name) @@ -508,6 +507,11 @@ bool GraphicPack2::Reload() return Activate(); } +std::string GraphicPack2::GetNormalizedPathString() const +{ + return _pathToUtf8(MakeRelativePath(ActiveSettings::GetUserDataPath(), GetRulesPath()).lexically_normal()); +} + bool GraphicPack2::ContainsTitleId(uint64_t title_id) const { const auto it = std::find_if(m_title_ids.begin(), m_title_ids.end(), [title_id](uint64 id) { return id == title_id; }); @@ -650,7 +654,7 @@ bool GraphicPack2::SetActivePreset(std::string_view category, std::string_view n void GraphicPack2::LoadShaders() { - fs::path path(m_filename); + fs::path path = GetRulesPath(); for (auto& it : fs::directory_iterator(path.remove_filename())) { if (!is_regular_file(it)) @@ -676,7 +680,7 @@ void GraphicPack2::LoadShaders() { std::ifstream file(p); if (!file.is_open()) - throw std::runtime_error(fmt::format("can't open graphic pack file: {}", p.filename().string()).c_str()); + throw std::runtime_error(fmt::format("can't open graphic pack file: {}", _pathToUtf8(p.filename()))); file.seekg(0, std::ios::end); m_output_shader_source.reserve(file.tellg()); @@ -689,7 +693,7 @@ void GraphicPack2::LoadShaders() { std::ifstream file(p); if (!file.is_open()) - throw std::runtime_error(fmt::format("can't open graphic pack file: {}", p.filename().string()).c_str()); + throw std::runtime_error(fmt::format("can't open graphic pack file: {}", _pathToUtf8(p.filename()))); file.seekg(0, std::ios::end); m_upscaling_shader_source.reserve(file.tellg()); @@ -702,7 +706,7 @@ void GraphicPack2::LoadShaders() { std::ifstream file(p); if (!file.is_open()) - throw std::runtime_error(fmt::format("can't open graphic pack file: {}", p.filename().string()).c_str()); + throw std::runtime_error(fmt::format("can't open graphic pack file: {}", _pathToUtf8(p.filename()))); file.seekg(0, std::ios::end); m_downscaling_shader_source.reserve(file.tellg()); @@ -805,7 +809,7 @@ void GraphicPack2::AddConstantsForCurrentPreset(ExpressionParser& ep) } } -void GraphicPack2::_iterateReplacedFiles(const fs::path& currentPath, std::wstring& internalPath, bool isAOC) +void GraphicPack2::_iterateReplacedFiles(const fs::path& currentPath, bool isAOC) { uint64 currentTitleId = CafeSystem::GetForegroundTitleId(); uint64 aocTitleId = (currentTitleId & 0xFFFFFFFFull) | 0x0005000c00000000ull; @@ -833,7 +837,7 @@ void GraphicPack2::LoadReplacedFiles() return; m_patchedFilesLoaded = true; - fs::path gfxPackPath = _utf8ToPath(m_filename); + fs::path gfxPackPath = GetRulesPath(); gfxPackPath = gfxPackPath.remove_filename(); // /content/ @@ -843,10 +847,9 @@ void GraphicPack2::LoadReplacedFiles() std::error_code ec; if (fs::exists(contentPath, ec)) { - std::wstring internalPath(L"/vol/content/"); // setup redirections fscDeviceRedirect_map(); - _iterateReplacedFiles(contentPath, internalPath, false); + _iterateReplacedFiles(contentPath, false); } // /aoc/ fs::path aocPath(gfxPackPath); @@ -857,13 +860,9 @@ void GraphicPack2::LoadReplacedFiles() uint64 aocTitleId = CafeSystem::GetForegroundTitleId(); aocTitleId = aocTitleId & 0xFFFFFFFFULL; aocTitleId |= 0x0005000c00000000ULL; - wchar_t internalAocPath[128]; - swprintf(internalAocPath, sizeof(internalAocPath)/sizeof(wchar_t), L"/aoc/%016llx/", aocTitleId); - - std::wstring internalPath(internalAocPath); // setup redirections fscDeviceRedirect_map(); - _iterateReplacedFiles(aocPath, internalPath, true); + _iterateReplacedFiles(aocPath, true); } } @@ -886,14 +885,14 @@ bool GraphicPack2::Activate() return false; } - FileStream* fs_rules = FileStream::openFile2(_utf8ToPath(m_filename)); + FileStream* fs_rules = FileStream::openFile2(m_rulesPath); if (!fs_rules) return false; std::vector rulesData; fs_rules->extract(rulesData); delete fs_rules; - IniParser rules({ (char*)rulesData.data(), rulesData.size()}, m_filename); + IniParser rules({ (char*)rulesData.data(), rulesData.size()}, GetNormalizedPathString()); // load rules try @@ -947,7 +946,7 @@ bool GraphicPack2::Activate() else if (anisotropyValue == 16) rule.overwrite_settings.anistropic_value = 4; else - cemuLog_log(LogType::Force, "Invalid value {} for overwriteAnisotropy in graphic pack {}. Only the values 1, 2, 4, 8 or 16 are allowed.", anisotropyValue, m_filename); + cemuLog_log(LogType::Force, "Invalid value {} for overwriteAnisotropy in graphic pack {}. Only the values 1, 2, 4, 8 or 16 are allowed.", anisotropyValue, GetNormalizedPathString()); } m_texture_rules.emplace_back(rule); } @@ -992,11 +991,11 @@ bool GraphicPack2::Activate() if (LatteTiming_getCustomVsyncFrequency(globalCustomVsyncFreq)) { if (customVsyncFreq != globalCustomVsyncFreq) - cemuLog_log(LogType::Force, "rules.txt error: Mismatching vsync frequency {} in graphic pack \'{}\'", customVsyncFreq, GetPath()); + cemuLog_log(LogType::Force, "rules.txt error: Mismatching vsync frequency {} in graphic pack \'{}\'", customVsyncFreq, GetVirtualPath()); } else { - cemuLog_log(LogType::Force, "Set vsync frequency to {} (graphic pack {})", customVsyncFreq, GetPath()); + cemuLog_log(LogType::Force, "Set vsync frequency to {} (graphic pack {})", customVsyncFreq, GetVirtualPath()); LatteTiming_setCustomVsyncFrequency(customVsyncFreq); } } diff --git a/src/Cafe/GraphicPack/GraphicPack2.h b/src/Cafe/GraphicPack/GraphicPack2.h index 6396ecc75..6b07cce99 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.h +++ b/src/Cafe/GraphicPack/GraphicPack2.h @@ -97,20 +97,20 @@ class GraphicPack2 }; using PresetPtr = std::shared_ptr; - GraphicPack2(std::string filename, IniParser& rules); + GraphicPack2(fs::path rulesPath, IniParser& rules); bool IsEnabled() const { return m_enabled; } bool IsActivated() const { return m_activated; } sint32 GetVersion() const { return m_version; } - const std::string& GetFilename() const { return m_filename; } - const fs::path GetFilename2() const { return fs::path(m_filename); } + const fs::path GetRulesPath() const { return m_rulesPath; } + std::string GetNormalizedPathString() const; bool RequiresRestart(bool changeEnableState, bool changePreset); bool Reload(); bool HasName() const { return !m_name.empty(); } - const std::string& GetName() const { return m_name.empty() ? m_path : m_name; } - const std::string& GetPath() const { return m_path; } + const std::string& GetName() const { return m_name.empty() ? m_virtualPath : m_name; } + const std::string& GetVirtualPath() const { return m_virtualPath; } // returns the path in the gfx tree hierarchy const std::string& GetDescription() const { return m_description; } bool IsDefaultEnabled() const { return m_default_enabled; } @@ -164,7 +164,7 @@ class GraphicPack2 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::string& filename, class IniParser& rules); + static bool LoadGraphicPack(const fs::path& rulesPath, class IniParser& rules); static bool ActivateGraphicPack(const std::shared_ptr& graphic_pack); static bool DeactivateGraphicPack(const std::shared_ptr& graphic_pack); static void ClearGraphicPacks(); @@ -208,11 +208,11 @@ class GraphicPack2 parser.TryAddConstant(var.first, (TType)var.second.second); } - std::string m_filename; + fs::path m_rulesPath; sint32 m_version; std::string m_name; - std::string m_path; + std::string m_virtualPath; std::string m_description; bool m_default_enabled = false; @@ -257,7 +257,7 @@ class GraphicPack2 CustomShader LoadShader(const fs::path& path, uint64 shader_base_hash, uint64 shader_aux_hash, GP_SHADER_TYPE shader_type) const; void ApplyShaderPresets(std::string& shader_source) const; void LoadReplacedFiles(); - void _iterateReplacedFiles(const fs::path& currentPath, std::wstring& internalPath, bool isAOC); + void _iterateReplacedFiles(const fs::path& currentPath, bool isAOC); // ram mappings std::vector> m_ramMappings; diff --git a/src/Cafe/GraphicPack/GraphicPack2Patches.cpp b/src/Cafe/GraphicPack/GraphicPack2Patches.cpp index 5c79630c1..2c0674847 100644 --- a/src/Cafe/GraphicPack/GraphicPack2Patches.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2Patches.cpp @@ -71,19 +71,8 @@ void PatchErrorHandler::showStageErrorMessageBox() // returns true if at least one file was found even if it could not be successfully parsed bool GraphicPack2::LoadCemuPatches() { - // todo - once we have updated to C++20 we can replace these with the new std::string functions - auto startsWith = [](const std::wstring& str, const std::wstring& prefix) - { - return str.size() >= prefix.size() && 0 == str.compare(0, prefix.size(), prefix); - }; - - auto endsWith = [](const std::wstring& str, const std::wstring& suffix) - { - return str.size() >= suffix.size() && 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix); - }; - bool foundPatches = false; - fs::path path(_utf8ToPath(m_filename)); + fs::path path(m_rulesPath); path.remove_filename(); for (auto& p : fs::directory_iterator(path)) { @@ -129,7 +118,7 @@ void GraphicPack2::LoadPatchFiles() if (LoadCemuPatches()) return; // exit if at least one Cemu style patch file was found // fall back to Cemuhook patches.txt to guarantee backward compatibility - fs::path path(_utf8ToPath(m_filename)); + fs::path path(m_rulesPath); path.remove_filename(); path.append("patches.txt"); FileStream* patchFile = FileStream::openFile2(path); diff --git a/src/Cafe/GraphicPack/GraphicPack2PatchesParser.cpp b/src/Cafe/GraphicPack/GraphicPack2PatchesParser.cpp index d011a10b5..05f8c6966 100644 --- a/src/Cafe/GraphicPack/GraphicPack2PatchesParser.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2PatchesParser.cpp @@ -25,7 +25,7 @@ sint32 GraphicPack2::GetLengthWithoutComment(const char* str, size_t length) void GraphicPack2::LogPatchesSyntaxError(sint32 lineNumber, std::string_view errorMsg) { - cemuLog_log(LogType::Force, "Syntax error while parsing patch for graphic pack '{}':", this->GetFilename()); + cemuLog_log(LogType::Force, "Syntax error while parsing patch for graphic pack '{}':", _pathToUtf8(this->GetRulesPath())); if(lineNumber >= 0) cemuLog_log(LogType::Force, fmt::format("Line {0}: {1}", lineNumber, errorMsg)); else diff --git a/src/Cafe/HW/Latte/Core/LatteSurfaceCopy.cpp b/src/Cafe/HW/Latte/Core/LatteSurfaceCopy.cpp index df99307c8..4f5b24add 100644 --- a/src/Cafe/HW/Latte/Core/LatteSurfaceCopy.cpp +++ b/src/Cafe/HW/Latte/Core/LatteSurfaceCopy.cpp @@ -46,9 +46,7 @@ void LatteSurfaceCopy_copySurfaceNew(MPTR srcPhysAddr, MPTR srcMipAddr, uint32 s // mark source and destination texture as still in use LatteTC_MarkTextureStillInUse(destinationTexture); LatteTC_MarkTextureStillInUse(sourceTexture); - // determine GL slice indices sint32 realSrcSlice = srcSlice; - sint32 realDstSlice = dstSlice; if (LatteTexture_doesEffectiveRescaleRatioMatch(sourceTexture, sourceView->firstMip, destinationTexture, destinationView->firstMip)) { // adjust copy size @@ -62,29 +60,11 @@ void LatteSurfaceCopy_copySurfaceNew(MPTR srcPhysAddr, MPTR srcMipAddr, uint32 s LatteTexture_scaleToEffectiveSize(sourceTexture, &effectiveCopyWidth, &effectiveCopyHeight, 0); // copy slice if (sourceView->baseTexture->isDepth != destinationView->baseTexture->isDepth) - { g_renderer->surfaceCopy_copySurfaceWithFormatConversion(sourceTexture, sourceView->firstMip, sourceView->firstSlice, destinationTexture, destinationView->firstMip, destinationView->firstSlice, copyWidth, copyHeight); - uint64 eventCounter = LatteTexture_getNextUpdateEventCounter(); - LatteTexture_MarkDynamicTextureAsChanged(destinationTexture->baseView, destinationView->firstSlice, destinationView->firstMip, eventCounter); - } else - { - // calculate mip levels relative to texture base - sint32 texDstMipLevel; - if (destinationTexture->physAddress == dstPhysAddr) - { - texDstMipLevel = dstLevel; - } - else - { - // todo - handle mip addresses properly - texDstMipLevel = dstLevel - destinationView->firstMip; - } - - g_renderer->texture_copyImageSubData(sourceTexture, sourceView->firstMip, 0, 0, realSrcSlice, destinationTexture, texDstMipLevel, 0, 0, realDstSlice, effectiveCopyWidth, effectiveCopyHeight, 1); - uint64 eventCounter = LatteTexture_getNextUpdateEventCounter(); - LatteTexture_MarkDynamicTextureAsChanged(destinationTexture->baseView, destinationView->firstSlice, texDstMipLevel, eventCounter); - } + g_renderer->texture_copyImageSubData(sourceTexture, sourceView->firstMip, 0, 0, realSrcSlice, destinationTexture, destinationView->firstMip, 0, 0, destinationView->firstSlice, effectiveCopyWidth, effectiveCopyHeight, 1); + const uint64 eventCounter = LatteTexture_getNextUpdateEventCounter(); + LatteTexture_MarkDynamicTextureAsChanged(destinationTexture->baseView, destinationView->firstSlice, destinationView->firstMip, eventCounter); } else { diff --git a/src/Cafe/HW/Latte/Core/LatteTexture.cpp b/src/Cafe/HW/Latte/Core/LatteTexture.cpp index 19162e04c..42a9d8c68 100644 --- a/src/Cafe/HW/Latte/Core/LatteTexture.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTexture.cpp @@ -836,6 +836,11 @@ bool IsDimensionCompatibleForView(Latte::E_DIM baseDim, Latte::E_DIM viewDim) // not compatible incompatibleDim = true; } + else if (baseDim == Latte::E_DIM::DIM_3D && viewDim == Latte::E_DIM::DIM_3D) + { + // incompatible by default, but may be compatible if the view matches the depth of the base texture and starts at mip/slice 0 + incompatibleDim = true; + } else if ((baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_CUBEMAP) || (baseDim == Latte::E_DIM::DIM_CUBEMAP && viewDim == Latte::E_DIM::DIM_2D)) { @@ -872,7 +877,9 @@ VIEWCOMPATIBILITY LatteTexture_CanTextureBeRepresentedAsView(LatteTexture* baseT return VIEW_NOT_COMPATIBLE; // depth and non-depth formats are never compatible (on OpenGL) if (!LatteTexture_IsTexelSizeCompatibleFormat(baseTexture->format, format) || baseTexture->width != width || baseTexture->height != height) return VIEW_NOT_COMPATIBLE; - if (!IsDimensionCompatibleForView(baseTexture->dim, dimView)) + // 3D views are only compatible on Vulkan if they match the base texture in regards to mip and slice count + bool isCompatible3DView = dimView == Latte::E_DIM::DIM_3D && baseTexture->dim == dimView && firstSlice == 0 && firstMip == 0 && baseTexture->mipLevels == numMip && baseTexture->depth == numSlice; + if (!isCompatible3DView && !IsDimensionCompatibleForView(baseTexture->dim, dimView)) return VIEW_NOT_COMPATIBLE; if (baseTexture->isDepth && baseTexture->format != format) { @@ -999,6 +1006,7 @@ void LatteTexture_RecreateTextureWithDifferentMipSliceCount(LatteTexture* textur // create new texture representation // if allowCreateNewDataTexture is true, a new texture will be created if necessary. If it is false, only existing textures may be used, except if a data-compatible version of the requested texture already exists and it's not view compatible +// the returned view will map to the provided mip and slice range within the created texture, this is to match the behavior of lookupSliceEx LatteTextureView* LatteTexture_CreateMapping(MPTR physAddr, MPTR physMipAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, Latte::E_HWTILEMODE tileMode, uint32 swizzle, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dimBase, Latte::E_DIM dimView, bool isDepth, bool allowCreateNewDataTexture) { if (format == Latte::E_GX2SURFFMT::INVALID_FORMAT) @@ -1105,11 +1113,17 @@ LatteTextureView* LatteTexture_CreateMapping(MPTR physAddr, MPTR physMipAddr, si if (allowCreateNewDataTexture == false) return nullptr; LatteTextureView* view = LatteTexture_CreateTexture(0, dimBase, physAddr, physMipAddr, format, width, height, depth, pitch, firstMip + numMip, swizzle, tileMode, isDepth); + LatteTexture* newTexture = view->baseTexture; LatteTexture_GatherTextureRelations(view->baseTexture); LatteTexture_UpdateTextureFromDynamicChanges(view->baseTexture); // delete any individual smaller slices/mips that have become redundant LatteTexture_DeleteAbsorbedSubtextures(view->baseTexture); - return view; + // create view + sint32 relativeMipIndex; + sint32 relativeSliceIndex; + VIEWCOMPATIBILITY viewCompatibility = LatteTexture_CanTextureBeRepresentedAsView(newTexture, physAddr, width, height, pitch, dimView, format, isDepth, firstMip, numMip, firstSlice, numSlice, relativeMipIndex, relativeSliceIndex); + cemu_assert(viewCompatibility == VIEW_COMPATIBLE); + return view->baseTexture->GetOrCreateView(dimView, format, relativeMipIndex + firstMip, numMip, relativeSliceIndex + firstSlice, numSlice); } LatteTextureView* LatteTC_LookupTextureByData(MPTR physAddr, sint32 width, sint32 height, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, sint32* searchIndex) diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp index 334b4855d..a37ba011e 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp @@ -507,7 +507,7 @@ void _emitRegisterAccessCode(LatteDecompilerShaderContext* shaderContext, sint32 { _emitTypeConversionPrefix(shaderContext, registerElementDataType, dataType); } - if(shaderContext->typeTracker.useArrayGPRs ) + if (shaderContext->typeTracker.useArrayGPRs) src->add("R"); else src->addFmt("R{}", gprIndex); @@ -540,6 +540,26 @@ void _emitRegisterAccessCode(LatteDecompilerShaderContext* shaderContext, sint32 _emitTypeConversionSuffix(shaderContext, registerElementDataType, dataType); } +// optimized variant of _emitRegisterAccessCode for raw one channel reads +void _emitRegisterChannelAccessCode(LatteDecompilerShaderContext* shaderContext, sint32 gprIndex, sint32 channel, sint32 dataType) +{ + cemu_assert_debug(gprIndex >= 0 && gprIndex <= 127); + cemu_assert_debug(channel >= 0 && channel < 4); + StringBuf* src = shaderContext->shaderSource; + sint32 registerElementDataType = shaderContext->typeTracker.defaultDataType; + _emitTypeConversionPrefix(shaderContext, registerElementDataType, dataType); + if (shaderContext->typeTracker.useArrayGPRs) + src->add("R"); + else + src->addFmt("R{}", gprIndex); + _appendRegisterTypeSuffix(src, registerElementDataType); + if (shaderContext->typeTracker.useArrayGPRs) + src->addFmt("[{}]", gprIndex); + src->add("."); + src->add(_getElementStrByIndex(channel)); + _emitTypeConversionSuffix(shaderContext, registerElementDataType, dataType); +} + void _emitALURegisterInputAccessCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex) { StringBuf* src = shaderContext->shaderSource; @@ -2129,63 +2149,31 @@ void _emitALUClauseCode(LatteDecompilerShaderContext* shaderContext, LatteDecomp /* * Emits code to access one component (xyzw) of the texture coordinate input vector */ -void _emitTEXSampleCoordInputComponent(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction, sint32 componentIndex, sint32 varType) +void _emitTEXSampleCoordInputComponent(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction, sint32 componentIndex, sint32 interpretSrcAsType) { + cemu_assert(componentIndex >= 0 && componentIndex < 4); + cemu_assert_debug(interpretSrcAsType == LATTE_DECOMPILER_DTYPE_SIGNED_INT || interpretSrcAsType == LATTE_DECOMPILER_DTYPE_FLOAT); StringBuf* src = shaderContext->shaderSource; - if( componentIndex >= 4 ) + sint32 elementSel = texInstruction->textureFetch.srcSel[componentIndex]; + if (elementSel < 4) { - debugBreakpoint(); + _emitRegisterChannelAccessCode(shaderContext, texInstruction->srcGpr, elementSel, interpretSrcAsType); return; } - sint32 elementSel = texInstruction->textureFetch.srcSel[componentIndex]; const char* resultElemTable[4] = {"x","y","z","w"}; - if( varType == LATTE_DECOMPILER_DTYPE_SIGNED_INT ) + if(interpretSrcAsType == LATTE_DECOMPILER_DTYPE_SIGNED_INT ) { - if (elementSel < 4) - { - if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT) - src->addFmt("{}.{}", _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[elementSel]); - else if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT) - src->addFmt("floatBitsToInt({}.{})", _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[elementSel]); - else - { - cemu_assert_unimplemented(); - } - } - else if( elementSel == 4 ) + if( elementSel == 4 ) src->add("floatBitsToInt(0.0)"); else if( elementSel == 5 ) src->add("floatBitsToInt(1.0)"); - else - { - cemu_assert_unimplemented(); - } } - else if( varType == LATTE_DECOMPILER_DTYPE_FLOAT ) + else if(interpretSrcAsType == LATTE_DECOMPILER_DTYPE_FLOAT ) { - if (elementSel < 4) - { - if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT) - src->addFmt("intBitsToFloat({}.{})", _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[elementSel]); - else if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT) - src->addFmt("{}.{}", _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[elementSel]); - else - { - cemu_assert_unimplemented(); - } - } - else if( elementSel == 4 ) - src->addFmt("0.0"); + if( elementSel == 4 ) + src->add("0.0"); else if( elementSel == 5 ) - src->addFmt("1.0"); - else - { - cemu_assert_unimplemented(); - } - } - else - { - cemu_assert_unimplemented(); + src->add("1.0"); } } @@ -2430,10 +2418,6 @@ void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, Latt cemu_assert_unimplemented(); src->add("texture("); } - if( texInstruction->textureFetch.srcSel[0] >= 4 ) - cemu_assert_unimplemented(); - if( texInstruction->textureFetch.srcSel[1] >= 4 ) - cemu_assert_unimplemented(); src->addFmt("{}{}, ", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex); // for textureGather() add shift (todo: depends on rounding mode set in sampler registers?) @@ -2455,7 +2439,7 @@ void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, Latt } } - + const sint32 texCoordDataType = (texOpcode == GPU7_TEX_INST_LD) ? LATTE_DECOMPILER_DTYPE_SIGNED_INT : LATTE_DECOMPILER_DTYPE_FLOAT; if(useTexelCoordinates) { // handle integer coordinates for texelFetch @@ -2463,9 +2447,9 @@ void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, Latt { src->add("ivec2("); src->add("vec2("); - _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, (texOpcode == GPU7_TEX_INST_LD) ? LATTE_DECOMPILER_DTYPE_SIGNED_INT : LATTE_DECOMPILER_DTYPE_FLOAT); + _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, texCoordDataType); src->addFmt(", "); - _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, (texOpcode == GPU7_TEX_INST_LD) ? LATTE_DECOMPILER_DTYPE_SIGNED_INT : LATTE_DECOMPILER_DTYPE_FLOAT); + _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, texCoordDataType); src->addFmt(")*uf_tex{}Scale", texInstruction->textureFetch.textureIndex); // close vec2 and scale @@ -2485,7 +2469,7 @@ void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, Latt else cemu_assert_debug(false); } - else + else /* useTexelCoordinates == false */ { // float coordinates if ( (texOpcode == GPU7_TEX_INST_SAMPLE_C || texOpcode == GPU7_TEX_INST_SAMPLE_C_L || texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ) ) @@ -2549,10 +2533,8 @@ void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, Latt else if( texDim == Latte::E_DIM::DIM_CUBEMAP ) { // 2 coords + faceId - if( texInstruction->textureFetch.srcSel[0] >= 4 || texInstruction->textureFetch.srcSel[1] >= 4 ) - { - debugBreakpoint(); - } + cemu_assert_debug(texInstruction->textureFetch.srcSel[0] < 4); + cemu_assert_debug(texInstruction->textureFetch.srcSel[1] < 4); src->add("vec4("); src->addFmt("redcCUBEReverse({},", _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], texInstruction->textureFetch.srcSel[1], -1, -1, tempBuffer0)); _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 2, LATTE_DECOMPILER_DTYPE_SIGNED_INT); @@ -2567,8 +2549,11 @@ void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, Latt else { // 2 coords - src->add(_getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], texInstruction->textureFetch.srcSel[1], -1, -1, tempBuffer0)); - + src->add("vec2("); + _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT); + src->add(","); + _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT); + src->add(")"); // avoid truncate to effectively round downwards on texel edges if (ActiveSettings::ForceSamplerRoundToPrecision()) src->addFmt("+ vec2(1.0)/vec2(textureSize({}{}, 0))/512.0", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex); @@ -2576,9 +2561,8 @@ void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, Latt // lod or lod bias parameter if( texOpcode == GPU7_TEX_INST_SAMPLE_L || texOpcode == GPU7_TEX_INST_SAMPLE_LB || texOpcode == GPU7_TEX_INST_SAMPLE_C_L) { - if( texInstruction->textureFetch.srcSel[3] >= 4 ) - debugBreakpoint(); - src->addFmt(",{}", _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[3], -1, -1, -1, tempBuffer0)); + src->add(","); + _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 3, LATTE_DECOMPILER_DTYPE_FLOAT); } else if( texOpcode == GPU7_TEX_INST_SAMPLE_LZ || texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ ) { diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp index e4c87d62b..8460c8b56 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp @@ -139,7 +139,7 @@ class _ShaderVkThreadPool } } - ~_ShaderVkThreadPool() + void StopThreads() { m_shutdownThread.store(true); for (uint32 i = 0; i < s_threads.size(); ++i) @@ -149,6 +149,11 @@ class _ShaderVkThreadPool s_threads.clear(); } + ~_ShaderVkThreadPool() + { + StopThreads(); + } + void CompilerThreadFunc() { while (!m_shutdownThread.load(std::memory_order::relaxed)) @@ -176,6 +181,8 @@ class _ShaderVkThreadPool } } + bool HasThreadsRunning() const { return !m_shutdownThread; } + public: std::vector s_threads; @@ -195,8 +202,8 @@ RendererShaderVk::RendererShaderVk(ShaderType type, uint64 baseHash, uint64 auxH m_compilationState.setValue(COMPILATION_STATE::QUEUED); ShaderVkThreadPool.s_compilationQueue.push_back(this); ShaderVkThreadPool.s_compilationQueueCount.increment(); - ShaderVkThreadPool.StartThreads(); ShaderVkThreadPool.s_compilationQueueMutex.unlock(); + cemu_assert_debug(ShaderVkThreadPool.HasThreadsRunning()); // make sure .StartThreads() was called } RendererShaderVk::~RendererShaderVk() @@ -204,6 +211,16 @@ RendererShaderVk::~RendererShaderVk() VulkanRenderer::GetInstance()->destroyShader(this); } +void RendererShaderVk::Init() +{ + ShaderVkThreadPool.StartThreads(); +} + +void RendererShaderVk::Shutdown() +{ + ShaderVkThreadPool.StopThreads(); +} + sint32 RendererShaderVk::GetUniformLocation(const char* name) { cemu_assert_suspicious(); @@ -457,4 +474,4 @@ void RendererShaderVk::ShaderCacheLoading_Close() { delete s_spirvCache; s_spirvCache = nullptr; -} \ No newline at end of file +} diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h index 561145f9c..207ea3eaa 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h @@ -28,6 +28,9 @@ class RendererShaderVk : public RendererShader RendererShaderVk(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& glslCode); virtual ~RendererShaderVk(); + static void Init(); + static void Shutdown(); + sint32 GetUniformLocation(const char* name) override; void SetUniform1iv(sint32 location, void* data, sint32 count) override; void SetUniform2fv(sint32 location, void* data, sint32 count) override; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 052ca21ab..5b4dd739a 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -591,6 +591,9 @@ VulkanRenderer::VulkanRenderer() { //cemuLog_log(LogType::Force, "Disable surface copies via buffer (Requires 2GB. Has only {}MB available)", availableSurfaceCopyBufferMem / 1024ull / 1024ull); } + + // start compilation threads + RendererShaderVk::Init(); } VulkanRenderer::~VulkanRenderer() @@ -598,6 +601,8 @@ VulkanRenderer::~VulkanRenderer() SubmitCommandBuffer(); WaitDeviceIdle(); WaitCommandBufferFinished(GetCurrentCommandBufferId()); + // shut down compilation threads + RendererShaderVk::Shutdown(); // shut down pipeline save thread m_destructionRequested = true; m_pipeline_cache_semaphore.notify(); diff --git a/src/Cafe/IOSU/PDM/iosu_pdm.cpp b/src/Cafe/IOSU/PDM/iosu_pdm.cpp index 45b4a1d88..e54529a9c 100644 --- a/src/Cafe/IOSU/PDM/iosu_pdm.cpp +++ b/src/Cafe/IOSU/PDM/iosu_pdm.cpp @@ -1,4 +1,5 @@ #include "iosu_pdm.h" +#include "Cafe/CafeSystem.h" #include "config/ActiveSettings.h" #include "Common/FileStream.h" #include "util/helpers/Semaphore.h" @@ -17,7 +18,8 @@ namespace iosu { namespace pdm { - std::mutex sDiaryLock; + std::recursive_mutex sPlaystatsLock; + std::recursive_mutex sDiaryLock; fs::path GetPDFile(const char* filename) { @@ -80,14 +82,16 @@ namespace iosu static_assert((NUM_PLAY_STATS_ENTRIES * sizeof(PlayStatsEntry)) == 0x1400); } - void LoadPlaystats() + void OpenPlaystats() { + std::unique_lock _l(sPlaystatsLock); PlayStats.numEntries = 0; for (size_t i = 0; i < NUM_PLAY_STATS_ENTRIES; i++) { auto& e = PlayStats.entry[i]; memset(&e, 0, sizeof(PlayStatsEntry)); } + cemu_assert_debug(!PlayStats.fs); PlayStats.fs = FileStream::openFile2(GetPDFile("PlayStats.dat"), true); if (!PlayStats.fs) { @@ -98,18 +102,39 @@ namespace iosu { delete PlayStats.fs; PlayStats.fs = nullptr; - cemuLog_log(LogType::Force, "PlayStats.dat malformed"); + cemuLog_log(LogType::Force, "PlayStats.dat malformed. Time tracking wont be used"); // dont delete the existing file in case it could still be salvaged (todo) and instead just dont track play time return; } + PlayStats.numEntries = 0; PlayStats.fs->readData(&PlayStats.numEntries, sizeof(uint32be)); if (PlayStats.numEntries > NUM_PLAY_STATS_ENTRIES) PlayStats.numEntries = NUM_PLAY_STATS_ENTRIES; PlayStats.fs->readData(PlayStats.entry, NUM_PLAY_STATS_ENTRIES * 20); } + void ClosePlaystats() + { + std::unique_lock _l(sPlaystatsLock); + if (PlayStats.fs) + { + delete PlayStats.fs; + PlayStats.fs = nullptr; + } + } + + void UnloadPlaystats() + { + std::unique_lock _l(sPlaystatsLock); + cemu_assert_debug(!PlayStats.fs); // unloading expects that file is closed + PlayStats.numEntries = 0; + for(auto& it : PlayStats.entry) + it = PlayStatsEntry{}; + } + PlayStatsEntry* PlayStats_GetEntry(uint64 titleId) { + std::unique_lock _l(sPlaystatsLock); uint32be titleIdHigh = (uint32)(titleId>>32); uint32be titleIdLow = (uint32)(titleId & 0xFFFFFFFF); size_t numEntries = PlayStats.numEntries; @@ -121,7 +146,7 @@ namespace iosu return nullptr; } - void PlayStats_WriteEntry(PlayStatsEntry* entry, bool writeEntryCount = false) + void PlayStats_WriteEntryNoLock(PlayStatsEntry* entry, bool writeEntryCount = false) { if (!PlayStats.fs) return; @@ -141,8 +166,15 @@ namespace iosu } } + void PlayStats_WriteEntry(PlayStatsEntry* entry, bool writeEntryCount = false) + { + std::unique_lock _l(sPlaystatsLock); + PlayStats_WriteEntryNoLock(entry, writeEntryCount); + } + PlayStatsEntry* PlayStats_CreateEntry(uint64 titleId) { + std::unique_lock _l(sPlaystatsLock); bool entryCountChanged = false; PlayStatsEntry* newEntry; if(PlayStats.numEntries < NUM_PLAY_STATS_ENTRIES) @@ -168,7 +200,7 @@ namespace iosu newEntry->numTimesLaunched = 1; newEntry->totalMinutesPlayed = 0; newEntry->ukn12 = 0; - PlayStats_WriteEntry(newEntry, entryCountChanged); + PlayStats_WriteEntryNoLock(newEntry, entryCountChanged); return newEntry; } @@ -176,6 +208,7 @@ namespace iosu // if it does not exist it creates a new entry with first and last played set to today PlayStatsEntry* PlayStats_BeginNewTracking(uint64 titleId) { + std::unique_lock _l(sPlaystatsLock); PlayStatsEntry* entry = PlayStats_GetEntry(titleId); if (entry) { @@ -189,11 +222,12 @@ namespace iosu void PlayStats_CountAdditionalMinutes(PlayStatsEntry* entry, uint32 additionalMinutes) { + std::unique_lock _l(sPlaystatsLock); if (additionalMinutes == 0) return; entry->totalMinutesPlayed += additionalMinutes; entry->mostRecentDayIndex = GetTodaysDayIndex(); - PlayStats_WriteEntry(entry); + PlayStats_WriteEntryNoLock(entry); } struct PlayDiaryHeader @@ -218,6 +252,7 @@ namespace iosu void CreatePlayDiary() { MakeDirectory(); + cemu_assert_debug(!PlayDiaryData.fs); PlayDiaryData.fs = FileStream::createFile2(GetPDFile("PlayDiary.dat")); if (!PlayDiaryData.fs) { @@ -230,7 +265,7 @@ namespace iosu PlayDiaryData.fs->writeData(&PlayDiaryData.header, sizeof(PlayDiaryHeader)); } - void LoadPlayDiary() + void OpenPlayDiary() { std::unique_lock _lock(sDiaryLock); cemu_assert_debug(!PlayDiaryData.fs); @@ -268,6 +303,26 @@ namespace iosu } } + void ClosePlayDiary() + { + std::unique_lock _lock(sDiaryLock); + if (PlayDiaryData.fs) + { + delete PlayDiaryData.fs; + PlayDiaryData.fs = nullptr; + } + } + + void UnloadDiaryData() + { + std::unique_lock _lock(sDiaryLock); + cemu_assert_debug(!PlayDiaryData.fs); // unloading expects that file is closed + PlayDiaryData.header.readIndex = 0; + PlayDiaryData.header.writeIndex = 0; + for (auto& it : PlayDiaryData.entry) + it = PlayDiaryEntry{}; + } + uint32 GetDiaryEntries(uint8 accountSlot, PlayDiaryEntry* diaryEntries, uint32 maxEntries) { std::unique_lock _lock(sDiaryLock); @@ -352,25 +407,59 @@ namespace iosu } } - void Initialize() + class : public ::IOSUModule { - // todo - add support for per-account handling - LoadPlaystats(); - LoadPlayDiary(); - } - - void StartTrackingTime(uint64 titleId) - { - sPDMRequestExitThread = false; - sPDMTimeTrackingThread = std::thread(TimeTrackingThread, titleId); - } + void PDMLoadAll() + { + OpenPlaystats(); + OpenPlayDiary(); + } + + void PDMUnloadAll() + { + UnloadPlaystats(); + UnloadDiaryData(); + } + + void PDMCloseAll() + { + ClosePlaystats(); + ClosePlayDiary(); + } + + void SystemLaunch() override + { + // todo - add support for per-account handling + PDMLoadAll(); + PDMCloseAll(); // close the files again, user may mess with MLC files or change MLC path while no game is running + } + void SystemExit() override + { + PDMCloseAll(); + PDMUnloadAll(); + } + void TitleStart() override + { + // reload data and keep files open + PDMUnloadAll(); + PDMLoadAll(); + auto titleId = CafeSystem::GetForegroundTitleId(); + sPDMRequestExitThread = false; + sPDMTimeTrackingThread = std::thread(TimeTrackingThread, titleId); + } + void TitleStop() override + { + sPDMRequestExitThread.store(true); + sPDMSem.increment(); + if(sPDMTimeTrackingThread.joinable()) + sPDMTimeTrackingThread.join(); + PDMCloseAll(); + } + }sIOSUModuleNNPDM; - void Stop() + IOSUModule* GetModule() { - sPDMRequestExitThread.store(true); - sPDMSem.increment(); - if(sPDMTimeTrackingThread.joinable()) - sPDMTimeTrackingThread.join(); + return static_cast(&sIOSUModuleNNPDM); } }; diff --git a/src/Cafe/IOSU/PDM/iosu_pdm.h b/src/Cafe/IOSU/PDM/iosu_pdm.h index fbafbc02f..0dd8a39d2 100644 --- a/src/Cafe/IOSU/PDM/iosu_pdm.h +++ b/src/Cafe/IOSU/PDM/iosu_pdm.h @@ -1,13 +1,10 @@ #pragma once +#include "Cafe/IOSU/iosu_types_common.h" namespace iosu { namespace pdm { - void Initialize(); - void StartTrackingTime(uint64 titleId); - void Stop(); - inline constexpr size_t NUM_PLAY_STATS_ENTRIES = 256; inline constexpr size_t NUM_PLAY_DIARY_ENTRIES_MAX = 18250; // 0x474A @@ -34,5 +31,7 @@ namespace iosu }; bool GetStatForGamelist(uint64 titleId, GameListStat& stat); + + IOSUModule* GetModule(); }; }; \ No newline at end of file diff --git a/src/gui/GraphicPacksWindow2.cpp b/src/gui/GraphicPacksWindow2.cpp index 13fec49aa..78b344d57 100644 --- a/src/gui/GraphicPacksWindow2.cpp +++ b/src/gui/GraphicPacksWindow2.cpp @@ -64,7 +64,7 @@ void GraphicPacksWindow2::FillGraphicPackList() const { bool found = false; - if (boost::icontains(p->GetPath(), m_filter)) + if (boost::icontains(p->GetVirtualPath(), m_filter)) found = true; else { @@ -82,7 +82,7 @@ void GraphicPacksWindow2::FillGraphicPackList() const continue; } - const auto& path = p->GetPath(); + const auto& path = p->GetVirtualPath(); auto tokens = TokenizeView(path, '/'); auto node = root; for(size_t i=0; iGetFilename())).lexically_normal(); + auto filename = _utf8ToPath(gp->GetNormalizedPathString()); if (gp->IsEnabled()) { data.graphic_pack_entries.try_emplace(filename); @@ -603,34 +603,29 @@ void GraphicPacksWindow2::OnCheckForUpdates(wxCommandEvent& event) { if (!CafeSystem::IsTitleRunning()) { - std::vector old_packs = GraphicPack2::GetGraphicPacks(); + // remember virtual paths of all the enabled packs + std::map previouslyEnabledPacks; + for(auto& it : GraphicPack2::GetGraphicPacks()) + { + if(it->IsEnabled()) + previouslyEnabledPacks.emplace(it->GetNormalizedPathString(), it->GetVirtualPath()); + } + // reload graphic packs RefreshGraphicPacks(); FillGraphicPackList(); - - // check if enabled graphic packs are lost: - const auto& new_packs = GraphicPack2::GetGraphicPacks(); - std::stringstream lost_packs; - for(const auto& p : old_packs) + // remove packs which are still present + for(auto& it : GraphicPack2::GetGraphicPacks()) + previouslyEnabledPacks.erase(it->GetNormalizedPathString()); + if(!previouslyEnabledPacks.empty()) { - if (!p->IsEnabled()) - continue; - - const auto it = std::find_if(new_packs.cbegin(), new_packs.cend(), [&p](const auto& gp) - { - return gp->GetFilename() == p->GetFilename(); - }); - - if(it == new_packs.cend()) + std::string lost_packs; + for(auto& it : previouslyEnabledPacks) { - lost_packs << p->GetPath() << "\n"; + lost_packs.append(it.second); + lost_packs.push_back('\n'); } - } - - const auto lost_packs_str = lost_packs.str(); - if (!lost_packs_str.empty()) - { wxString message = _("This update removed or renamed the following graphic packs:"); - message << "\n \n" << lost_packs_str << " \n" << _("You may need to set them up again."); + message << "\n \n" << wxString::FromUTF8(lost_packs) << " \n" << _("You may need to set them up again."); wxMessageBox(message, _("Warning"), wxOK | wxCENTRE | wxICON_INFORMATION, this); } }