diff --git a/CMakeLists.txt b/CMakeLists.txt index c988508c..9dc1a6f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,9 +89,10 @@ if (WIN32) option(ENABLE_XINPUT "Enables the usage of XInput" ON) option(ENABLE_DIRECTINPUT "Enables the usage of DirectInput" ON) add_compile_definitions(HAS_DIRECTINPUT) + set(ENABLE_WIIMOTE ON) +elseif (UNIX) + option(ENABLE_HIDAPI "Build with HIDAPI" ON) endif() - -option(ENABLE_HIDAPI "Build with HIDAPI" ON) option(ENABLE_SDL "Enables the SDLController backend" ON) # audio backends diff --git a/dist/linux/appimage.sh b/dist/linux/appimage.sh index 60a50329..7043a759 100755 --- a/dist/linux/appimage.sh +++ b/dist/linux/appimage.sh @@ -46,7 +46,6 @@ fi echo "Cemu Version Cemu-${GITVERSION}" rm AppDir/usr/lib/libwayland-client.so.0 -cp /lib/x86_64-linux-gnu/libstdc++.so.6 AppDir/usr/lib/ echo -e "export LC_ALL=C\nexport FONTCONFIG_PATH=/etc/fonts" >> AppDir/apprun-hooks/linuxdeploy-plugin-gtk.sh VERSION="${GITVERSION}" ./mkappimage.AppImage --appimage-extract-and-run "${GITHUB_WORKSPACE}"/AppDir diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index de9a6600..00a43a80 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -81,8 +81,6 @@ if (MACOS_BUNDLE) set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2023 Cemu Project") set(MACOSX_BUNDLE_CATEGORY "public.app-category.games") - set(MACOSX_MINIMUM_SYSTEM_VERSION "12.0") - set(MACOSX_BUNDLE_TYPE_EXTENSION "wua") set_target_properties(CemuBin PROPERTIES MACOSX_BUNDLE true diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index 30dab1d4..3d06281e 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -530,8 +530,7 @@ namespace CafeSystem { // entries in this list are ordered by initialization order. Shutdown in reverse order iosu::kernel::GetModule(), - iosu::fpd::GetModule(), - iosu::pdm::GetModule(), + iosu::fpd::GetModule() }; // initialize all subsystems which are persistent and don't depend on a game running @@ -572,6 +571,7 @@ namespace CafeSystem iosu::iosuAcp_init(); iosu::boss_init(); iosu::nim::Initialize(); + iosu::pdm::Initialize(); iosu::odm::Initialize(); // init Cafe OS avm::Initialize(); @@ -840,6 +840,7 @@ namespace CafeSystem coreinit::OSSchedulerBegin(3); else coreinit::OSSchedulerBegin(1); + iosu::pdm::StartTrackingTime(GetForegroundTitleId()); } void LaunchForegroundTitle() @@ -969,6 +970,8 @@ 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 ee92107a..d068237e 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, _pathToUtf8(gameProfilePath)); + IniParser iniParser(*profileContents, gameProfilePath.string()); // parse ini while (iniParser.NextSection()) { diff --git a/src/Cafe/GraphicPack/GraphicPack2.cpp b/src/Cafe/GraphicPack/GraphicPack2.cpp index 365e6e3e..72e301c4 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, _pathToUtf8(rulesPath)); + IniParser iniParser(rulesData, rulesPath.string()); if (!iniParser.NextSection()) { @@ -51,9 +51,10 @@ void GraphicPack2::LoadGraphicPack(fs::path graphicPackPath) cemuLog_log(LogType::Force, "{}: Unable to parse version", _pathToUtf8(rulesPath)); return; } + if (versionNum > GP_LEGACY_VERSION) { - GraphicPack2::LoadGraphicPack(rulesPath, iniParser); + GraphicPack2::LoadGraphicPack(_pathToUtf8(rulesPath), iniParser); return; } } @@ -78,22 +79,22 @@ void GraphicPack2::LoadAll() } } -bool GraphicPack2::LoadGraphicPack(const fs::path& rulesPath, IniParser& rules) +bool GraphicPack2::LoadGraphicPack(const std::string& filename, IniParser& rules) { try { - auto gp = std::make_shared(rulesPath, rules); + auto gp = std::make_shared(filename, 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->GetRulesPath(); + auto file = gp->GetFilename2(); auto it = config_entries.find(file.lexically_normal()); if (it == config_entries.cend()) { // check for relative path - it = config_entries.find(_utf8ToPath(gp->GetNormalizedPathString())); + it = config_entries.find(MakeRelativePath(ActiveSettings::GetUserDataPath(), gp->GetFilename2()).lexically_normal()); } if (it != config_entries.cend()) @@ -144,7 +145,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->GetNormalizedPathString() == graphic_pack->GetNormalizedPathString(); + return gp->GetFilename() == graphic_pack->GetFilename(); } ); @@ -172,12 +173,12 @@ void GraphicPack2::ActivateForCurrentTitle() { if (gp->GetPresets().empty()) { - cemuLog_log(LogType::Force, "Activate graphic pack: {}", gp->GetVirtualPath()); + cemuLog_log(LogType::Force, "Activate graphic pack: {}", gp->GetPath()); } else { std::string logLine; - logLine.assign(fmt::format("Activate graphic pack: {} [Presets: ", gp->GetVirtualPath())); + logLine.assign(fmt::format("Activate graphic pack: {} [Presets: ", gp->GetPath())); bool isFirst = true; for (auto& itr : gp->GetPresets()) { @@ -248,8 +249,8 @@ std::unordered_map GraphicPack2::ParsePres return vars; } -GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules) - : m_rulesPath(std::move(rulesPath)) +GraphicPack2::GraphicPack2(std::string filename, IniParser& rules) + : m_filename(std::move(filename)) { // we're already in [Definition] auto option_version = rules.FindOption("version"); @@ -258,7 +259,7 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules) m_version = StringHelpers::ToInt(*option_version, -1); if (m_version < 0) { - cemuLog_log(LogType::Force, "{}: Invalid version", _pathToUtf8(m_rulesPath)); + cemuLog_log(LogType::Force, "{}: Invalid version", m_filename); throw std::exception(); } @@ -304,7 +305,7 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, 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_virtualPath = *option_path; + m_path = *option_path; auto option_gp_name = rules.FindOption("name"); if (option_gp_name) @@ -507,11 +508,6 @@ 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; }); @@ -654,7 +650,7 @@ bool GraphicPack2::SetActivePreset(std::string_view category, std::string_view n void GraphicPack2::LoadShaders() { - fs::path path = GetRulesPath(); + fs::path path(m_filename); for (auto& it : fs::directory_iterator(path.remove_filename())) { if (!is_regular_file(it)) @@ -680,7 +676,7 @@ void GraphicPack2::LoadShaders() { std::ifstream file(p); if (!file.is_open()) - throw std::runtime_error(fmt::format("can't open graphic pack file: {}", _pathToUtf8(p.filename()))); + throw std::runtime_error(fmt::format("can't open graphic pack file: {}", p.filename().string()).c_str()); file.seekg(0, std::ios::end); m_output_shader_source.reserve(file.tellg()); @@ -693,7 +689,7 @@ void GraphicPack2::LoadShaders() { std::ifstream file(p); if (!file.is_open()) - throw std::runtime_error(fmt::format("can't open graphic pack file: {}", _pathToUtf8(p.filename()))); + throw std::runtime_error(fmt::format("can't open graphic pack file: {}", p.filename().string()).c_str()); file.seekg(0, std::ios::end); m_upscaling_shader_source.reserve(file.tellg()); @@ -706,7 +702,7 @@ void GraphicPack2::LoadShaders() { std::ifstream file(p); if (!file.is_open()) - throw std::runtime_error(fmt::format("can't open graphic pack file: {}", _pathToUtf8(p.filename()))); + throw std::runtime_error(fmt::format("can't open graphic pack file: {}", p.filename().string()).c_str()); file.seekg(0, std::ios::end); m_downscaling_shader_source.reserve(file.tellg()); @@ -809,7 +805,7 @@ void GraphicPack2::AddConstantsForCurrentPreset(ExpressionParser& ep) } } -void GraphicPack2::_iterateReplacedFiles(const fs::path& currentPath, bool isAOC) +void GraphicPack2::_iterateReplacedFiles(const fs::path& currentPath, std::wstring& internalPath, bool isAOC) { uint64 currentTitleId = CafeSystem::GetForegroundTitleId(); uint64 aocTitleId = (currentTitleId & 0xFFFFFFFFull) | 0x0005000c00000000ull; @@ -837,7 +833,7 @@ void GraphicPack2::LoadReplacedFiles() return; m_patchedFilesLoaded = true; - fs::path gfxPackPath = GetRulesPath(); + fs::path gfxPackPath = _utf8ToPath(m_filename); gfxPackPath = gfxPackPath.remove_filename(); // /content/ @@ -847,9 +843,10 @@ void GraphicPack2::LoadReplacedFiles() std::error_code ec; if (fs::exists(contentPath, ec)) { + std::wstring internalPath(L"/vol/content/"); // setup redirections fscDeviceRedirect_map(); - _iterateReplacedFiles(contentPath, false); + _iterateReplacedFiles(contentPath, internalPath, false); } // /aoc/ fs::path aocPath(gfxPackPath); @@ -860,9 +857,13 @@ 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, true); + _iterateReplacedFiles(aocPath, internalPath, true); } } @@ -885,14 +886,14 @@ bool GraphicPack2::Activate() return false; } - FileStream* fs_rules = FileStream::openFile2(m_rulesPath); + FileStream* fs_rules = FileStream::openFile2(_utf8ToPath(m_filename)); if (!fs_rules) return false; std::vector rulesData; fs_rules->extract(rulesData); delete fs_rules; - IniParser rules({ (char*)rulesData.data(), rulesData.size()}, GetNormalizedPathString()); + IniParser rules({ (char*)rulesData.data(), rulesData.size()}, m_filename); // load rules try @@ -946,7 +947,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, GetNormalizedPathString()); + 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); } m_texture_rules.emplace_back(rule); } @@ -991,11 +992,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, GetVirtualPath()); + cemuLog_log(LogType::Force, "rules.txt error: Mismatching vsync frequency {} in graphic pack \'{}\'", customVsyncFreq, GetPath()); } else { - cemuLog_log(LogType::Force, "Set vsync frequency to {} (graphic pack {})", customVsyncFreq, GetVirtualPath()); + cemuLog_log(LogType::Force, "Set vsync frequency to {} (graphic pack {})", customVsyncFreq, GetPath()); LatteTiming_setCustomVsyncFrequency(customVsyncFreq); } } diff --git a/src/Cafe/GraphicPack/GraphicPack2.h b/src/Cafe/GraphicPack/GraphicPack2.h index 6b07cce9..6396ecc7 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.h +++ b/src/Cafe/GraphicPack/GraphicPack2.h @@ -97,20 +97,20 @@ public: }; using PresetPtr = std::shared_ptr; - GraphicPack2(fs::path rulesPath, IniParser& rules); + GraphicPack2(std::string filename, IniParser& rules); bool IsEnabled() const { return m_enabled; } bool IsActivated() const { return m_activated; } sint32 GetVersion() const { return m_version; } - const fs::path GetRulesPath() const { return m_rulesPath; } - std::string GetNormalizedPathString() const; + const std::string& GetFilename() const { return m_filename; } + const fs::path GetFilename2() const { return fs::path(m_filename); } 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_virtualPath : m_name; } - const std::string& GetVirtualPath() const { return m_virtualPath; } // returns the path in the gfx tree hierarchy + const std::string& GetName() const { return m_name.empty() ? m_path : m_name; } + const std::string& GetPath() const { return m_path; } const std::string& GetDescription() const { return m_description; } bool IsDefaultEnabled() const { return m_default_enabled; } @@ -164,7 +164,7 @@ public: 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 fs::path& rulesPath, class IniParser& rules); + static bool LoadGraphicPack(const std::string& 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(); @@ -208,11 +208,11 @@ private: parser.TryAddConstant(var.first, (TType)var.second.second); } - fs::path m_rulesPath; + std::string m_filename; sint32 m_version; std::string m_name; - std::string m_virtualPath; + std::string m_path; std::string m_description; bool m_default_enabled = false; @@ -257,7 +257,7 @@ private: 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, bool isAOC); + void _iterateReplacedFiles(const fs::path& currentPath, std::wstring& internalPath, bool isAOC); // ram mappings std::vector> m_ramMappings; diff --git a/src/Cafe/GraphicPack/GraphicPack2Patches.cpp b/src/Cafe/GraphicPack/GraphicPack2Patches.cpp index 2c067484..5c79630c 100644 --- a/src/Cafe/GraphicPack/GraphicPack2Patches.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2Patches.cpp @@ -71,8 +71,19 @@ 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(m_rulesPath); + fs::path path(_utf8ToPath(m_filename)); path.remove_filename(); for (auto& p : fs::directory_iterator(path)) { @@ -118,7 +129,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(m_rulesPath); + fs::path path(_utf8ToPath(m_filename)); 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 05f8c696..d011a10b 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 '{}':", _pathToUtf8(this->GetRulesPath())); + cemuLog_log(LogType::Force, "Syntax error while parsing patch for graphic pack '{}':", this->GetFilename()); if(lineNumber >= 0) cemuLog_log(LogType::Force, fmt::format("Line {0}: {1}", lineNumber, errorMsg)); else diff --git a/src/Cafe/HW/Espresso/Debugger/GDBStub.cpp b/src/Cafe/HW/Espresso/Debugger/GDBStub.cpp index c8308594..e934e55d 100644 --- a/src/Cafe/HW/Espresso/Debugger/GDBStub.cpp +++ b/src/Cafe/HW/Espresso/Debugger/GDBStub.cpp @@ -356,7 +356,7 @@ void GDBServer::ThreadFunc() } char checkSumStr[2]; receiveMessage(checkSumStr, 2); - uint32_t checkSum = std::stoi(std::string(checkSumStr, sizeof(checkSumStr)), nullptr, 16); + uint32_t checkSum = std::stoi(checkSumStr, nullptr, 16); assert((checkedSum & 0xFF) == checkSum); HandleCommand(message); diff --git a/src/Cafe/HW/Latte/Core/Latte.h b/src/Cafe/HW/Latte/Core/Latte.h index dc3cbc91..861d7ddf 100644 --- a/src/Cafe/HW/Latte/Core/Latte.h +++ b/src/Cafe/HW/Latte/Core/Latte.h @@ -115,7 +115,7 @@ void LatteTC_RegisterTexture(LatteTexture* tex); void LatteTC_UnregisterTexture(LatteTexture* tex); uint32 LatteTexture_CalculateTextureDataHash(LatteTexture* hostTexture); -void LatteTexture_ReloadData(LatteTexture* hostTexture); +void LatteTexture_ReloadData(LatteTexture* hostTexture, uint32 textureUnit); bool LatteTC_HasTextureChanged(LatteTexture* hostTexture, bool force = false); void LatteTC_ResetTextureChangeTracker(LatteTexture* hostTexture, bool force = false); diff --git a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp index abdfda21..06015949 100644 --- a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp +++ b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp @@ -239,6 +239,8 @@ LatteTextureView* LatteMRT_CreateColorBuffer(MPTR colorBufferPhysMem, uint32 wid textureView = LatteTexture_CreateMapping(colorBufferPhysMem, MPTR_NULL, width, height, viewSlice+1, pitch, tileMode, swizzle, 0, 1, viewSlice, 1, format, Latte::E_DIM::DIM_2D_ARRAY, Latte::E_DIM::DIM_2D, false); else textureView = LatteTexture_CreateMapping(colorBufferPhysMem, MPTR_NULL, width, height, 1, pitch, tileMode, swizzle, 0, 1, viewSlice, 1, format, Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, false); + // unbind texture + g_renderer->texture_bindAndActivate(nullptr, 0); return textureView; } @@ -251,6 +253,8 @@ LatteTextureView* LatteMRT_CreateDepthBuffer(MPTR depthBufferPhysMem, uint32 wid textureView = LatteTexture_CreateMapping(depthBufferPhysMem, MPTR_NULL, width, height, viewSlice+1, pitch, tileMode, swizzle, 0, 1, viewSlice, 1, format, Latte::E_DIM::DIM_2D_ARRAY, Latte::E_DIM::DIM_2D, true); LatteMRT::SetDepthAndStencilAttachment(textureView, textureView->baseTexture->hasStencil); + // unbind texture + g_renderer->texture_bindAndActivate(nullptr, 0); return textureView; } diff --git a/src/Cafe/HW/Latte/Core/LatteShader.cpp b/src/Cafe/HW/Latte/Core/LatteShader.cpp index 503fb664..c0ad06a1 100644 --- a/src/Cafe/HW/Latte/Core/LatteShader.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShader.cpp @@ -838,6 +838,7 @@ LatteDecompilerShader* LatteShader_CompileSeparablePixelShader(uint64 baseHash, void LatteSHRC_UpdateVertexShader(uint8* vertexShaderPtr, uint32 vertexShaderSize, bool usesGeometryShader) { // todo - should include VTX_SEMANTIC table in state + LatteSHRC_UpdateVSBaseHash(vertexShaderPtr, vertexShaderSize, usesGeometryShader); uint64 vsAuxHash = 0; auto itBaseShader = sVertexShaders.find(_shaderBaseHash_vs); @@ -854,13 +855,15 @@ void LatteSHRC_UpdateVertexShader(uint8* vertexShaderPtr, uint32 vertexShaderSiz LatteGPUState.activeShaderHasError = true; return; } + g_renderer->shader_bind(vertexShader->shader); _activeVertexShader = vertexShader; } void LatteSHRC_UpdateGeometryShader(bool usesGeometryShader, uint8* geometryShaderPtr, uint32 geometryShaderSize, uint8* geometryCopyShader, uint32 geometryCopyShaderSize) { - if (!usesGeometryShader || !_activeVertexShader) + if (usesGeometryShader == false || _activeVertexShader == nullptr) { + g_renderer->shader_unbind(RendererShader::ShaderType::kGeometry); _shaderBaseHash_gs = 0; _activeGeometryShader = nullptr; return; @@ -884,11 +887,21 @@ void LatteSHRC_UpdateGeometryShader(bool usesGeometryShader, uint8* geometryShad LatteGPUState.activeShaderHasError = true; return; } + g_renderer->shader_bind(geometryShader->shader); _activeGeometryShader = geometryShader; } void LatteSHRC_UpdatePixelShader(uint8* pixelShaderPtr, uint32 pixelShaderSize, bool usesGeometryShader) { + if (LatteGPUState.contextRegister[mmVGT_STRMOUT_EN] != 0 && g_renderer->GetType() == RendererAPI::OpenGL) + { + if (_activePixelShader) + { + g_renderer->shader_unbind(RendererShader::ShaderType::kFragment); + _activePixelShader = nullptr; + } + return; + } LatteSHRC_UpdatePSBaseHash(pixelShaderPtr, pixelShaderSize, usesGeometryShader); uint64 psAuxHash = 0; auto itBaseShader = sPixelShaders.find(_shaderBaseHash_ps); @@ -905,6 +918,7 @@ void LatteSHRC_UpdatePixelShader(uint8* pixelShaderPtr, uint32 pixelShaderSize, LatteGPUState.activeShaderHasError = true; return; } + g_renderer->shader_bind(pixelShader->shader); _activePixelShader = pixelShader; } diff --git a/src/Cafe/HW/Latte/Core/LatteSurfaceCopy.cpp b/src/Cafe/HW/Latte/Core/LatteSurfaceCopy.cpp index 4f5b24ad..df99307c 100644 --- a/src/Cafe/HW/Latte/Core/LatteSurfaceCopy.cpp +++ b/src/Cafe/HW/Latte/Core/LatteSurfaceCopy.cpp @@ -46,7 +46,9 @@ 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 @@ -60,11 +62,29 @@ 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 - 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); + { + // 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); + } } else { diff --git a/src/Cafe/HW/Latte/Core/LatteTexture.cpp b/src/Cafe/HW/Latte/Core/LatteTexture.cpp index d38af8ec..19162e04 100644 --- a/src/Cafe/HW/Latte/Core/LatteTexture.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTexture.cpp @@ -795,8 +795,6 @@ bool IsDimensionCompatibleForView(Latte::E_DIM baseDim, Latte::E_DIM viewDim) bool incompatibleDim = false; if (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_2D) ; - else if (baseDim == Latte::E_DIM::DIM_1D && viewDim == Latte::E_DIM::DIM_1D) - ; else if (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_2D_ARRAY) ; else if (baseDim == Latte::E_DIM::DIM_CUBEMAP && viewDim == Latte::E_DIM::DIM_CUBEMAP) @@ -838,11 +836,6 @@ 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)) { @@ -879,9 +872,7 @@ 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; - // 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)) + if (!IsDimensionCompatibleForView(baseTexture->dim, dimView)) return VIEW_NOT_COMPATIBLE; if (baseTexture->isDepth && baseTexture->format != format) { @@ -987,7 +978,7 @@ void LatteTexture_RecreateTextureWithDifferentMipSliceCount(LatteTexture* textur newDim = Latte::E_DIM::DIM_2D_ARRAY; else if (newDim == Latte::E_DIM::DIM_1D && newDepth > 1) newDim = Latte::E_DIM::DIM_1D_ARRAY; - LatteTextureView* view = LatteTexture_CreateTexture(newDim, texture->physAddress, physMipAddr, texture->format, texture->width, texture->height, newDepth, texture->pitch, newMipCount, texture->swizzle, texture->tileMode, texture->isDepth); + LatteTextureView* view = LatteTexture_CreateTexture(0, newDim, texture->physAddress, physMipAddr, texture->format, texture->width, texture->height, newDepth, texture->pitch, newMipCount, texture->swizzle, texture->tileMode, texture->isDepth); cemu_assert(!(view->baseTexture->mipLevels <= 1 && physMipAddr == MPTR_NULL && newMipCount > 1)); // copy data from old texture if its dynamically updated if (texture->isUpdatedOnGPU) @@ -1008,7 +999,6 @@ 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) @@ -1114,18 +1104,12 @@ LatteTextureView* LatteTexture_CreateMapping(MPTR physAddr, MPTR physMipAddr, si // create new texture if (allowCreateNewDataTexture == false) return nullptr; - LatteTextureView* view = LatteTexture_CreateTexture(dimBase, physAddr, physMipAddr, format, width, height, depth, pitch, firstMip + numMip, swizzle, tileMode, isDepth); - LatteTexture* newTexture = view->baseTexture; + LatteTextureView* view = LatteTexture_CreateTexture(0, dimBase, physAddr, physMipAddr, format, width, height, depth, pitch, firstMip + numMip, swizzle, tileMode, isDepth); LatteTexture_GatherTextureRelations(view->baseTexture); LatteTexture_UpdateTextureFromDynamicChanges(view->baseTexture); // delete any individual smaller slices/mips that have become redundant LatteTexture_DeleteAbsorbedSubtextures(view->baseTexture); - // 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); + return view; } LatteTextureView* LatteTC_LookupTextureByData(MPTR physAddr, sint32 width, sint32 height, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, sint32* searchIndex) @@ -1193,8 +1177,12 @@ LatteTextureView* LatteTC_GetTextureSliceViewOrTryCreate(MPTR srcImagePtr, MPTR void LatteTexture_UpdateDataToLatest(LatteTexture* texture) { if (LatteTC_HasTextureChanged(texture)) - LatteTexture_ReloadData(texture); - + { + g_renderer->texture_rememberBoundTexture(0); + g_renderer->texture_bindAndActivateRawTex(texture, 0); + LatteTexture_ReloadData(texture, 0); + g_renderer->texture_restoreBoundTexture(0); + } if (texture->reloadFromDynamicTextures) { LatteTexture_UpdateCacheFromDynamicTextures(texture); @@ -1243,7 +1231,7 @@ std::vector& LatteTexture::GetAllTextures() return sAllTextures; } -LatteTexture::LatteTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, +LatteTexture::LatteTexture(uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) { _AddTextureToGlobalList(this); diff --git a/src/Cafe/HW/Latte/Core/LatteTexture.h b/src/Cafe/HW/Latte/Core/LatteTexture.h index d5e872e6..6cdc528e 100644 --- a/src/Cafe/HW/Latte/Core/LatteTexture.h +++ b/src/Cafe/HW/Latte/Core/LatteTexture.h @@ -24,9 +24,11 @@ struct LatteSamplerState class LatteTexture { public: - LatteTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth); + LatteTexture(uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth); virtual ~LatteTexture(); + virtual void InitTextureState() {}; + LatteTextureView* GetOrCreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) { for (auto& itr : views) @@ -305,7 +307,7 @@ std::vector LatteTexture_QueryCacheInfo(); float* LatteTexture_getEffectiveTextureScale(LatteConst::ShaderType shaderType, sint32 texUnit); -LatteTextureView* LatteTexture_CreateTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth); +LatteTextureView* LatteTexture_CreateTexture(uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth); void LatteTexture_Delete(LatteTexture* texture); void LatteTextureLoader_writeReadbackTextureToMemory(LatteTextureDefinition* textureData, uint32 sliceIndex, uint32 mipIndex, uint8* linearPixelData); diff --git a/src/Cafe/HW/Latte/Core/LatteTextureLegacy.cpp b/src/Cafe/HW/Latte/Core/LatteTextureLegacy.cpp index 0260002b..9cce2526 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureLegacy.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTextureLegacy.cpp @@ -32,9 +32,9 @@ void LatteTexture_setEffectiveTextureScale(LatteConst::ShaderType shaderType, si t[1] = v; } -void LatteTextureLoader_UpdateTextureSliceData(LatteTexture* tex, uint32 sliceIndex, uint32 mipIndex, MPTR physImagePtr, MPTR physMipPtr, Latte::E_DIM dim, uint32 width, uint32 height, uint32 depth, uint32 mipLevels, uint32 pitch, Latte::E_HWTILEMODE tileMode, uint32 swizzle, bool dumpTex); +void LatteTextureLoader_UpdateTextureSliceData(LatteTexture* tex, sint32 textureUnit, uint32 sliceIndex, uint32 mipIndex, MPTR physImagePtr, MPTR physMipPtr, Latte::E_DIM dim, uint32 width, uint32 height, uint32 depth, uint32 mipLevels, uint32 pitch, Latte::E_HWTILEMODE tileMode, uint32 swizzle, bool dumpTex); -void LatteTexture_ReloadData(LatteTexture* tex) +void LatteTexture_ReloadData(LatteTexture* tex, uint32 textureUnit) { tex->reloadCount++; for(sint32 mip=0; mipmipLevels; mip++) @@ -44,35 +44,35 @@ void LatteTexture_ReloadData(LatteTexture* tex) { sint32 numSlices = std::max(tex->depth, 1); for(sint32 s=0; sphysAddress, tex->physMipAddress, tex->dim, tex->width, tex->height, tex->depth, tex->mipLevels, tex->pitch, tex->tileMode, tex->swizzle, true); + LatteTextureLoader_UpdateTextureSliceData(tex, textureUnit, s, mip, tex->physAddress, tex->physMipAddress, tex->dim, tex->width, tex->height, tex->depth, tex->mipLevels, tex->pitch, tex->tileMode, tex->swizzle, true); } else if( tex->dim == Latte::E_DIM::DIM_CUBEMAP ) { cemu_assert_debug((tex->depth % 6) == 0); sint32 numFullCubeMaps = tex->depth/6; // number of cubemaps (if numFullCubeMaps is >1 then this texture is a cubemap array) for(sint32 s=0; sphysAddress, tex->physMipAddress, tex->dim, tex->width, tex->height, tex->depth, tex->mipLevels, tex->pitch, tex->tileMode, tex->swizzle, true); + LatteTextureLoader_UpdateTextureSliceData(tex, textureUnit, s, mip, tex->physAddress, tex->physMipAddress, tex->dim, tex->width, tex->height, tex->depth, tex->mipLevels, tex->pitch, tex->tileMode, tex->swizzle, true); } else if( tex->dim == Latte::E_DIM::DIM_3D ) { sint32 mipDepth = std::max(tex->depth>>mip, 1); for(sint32 s=0; sphysAddress, tex->physMipAddress, tex->dim, tex->width, tex->height, tex->depth, tex->mipLevels, tex->pitch, tex->tileMode, tex->swizzle, true); + LatteTextureLoader_UpdateTextureSliceData(tex, textureUnit, s, mip, tex->physAddress, tex->physMipAddress, tex->dim, tex->width, tex->height, tex->depth, tex->mipLevels, tex->pitch, tex->tileMode, tex->swizzle, true); } } else { // load slice 0 - LatteTextureLoader_UpdateTextureSliceData(tex, 0, mip, tex->physAddress, tex->physMipAddress, tex->dim, tex->width, tex->height, tex->depth, tex->mipLevels, tex->pitch, tex->tileMode, tex->swizzle, true); + LatteTextureLoader_UpdateTextureSliceData(tex, textureUnit, 0, mip, tex->physAddress, tex->physMipAddress, tex->dim, tex->width, tex->height, tex->depth, tex->mipLevels, tex->pitch, tex->tileMode, tex->swizzle, true); } } tex->lastUpdateEventCounter = LatteTexture_getNextUpdateEventCounter(); } -LatteTextureView* LatteTexture_CreateTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) +LatteTextureView* LatteTexture_CreateTexture(uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) { - const auto tex = g_renderer->texture_createTextureEx(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth); + const auto tex = g_renderer->texture_createTextureEx(textureUnit, dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth); // init slice/mip info array LatteTexture_InitSliceAndMipInfo(tex); LatteTexture_RegisterTextureMemoryOccupancy(tex); @@ -110,7 +110,7 @@ LatteTextureView* LatteTexture_CreateTexture(Latte::E_DIM dim, MPTR physAddress, } } } - LatteTexture_ReloadData(tex); + LatteTexture_ReloadData(tex, textureUnit); LatteTC_MarkTextureStillInUse(tex); LatteTC_RegisterTexture(tex); // create initial view that maps to the whole texture @@ -247,7 +247,7 @@ void LatteTexture_updateTexturesForStage(LatteDecompilerShader* shaderContext, u textureView->lastTextureBindIndex = LatteGPUState.textureBindCounter; rendererGL->renderstate_updateTextureSettingsGL(shaderContext, textureView, textureIndex + glBackendBaseTexUnit, word4, textureIndex, isDepthSampler); } - g_renderer->texture_setLatteTexture(textureView, textureIndex + glBackendBaseTexUnit); + g_renderer->texture_bindOnly(textureView, textureIndex + glBackendBaseTexUnit); // update if data changed bool swizzleChanged = false; if (textureView->baseTexture->swizzle != swizzle) @@ -285,8 +285,9 @@ void LatteTexture_updateTexturesForStage(LatteDecompilerShader* shaderContext, u textureView->baseTexture->physMipAddress = physMipAddr; } } + g_renderer->texture_bindAndActivateRawTex(textureView->baseTexture, textureIndex + glBackendBaseTexUnit); debug_printf("Reload reason: Data-change when bound as texture (new hash 0x%08x)\n", textureView->baseTexture->texDataHash2); - LatteTexture_ReloadData(textureView->baseTexture); + LatteTexture_ReloadData(textureView->baseTexture, textureIndex + glBackendBaseTexUnit); } LatteTexture* baseTexture = textureView->baseTexture; if (baseTexture->reloadFromDynamicTextures) diff --git a/src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp b/src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp index 862fff06..331c1500 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp @@ -599,7 +599,7 @@ void LatteTextureLoader_loadTextureDataIntoSlice(LatteTexture* hostTexture, sint } } -void LatteTextureLoader_UpdateTextureSliceData(LatteTexture* tex, uint32 sliceIndex, uint32 mipIndex, MPTR physImagePtr, MPTR physMipPtr, Latte::E_DIM dim, uint32 width, uint32 height, uint32 depth, uint32 mipLevels, uint32 pitch, Latte::E_HWTILEMODE tileMode, uint32 swizzle, bool dumpTex) +void LatteTextureLoader_UpdateTextureSliceData(LatteTexture* tex, sint32 textureUnit, uint32 sliceIndex, uint32 mipIndex, MPTR physImagePtr, MPTR physMipPtr, Latte::E_DIM dim, uint32 width, uint32 height, uint32 depth, uint32 mipLevels, uint32 pitch, Latte::E_HWTILEMODE tileMode, uint32 swizzle, bool dumpTex) { LatteTextureLoaderCtx textureLoader = { 0 }; diff --git a/src/Cafe/HW/Latte/Core/LatteThread.cpp b/src/Cafe/HW/Latte/Core/LatteThread.cpp index 60b32ec4..897f769c 100644 --- a/src/Cafe/HW/Latte/Core/LatteThread.cpp +++ b/src/Cafe/HW/Latte/Core/LatteThread.cpp @@ -44,7 +44,7 @@ LatteTextureView* LatteHandleOSScreen_getOrCreateScreenTex(MPTR physAddress, uin LatteTextureView* texView = LatteTextureViewLookupCache::lookup(physAddress, width, height, 1, pitch, 0, 1, 0, 1, Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM, Latte::E_DIM::DIM_2D); if (texView) return texView; - return LatteTexture_CreateTexture(Latte::E_DIM::DIM_2D, physAddress, 0, Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM, width, height, 1, pitch, 1, 0, Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED, false); + return LatteTexture_CreateTexture(0, Latte::E_DIM::DIM_2D, physAddress, 0, Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM, width, height, 1, pitch, 1, 0, Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED, false); } void LatteHandleOSScreen_prepareTextures() @@ -71,7 +71,8 @@ bool LatteHandleOSScreen_TV() const uint32 bufferIndexTV = (bufferDisplayTV); const uint32 bufferIndexDRC = bufferDisplayDRC; - LatteTexture_ReloadData(osScreenTVTex[bufferIndexTV]->baseTexture); + g_renderer->texture_bindAndActivate(osScreenTVTex[bufferIndexTV], 0); + LatteTexture_ReloadData(osScreenTVTex[bufferIndexTV]->baseTexture, 0); // TV screen LatteRenderTarget_copyToBackbuffer(osScreenTVTex[bufferIndexTV]->baseTexture->baseView, false); @@ -93,7 +94,8 @@ bool LatteHandleOSScreen_DRC() const uint32 bufferIndexDRC = bufferDisplayDRC; - LatteTexture_ReloadData(osScreenDRCTex[bufferIndexDRC]->baseTexture); + g_renderer->texture_bindAndActivate(osScreenDRCTex[bufferIndexDRC], 0); + LatteTexture_ReloadData(osScreenDRCTex[bufferIndexDRC]->baseTexture, 0); // GamePad screen LatteRenderTarget_copyToBackbuffer(osScreenDRCTex[bufferIndexDRC]->baseTexture->baseView, true); diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.cpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.cpp index cf88b901..30e3d7a2 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.cpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.cpp @@ -666,9 +666,6 @@ void LatteDecompiler_ParseTEXClause(LatteDecompilerShader* shaderContext, LatteD uint32 offsetY = (word2 >> 5) & 0x1F; uint32 offsetZ = (word2 >> 10) & 0x1F; - sint8 lodBias = (word2 >> 21) & 0x7F; - if ((lodBias&0x40) != 0) - lodBias |= 0x80; // bufferID -> Texture index // samplerId -> Sampler index sint32 textureIndex = bufferId - 0x00; @@ -696,7 +693,6 @@ void LatteDecompiler_ParseTEXClause(LatteDecompilerShader* shaderContext, LatteD texInstruction.textureFetch.unnormalized[1] = coordTypeY == 0; texInstruction.textureFetch.unnormalized[2] = coordTypeZ == 0; texInstruction.textureFetch.unnormalized[3] = coordTypeW == 0; - texInstruction.textureFetch.lodBias = (sint8)lodBias; cfInstruction->instructionsTEX.emplace_back(texInstruction); } else if( inst0_4 == GPU7_TEX_INST_SET_CUBEMAP_INDEX ) diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp index aa7b7162..334b4855 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,26 +540,6 @@ 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; @@ -2149,31 +2129,63 @@ 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 interpretSrcAsType) +void _emitTEXSampleCoordInputComponent(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction, sint32 componentIndex, sint32 varType) { - cemu_assert(componentIndex >= 0 && componentIndex < 4); - cemu_assert_debug(interpretSrcAsType == LATTE_DECOMPILER_DTYPE_SIGNED_INT || interpretSrcAsType == LATTE_DECOMPILER_DTYPE_FLOAT); StringBuf* src = shaderContext->shaderSource; - sint32 elementSel = texInstruction->textureFetch.srcSel[componentIndex]; - if (elementSel < 4) + if( componentIndex >= 4 ) { - _emitRegisterChannelAccessCode(shaderContext, texInstruction->srcGpr, elementSel, interpretSrcAsType); + debugBreakpoint(); return; } + sint32 elementSel = texInstruction->textureFetch.srcSel[componentIndex]; const char* resultElemTable[4] = {"x","y","z","w"}; - if(interpretSrcAsType == LATTE_DECOMPILER_DTYPE_SIGNED_INT ) + if( varType == LATTE_DECOMPILER_DTYPE_SIGNED_INT ) { - if( elementSel == 4 ) + 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 ) src->add("floatBitsToInt(0.0)"); else if( elementSel == 5 ) src->add("floatBitsToInt(1.0)"); + else + { + cemu_assert_unimplemented(); + } } - else if(interpretSrcAsType == LATTE_DECOMPILER_DTYPE_FLOAT ) + else if( varType == LATTE_DECOMPILER_DTYPE_FLOAT ) { - if( elementSel == 4 ) - src->add("0.0"); + 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"); else if( elementSel == 5 ) - src->add("1.0"); + src->addFmt("1.0"); + else + { + cemu_assert_unimplemented(); + } + } + else + { + cemu_assert_unimplemented(); } } @@ -2418,6 +2430,10 @@ 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?) @@ -2439,7 +2455,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 @@ -2447,9 +2463,9 @@ void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, Latt { src->add("ivec2("); src->add("vec2("); - _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, texCoordDataType); + _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, (texOpcode == GPU7_TEX_INST_LD) ? LATTE_DECOMPILER_DTYPE_SIGNED_INT : LATTE_DECOMPILER_DTYPE_FLOAT); src->addFmt(", "); - _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, texCoordDataType); + _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, (texOpcode == GPU7_TEX_INST_LD) ? LATTE_DECOMPILER_DTYPE_SIGNED_INT : LATTE_DECOMPILER_DTYPE_FLOAT); src->addFmt(")*uf_tex{}Scale", texInstruction->textureFetch.textureIndex); // close vec2 and scale @@ -2469,7 +2485,7 @@ void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, Latt else cemu_assert_debug(false); } - else /* useTexelCoordinates == false */ + else { // float coordinates if ( (texOpcode == GPU7_TEX_INST_SAMPLE_C || texOpcode == GPU7_TEX_INST_SAMPLE_C_L || texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ) ) @@ -2533,8 +2549,10 @@ void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, Latt else if( texDim == Latte::E_DIM::DIM_CUBEMAP ) { // 2 coords + faceId - cemu_assert_debug(texInstruction->textureFetch.srcSel[0] < 4); - cemu_assert_debug(texInstruction->textureFetch.srcSel[1] < 4); + if( texInstruction->textureFetch.srcSel[0] >= 4 || texInstruction->textureFetch.srcSel[1] >= 4 ) + { + debugBreakpoint(); + } 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); @@ -2549,11 +2567,8 @@ void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, Latt else { // 2 coords - src->add("vec2("); - _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT); - src->add(","); - _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT); - src->add(")"); + src->add(_getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], texInstruction->textureFetch.srcSel[1], -1, -1, tempBuffer0)); + // 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); @@ -2561,13 +2576,9 @@ 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(texOpcode == GPU7_TEX_INST_SAMPLE_LB) - src->addFmt("{}", (float)texInstruction->textureFetch.lodBias / 16.0f); - else - { - src->add(","); - _emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 3, LATTE_DECOMPILER_DTYPE_FLOAT); - } + 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)); } else if( texOpcode == GPU7_TEX_INST_SAMPLE_LZ || texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ ) { diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h index ac2a1fe1..54112ddf 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h @@ -57,7 +57,6 @@ struct LatteDecompilerTEXInstruction sint8 offsetY{}; sint8 offsetZ{}; bool unnormalized[4]{}; // set if texture coordinates are in [0,dim] range instead of [0,1] - sint8 lodBias{}; // divide by 16 to get actual value }textureFetch; // memRead struct diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp index 584af40c..c9541470 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp @@ -19,17 +19,20 @@ static GLuint _genTextureHandleGL() return texIdPool[texIdPoolIndex - 1]; } -LatteTextureGL::LatteTextureGL(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, +LatteTextureGL::LatteTextureGL(uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) - : LatteTexture(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth) + : LatteTexture(textureUnit, dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth) { - GenerateEmptyTextureFromGX2Dim(dim, this->glId_texture, this->glTexTarget, true); + GenerateEmptyTextureFromGX2Dim(dim, this->glId_texture, this->glTexTarget); // set format info FormatInfoGL glFormatInfo; GetOpenGLFormatInfo(isDepth, format, dim, &glFormatInfo); this->glInternalFormat = glFormatInfo.glInternalFormat; this->isAlternativeFormat = glFormatInfo.isUsingAlternativeFormat; this->hasStencil = glFormatInfo.hasStencil; // todo - should get this from the GX2 format? + // bind texture + g_renderer->texture_bindAndActivateRawTex(this, textureUnit); + LatteTextureGL::InitTextureState(); // set debug name bool useGLDebugNames = false; #ifdef CEMU_DEBUG_ASSERT @@ -51,8 +54,9 @@ LatteTextureGL::~LatteTextureGL() catchOpenGLError(); } -void LatteTextureGL::GenerateEmptyTextureFromGX2Dim(Latte::E_DIM dim, GLuint& texId, GLint& texTarget, bool createForTargetType) +void LatteTextureGL::GenerateEmptyTextureFromGX2Dim(Latte::E_DIM dim, GLuint& texId, GLint& texTarget) { + texId = _genTextureHandleGL(); if (dim == Latte::E_DIM::DIM_2D) texTarget = GL_TEXTURE_2D; else if (dim == Latte::E_DIM::DIM_1D) @@ -69,10 +73,6 @@ void LatteTextureGL::GenerateEmptyTextureFromGX2Dim(Latte::E_DIM dim, GLuint& te { cemu_assert_unimplemented(); } - if(createForTargetType) - texId = glCreateTextureWrapper(texTarget); // initializes the texture to texTarget (equivalent to calling glGenTextures + glBindTexture) - else - glGenTextures(1, &texId); } LatteTextureView* LatteTextureGL::CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) @@ -80,6 +80,18 @@ LatteTextureView* LatteTextureGL::CreateView(Latte::E_DIM dim, Latte::E_GX2SURFF return new LatteTextureViewGL(this, dim, format, firstMip, mipCount, firstSlice, sliceCount); } +void LatteTextureGL::InitTextureState() +{ + // init texture with some default parameters (todo - this shouldn't be necessary if we properly set parameters when a texture is used) + catchOpenGLError(); + glTexParameteri(glTexTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(glTexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(glTexTarget, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(glTexTarget, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(glTexTarget, GL_TEXTURE_COMPARE_MODE, GL_NONE); + catchOpenGLError(); +} + void LatteTextureGL::GetOpenGLFormatInfo(bool isDepth, Latte::E_GX2SURFFMT format, Latte::E_DIM dim, FormatInfoGL* formatInfoOut) { formatInfoOut->isUsingAlternativeFormat = false; diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h b/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h index 9169bb29..fabd1bac 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h @@ -6,12 +6,14 @@ class LatteTextureGL : public LatteTexture { public: - LatteTextureGL(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, + LatteTextureGL(uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth); ~LatteTextureGL(); - static void GenerateEmptyTextureFromGX2Dim(Latte::E_DIM dim, GLuint& texId, GLint& texTarget, bool createForTargetType); + static void GenerateEmptyTextureFromGX2Dim(Latte::E_DIM dim, GLuint& texId, GLint& texTarget); + + void InitTextureState() override; protected: LatteTextureView* CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) override; diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp index 29085642..f33fd7ff 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp @@ -11,7 +11,7 @@ LatteTextureViewGL::LatteTextureViewGL(LatteTextureGL* texture, Latte::E_DIM dim firstSlice != 0 || firstMip != 0 || mipCount != texture->mipLevels || sliceCount != texture->depth || forceCreateNewTexId) { - LatteTextureGL::GenerateEmptyTextureFromGX2Dim(dim, glTexId, glTexTarget, false); + LatteTextureGL::GenerateEmptyTextureFromGX2Dim(dim, glTexId, glTexTarget); this->glInternalFormat = 0; InitAliasView(); } diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp index f09f04f1..5269be64 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp @@ -77,6 +77,8 @@ static const GLenum glAlphaTestFunc[] = GL_ALWAYS }; + + OpenGLRenderer::OpenGLRenderer() { glRendererState.useTextureUploadBuffer = false; @@ -273,6 +275,10 @@ void OpenGLRenderer::Initialize() cemuLog_log(LogType::Force, "ARB_copy_image: {}", (glCopyImageSubData != NULL) ? "available" : "not supported"); cemuLog_log(LogType::Force, "NV_depth_buffer_float: {}", (glDepthRangedNV != NULL) ? "available" : "not supported"); + // generate default frame buffer + glGenFramebuffers(1, &m_defaultFramebufferId); + catchOpenGLError(); + // enable framebuffer SRGB support glEnable(GL_FRAMEBUFFER_SRGB); @@ -560,16 +566,17 @@ void OpenGLRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu sint32 effectiveHeight; LatteTexture_getEffectiveSize(texView->baseTexture, &effectiveWidth, &effectiveHeight, nullptr, 0); - shader_unbind(RendererShader::ShaderType::kGeometry); - shader_bind(shader->GetVertexShader()); - shader_bind(shader->GetFragmentShader()); + g_renderer->shader_unbind(RendererShader::ShaderType::kVertex); + g_renderer->shader_unbind(RendererShader::ShaderType::kGeometry); + g_renderer->shader_unbind(RendererShader::ShaderType::kFragment); + shader->Bind(); shader->SetUniformParameters(*texView, { effectiveWidth, effectiveHeight }, { imageWidth, imageHeight }); // set viewport glViewportIndexedf(0, imageX, imageY, imageWidth, imageHeight); LatteTextureViewGL* texViewGL = (LatteTextureViewGL*)texView; - texture_bindAndActivate(texView, 0); + g_renderer->texture_bindAndActivate(texView, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, useLinearTexFilter ? GL_LINEAR : GL_NEAREST); texViewGL->samplerState.filterMag = 0xFFFFFFFF; @@ -584,7 +591,7 @@ void OpenGLRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu glEnable(GL_FRAMEBUFFER_SRGB); // unbind texture - texture_bindAndActivate(nullptr, 0); + g_renderer->texture_bindAndActivate(nullptr, 0); catchOpenGLError(); @@ -988,9 +995,8 @@ void OpenGLRenderer::texture_destroy(LatteTexture* hostTexture) delete hostTexture; } -void OpenGLRenderer::texture_reserveTextureOnGPU(LatteTexture* hostTextureGeneric) +void OpenGLRenderer::texture_reserveTextureOnGPU(LatteTexture* hostTexture) { - auto hostTexture = (LatteTextureGL*)hostTextureGeneric; cemu_assert_debug(hostTexture->isDataDefined == false); sint32 effectiveBaseWidth = hostTexture->width; sint32 effectiveBaseHeight = hostTexture->height; @@ -1011,25 +1017,25 @@ void OpenGLRenderer::texture_reserveTextureOnGPU(LatteTexture* hostTextureGeneri if (hostTexture->dim == Latte::E_DIM::DIM_2D || hostTexture->dim == Latte::E_DIM::DIM_2D_MSAA) { cemu_assert_debug(effectiveBaseDepth == 1); - glTextureStorage2DWrapper(GL_TEXTURE_2D, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight); + glTexStorage2D(GL_TEXTURE_2D, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight); } else if (hostTexture->dim == Latte::E_DIM::DIM_1D) { cemu_assert_debug(effectiveBaseHeight == 1); cemu_assert_debug(effectiveBaseDepth == 1); - glTextureStorage1DWrapper(GL_TEXTURE_1D, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth); + glTexStorage1D(GL_TEXTURE_1D, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth); } else if (hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY || hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA) { - glTextureStorage3DWrapper(GL_TEXTURE_2D_ARRAY, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth)); + glTexStorage3D(GL_TEXTURE_2D_ARRAY, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth)); } else if (hostTexture->dim == Latte::E_DIM::DIM_3D) { - glTextureStorage3DWrapper(GL_TEXTURE_3D, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth)); + glTexStorage3D(GL_TEXTURE_3D, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth)); } else if (hostTexture->dim == Latte::E_DIM::DIM_CUBEMAP) { - glTextureStorage3DWrapper(GL_TEXTURE_CUBE_MAP_ARRAY, hostTexture->glId_texture, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, effectiveBaseDepth); + glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mipLevels, glFormatInfo.glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, effectiveBaseDepth); } else { @@ -1041,6 +1047,7 @@ void OpenGLRenderer::texture_reserveTextureOnGPU(LatteTexture* hostTextureGeneri void OpenGLRenderer_texture_loadSlice_normal(LatteTexture* hostTextureGeneric, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 imageSize) { auto hostTexture = (LatteTextureGL*)hostTextureGeneric; + sint32 effectiveWidth = width; sint32 effectiveHeight = height; sint32 effectiveDepth = depth; @@ -1051,37 +1058,58 @@ void OpenGLRenderer_texture_loadSlice_normal(LatteTexture* hostTextureGeneric, s LatteTextureGL::GetOpenGLFormatInfo(hostTexture->isDepth, hostTexture->overwriteInfo.hasFormatOverwrite ? (Latte::E_GX2SURFFMT)hostTexture->overwriteInfo.format : hostTexture->format, hostTexture->dim, &glFormatInfo); // upload slice catchOpenGLError(); - if (mipIndex >= hostTexture->maxPossibleMipLevels) - { - cemuLog_logDebug(LogType::Force, "2D texture mip level allocated out of range"); - return; - } if (hostTexture->dim == Latte::E_DIM::DIM_2D || hostTexture->dim == Latte::E_DIM::DIM_2D_MSAA) { if (glFormatInfo.glIsCompressed) - glCompressedTextureSubImage2DWrapper(hostTexture->glTexTarget, hostTexture->glId_texture, mipIndex, 0, 0, effectiveWidth, effectiveHeight, glFormatInfo.glInternalFormat, imageSize, pixelData); + { + if (glCompressedTextureSubImage2D) + glCompressedTextureSubImage2D(hostTexture->glId_texture, mipIndex, 0, 0, effectiveWidth, effectiveHeight, glFormatInfo.glInternalFormat, imageSize, pixelData); + else + glCompressedTexSubImage2D(GL_TEXTURE_2D, mipIndex, 0, 0, effectiveWidth, effectiveHeight, glFormatInfo.glInternalFormat, imageSize, pixelData); + } else - glTextureSubImage2DWrapper(hostTexture->glTexTarget, hostTexture->glId_texture, mipIndex, 0, 0, effectiveWidth, effectiveHeight, glFormatInfo.glSuppliedFormat, glFormatInfo.glSuppliedFormatType, pixelData); + { + if (mipIndex < hostTexture->maxPossibleMipLevels) + glTexSubImage2D(GL_TEXTURE_2D, mipIndex, 0, 0, effectiveWidth, effectiveHeight, glFormatInfo.glSuppliedFormat, glFormatInfo.glSuppliedFormatType, pixelData); + else + cemuLog_logDebug(LogType::Force, "2D texture mip level allocated out of range"); + } } else if (hostTexture->dim == Latte::E_DIM::DIM_1D) { - if (glFormatInfo.glIsCompressed) - glCompressedTextureSubImage1DWrapper(hostTexture->glTexTarget, hostTexture->glId_texture, mipIndex, 0, width, glFormatInfo.glInternalFormat, imageSize, pixelData); - else - glTextureSubImage1DWrapper(hostTexture->glTexTarget, hostTexture->glId_texture, mipIndex, 0, width, glFormatInfo.glSuppliedFormat, glFormatInfo.glSuppliedFormatType, pixelData); + if (glFormatInfo.glIsCompressed == true) + cemu_assert_unimplemented(); + glTexSubImage1D(GL_TEXTURE_1D, mipIndex, 0, width, glFormatInfo.glSuppliedFormat, glFormatInfo.glSuppliedFormatType, pixelData); } - else if (hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY || hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA || - hostTexture->dim == Latte::E_DIM::DIM_3D || - hostTexture->dim == Latte::E_DIM::DIM_CUBEMAP) + else if (hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY || hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA) { if (glFormatInfo.glIsCompressed) - glCompressedTextureSubImage3DWrapper(hostTexture->glTexTarget, hostTexture->glId_texture, mipIndex, 0, 0, sliceIndex, effectiveWidth, effectiveHeight, 1, glFormatInfo.glInternalFormat, imageSize, pixelData); + glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, mipIndex, 0, 0, sliceIndex, effectiveWidth, effectiveHeight, 1, glFormatInfo.glInternalFormat, imageSize, pixelData); else - glTextureSubImage3DWrapper(hostTexture->glTexTarget, hostTexture->glId_texture, mipIndex, 0, 0, sliceIndex, effectiveWidth, effectiveHeight, 1, glFormatInfo.glSuppliedFormat, glFormatInfo.glSuppliedFormatType, pixelData); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, mipIndex, 0, 0, sliceIndex, effectiveWidth, effectiveHeight, 1, glFormatInfo.glSuppliedFormat, glFormatInfo.glSuppliedFormatType, pixelData); + } + else if (hostTexture->dim == Latte::E_DIM::DIM_3D) + { + if (glFormatInfo.glIsCompressed) + glCompressedTexSubImage3D(GL_TEXTURE_3D, mipIndex, 0, 0, sliceIndex, effectiveWidth, effectiveHeight, 1, glFormatInfo.glInternalFormat, imageSize, pixelData); + else + glTexSubImage3D(GL_TEXTURE_3D, mipIndex, 0, 0, sliceIndex, effectiveWidth, effectiveHeight, 1, glFormatInfo.glSuppliedFormat, glFormatInfo.glSuppliedFormatType, pixelData); + } + else if (hostTexture->dim == Latte::E_DIM::DIM_CUBEMAP) + { + if (glFormatInfo.glIsCompressed) + glCompressedTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mipIndex, 0, 0, sliceIndex, width, height, 1, glFormatInfo.glInternalFormat, imageSize, pixelData); + else + glTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mipIndex, 0, 0, sliceIndex, width, height, 1, glFormatInfo.glSuppliedFormat, glFormatInfo.glSuppliedFormatType, pixelData); + } + else + { + cemu_assert_debug(false); } catchOpenGLError(); } + // use persistent buffers to upload data void OpenGLRenderer_texture_loadSlice_viaBuffers(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 imageSize) { @@ -1197,10 +1225,10 @@ void OpenGLRenderer::texture_clearSlice(LatteTexture* hostTextureGeneric, sint32 glClearTexSubImage(hostTexture->glId_texture, mipIndex, 0, 0, sliceIndex, effectiveWidth, effectiveHeight, 1, formatInfoGL.glSuppliedFormat, formatInfoGL.glSuppliedFormatType, NULL); } -LatteTexture* OpenGLRenderer::texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, +LatteTexture* OpenGLRenderer::texture_createTextureEx(uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) { - return new LatteTextureGL(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth); + return new LatteTextureGL(textureUnit, dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth); } @@ -1216,18 +1244,42 @@ void OpenGLRenderer::texture_setActiveTextureUnit(sint32 index) void OpenGLRenderer::texture_bindAndActivate(LatteTextureView* textureView, uint32 textureUnit) { const auto textureViewGL = (LatteTextureViewGL*)textureView; + cemu_assert_debug(textureUnit < (sizeof(LatteBoundTexturesBackup) / sizeof(LatteBoundTexturesBackup[0]))); // don't call glBindTexture if the texture is already bound - if (m_latteBoundTextures[textureUnit] == textureViewGL) + if (LatteBoundTextures[textureUnit] == textureViewGL) { texture_setActiveTextureUnit(textureUnit); return; // already bound } // bind - m_latteBoundTextures[textureUnit] = textureViewGL; + LatteBoundTextures[textureUnit] = textureViewGL; texture_setActiveTextureUnit(textureUnit); if (textureViewGL) { glBindTexture(textureViewGL->glTexTarget, textureViewGL->glTexId); + texUnitTexId[textureUnit] = textureViewGL->glTexId; + texUnitTexTarget[textureUnit] = textureViewGL->glTexTarget; + } +} + +void OpenGLRenderer::texture_bindAndActivateRawTex(LatteTexture* texture, uint32 textureUnit) +{ + cemu_assert_debug(textureUnit < (sizeof(LatteBoundTexturesBackup) / sizeof(LatteBoundTexturesBackup[0]))); + // don't call glBindTexture if the texture is already bound + if (LatteBoundTextures[textureUnit] == texture) + { + texture_setActiveTextureUnit(textureUnit); + return; // already bound + } + // bind + LatteBoundTextures[textureUnit] = texture; + texture_setActiveTextureUnit(textureUnit); + if (texture) + { + auto textureGL = (LatteTextureGL*)texture; + glBindTexture(textureGL->glTexTarget, textureGL->glId_texture); + texUnitTexId[textureUnit] = textureGL->glId_texture; + texUnitTexTarget[textureUnit] = textureGL->glTexTarget; } } @@ -1235,18 +1287,18 @@ void OpenGLRenderer::texture_notifyDelete(LatteTextureView* textureView) { for (uint32 i = 0; i < Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3; i++) { - if (m_latteBoundTextures[i] == textureView) - m_latteBoundTextures[i] = nullptr; + if (LatteBoundTextures[i] == textureView) + LatteBoundTextures[i] = nullptr; } } -// set Latte texture, on the OpenGL renderer this behaves like _bindAndActivate() but doesn't call _setActiveTextureUnit() if the texture is already bound -void OpenGLRenderer::texture_setLatteTexture(LatteTextureView* textureView1, uint32 textureUnit) +// similar to _bindAndActivate() but doesn't call _setActiveTextureUnit() if texture is already bound +void OpenGLRenderer::texture_bindOnly(LatteTextureView* textureView1, uint32 textureUnit) { auto textureView = ((LatteTextureViewGL*)textureView1); cemu_assert_debug(textureUnit < Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3); - if (m_latteBoundTextures[textureUnit] == textureView) + if (LatteBoundTextures[textureUnit] == textureView) return; if (textureView == nullptr) return; @@ -1254,17 +1306,45 @@ void OpenGLRenderer::texture_setLatteTexture(LatteTextureView* textureView1, uin if (glBindTextureUnit) { glBindTextureUnit(textureUnit, textureView->glTexId); - m_latteBoundTextures[textureUnit] = textureView; + LatteBoundTextures[textureUnit] = textureView; + texUnitTexId[textureUnit] = textureView->glTexId; + texUnitTexTarget[textureUnit] = textureView->glTexTarget; activeTextureUnit = -1; } else { texture_setActiveTextureUnit(textureUnit); glBindTexture(textureView->glTexTarget, textureView->glTexId); - m_latteBoundTextures[textureUnit] = textureView; + LatteBoundTextures[textureUnit] = textureView; + texUnitTexId[textureUnit] = textureView->glTexId; + texUnitTexTarget[textureUnit] = textureView->glTexTarget; } } +void OpenGLRenderer::texture_rememberBoundTexture(uint32 textureUnit) +{ + cemu_assert_debug(texUnitBackupSlotUsed[textureUnit] == false); + texUnitBackupSlotUsed[textureUnit] = true; + LatteBoundTexturesBackup[textureUnit] = LatteBoundTextures[textureUnit]; + texUnitTexIdBackup[textureUnit] = texUnitTexId[textureUnit]; + texUnitTexTargetBackup[textureUnit] = texUnitTexTarget[textureUnit]; +} + +void OpenGLRenderer::texture_restoreBoundTexture(uint32 textureUnit) +{ + cemu_assert_debug(texUnitBackupSlotUsed[textureUnit] == true); + texUnitBackupSlotUsed[textureUnit] = false; + if (LatteBoundTextures[textureUnit] == LatteBoundTexturesBackup[textureUnit]) + { + return; // already bound + } + LatteBoundTextures[textureUnit] = LatteBoundTexturesBackup[textureUnit]; + texUnitTexId[textureUnit] = texUnitTexIdBackup[textureUnit]; + texUnitTexTarget[textureUnit] = texUnitTexTargetBackup[textureUnit]; + texture_setActiveTextureUnit(textureUnit); + glBindTexture(texUnitTexTargetBackup[textureUnit], texUnitTexIdBackup[textureUnit]); +} + void OpenGLRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth) { @@ -1353,25 +1433,31 @@ RendererShader* OpenGLRenderer::shader_create(RendererShader::ShaderType type, u void OpenGLRenderer::shader_bind(RendererShader* shader) { auto shaderGL = (RendererShaderGL*)shader; + GLbitfield shaderBit; + const auto program = shaderGL->GetProgram(); + switch(shader->GetType()) { case RendererShader::ShaderType::kVertex: if (program == prevVertexShaderProgram) return; + shaderBit = GL_VERTEX_SHADER_BIT; prevVertexShaderProgram = program; break; case RendererShader::ShaderType::kFragment: if (program == prevPixelShaderProgram) return; + shaderBit = GL_FRAGMENT_SHADER_BIT; prevPixelShaderProgram = program; break; case RendererShader::ShaderType::kGeometry: if (program == prevGeometryShaderProgram) return; + shaderBit = GL_GEOMETRY_SHADER_BIT; prevGeometryShaderProgram = program; break; @@ -1384,6 +1470,13 @@ void OpenGLRenderer::shader_bind(RendererShader* shader) catchOpenGLError(); } +void OpenGLRenderer::shader_bind(GLuint program, GLbitfield shaderType) +{ + catchOpenGLError(); + glUseProgramStages(m_pipeline, shaderType, program); + catchOpenGLError(); +} + void OpenGLRenderer::shader_unbind(RendererShader::ShaderType shaderType) { switch (shaderType) { diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h index 8a4b1a1d..600985ff 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h @@ -79,10 +79,13 @@ public: void texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) override; void texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) override; - LatteTexture* texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) override; + LatteTexture* texture_createTextureEx(uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) override; - void texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) override; - void texture_bindAndActivate(LatteTextureView* textureView, uint32 textureUnit); + void texture_bindAndActivate(LatteTextureView* textureView, uint32 textureUnit) override; + void texture_bindAndActivateRawTex(LatteTexture* texture, uint32 textureUnit) override; + void texture_bindOnly(LatteTextureView* textureView, uint32 textureUnit) override; + void texture_rememberBoundTexture(uint32 textureUnit) override; + void texture_restoreBoundTexture(uint32 textureUnit) override; void texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth) override; void texture_notifyDelete(LatteTextureView* textureView); @@ -124,8 +127,9 @@ public: // shader RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool isGameShader, bool isGfxPackShader) override; - void shader_bind(RendererShader* shader); - void shader_unbind(RendererShader::ShaderType shaderType); + void shader_bind(RendererShader* shader) override; + void shader_bind(GLuint program, GLbitfield shaderType); + void shader_unbind(RendererShader::ShaderType shaderType) override; // streamout void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override; @@ -161,6 +165,7 @@ private: void texture_syncSliceSpecialBC4(LatteTexture* srcTexture, sint32 srcSliceIndex, sint32 srcMipIndex, LatteTexture* dstTexture, sint32 dstSliceIndex, sint32 dstMipIndex); void texture_syncSliceSpecialIntegerToBC3(LatteTexture* srcTexture, sint32 srcSliceIndex, sint32 srcMipIndex, LatteTexture* dstTexture, sint32 dstSliceIndex, sint32 dstMipIndex); + GLuint m_defaultFramebufferId; GLuint m_pipeline = 0; bool m_isPadViewContext{}; @@ -185,7 +190,14 @@ private: bool m_isXfbActive = false; sint32 activeTextureUnit = 0; - void* m_latteBoundTextures[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3]{}; + void* LatteBoundTextures[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3]{}; + GLuint texUnitTexId[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3]{}; + GLenum texUnitTexTarget[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3]{}; + + void* LatteBoundTexturesBackup[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3]{}; + GLuint texUnitTexIdBackup[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3]{}; + GLenum texUnitTexTargetBackup[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3]{}; + bool texUnitBackupSlotUsed[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3]{}; // attribute stream GLuint glAttributeCacheAB{}; @@ -204,6 +216,8 @@ private: uint32 prevLogicOp = 0; uint32 prevBlendColorConstant[4] = { 0 }; uint8 prevAlphaTestEnable = 0; + uint8 prevAlphaTestFunc = 0; + uint32 prevAlphaTestRefU32 = 0; bool prevDepthEnable = 0; bool prevDepthWriteEnable = 0; Latte::LATTE_DB_DEPTH_CONTROL::E_ZFUNC prevDepthFunc = (Latte::LATTE_DB_DEPTH_CONTROL::E_ZFUNC)-1; @@ -249,9 +263,9 @@ private: std::vector list_queryCacheOcclusion; // cache for unused queries // resource garbage collection - struct BufferCacheReleaseQueueEntry + struct bufferCacheReleaseQueueEntry_t { - BufferCacheReleaseQueueEntry(VirtualBufferHeap_t* heap, VirtualBufferHeapEntry_t* entry) : m_heap(heap), m_entry(entry) {}; + bufferCacheReleaseQueueEntry_t(VirtualBufferHeap_t* heap, VirtualBufferHeapEntry_t* entry) : m_heap(heap), m_entry(entry) {}; void free() { @@ -265,7 +279,7 @@ private: struct { sint32 index; - std::vector bufferCacheEntries; + std::vector bufferCacheEntries; }m_destructionQueues; }; diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp index 51d0d206..d5cec237 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp @@ -912,21 +912,6 @@ void OpenGLRenderer::draw_genericDrawHandler(uint32 baseVertex, uint32 baseInsta { beginPerfMonProfiling(performanceMonitor.gpuTime_dcStageShaderAndUniformMgr); LatteSHRC_UpdateActiveShaders(); - LatteDecompilerShader* vs = (LatteDecompilerShader*)LatteSHRC_GetActiveVertexShader(); - LatteDecompilerShader* gs = (LatteDecompilerShader*)LatteSHRC_GetActiveGeometryShader(); - LatteDecompilerShader* ps = (LatteDecompilerShader*)LatteSHRC_GetActivePixelShader(); - if (vs) - shader_bind(vs->shader); - else - shader_unbind(RendererShader::ShaderType::kVertex); - if (ps && LatteGPUState.contextRegister[mmVGT_STRMOUT_EN] == 0) - shader_bind(ps->shader); - else - shader_unbind(RendererShader::ShaderType::kFragment); - if (gs) - shader_bind(gs->shader); - else - shader_unbind(RendererShader::ShaderType::kGeometry); endPerfMonProfiling(performanceMonitor.gpuTime_dcStageShaderAndUniformMgr); } if (LatteGPUState.activeShaderHasError) @@ -1342,7 +1327,7 @@ uint32 _correctTextureCompSelGL(Latte::E_GX2SURFFMT format, uint32 compSel) return compSel; } -#define quickBindTexture() if( textureIsActive == false ) { texture_bindAndActivate(hostTextureView, hostTextureUnit); textureIsActive = true; } +#define quickBindTexture() if( textureIsActive == false ) { g_renderer->texture_bindAndActivate(hostTextureView, hostTextureUnit); textureIsActive = true; } uint32 _getGLMinFilter(Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER filterMin, Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER filterMip) { @@ -1365,9 +1350,11 @@ uint32 _getGLMinFilter(Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER filterMi /* * Update channel swizzling and other texture settings for a texture unit * hostTextureView is the texture unit view used on the host side +* The baseGX2TexUnit parameter is used to identify the shader stage in which this texture is accessed */ void OpenGLRenderer::renderstate_updateTextureSettingsGL(LatteDecompilerShader* shaderContext, LatteTextureView* _hostTextureView, uint32 hostTextureUnit, const Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N texUnitWord4, uint32 texUnitIndex, bool isDepthSampler) { + // todo - this is OpenGL-specific, decouple this from the renderer-neutral backend auto hostTextureView = (LatteTextureViewGL*)_hostTextureView; LatteTexture* baseTexture = hostTextureView->baseTexture; diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLSurfaceCopy.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLSurfaceCopy.cpp index c49a57e4..8c8c36d7 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLSurfaceCopy.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLSurfaceCopy.cpp @@ -52,7 +52,7 @@ void OpenGLRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* s LatteTextureView* sourceView = sourceTexture->GetOrCreateView(srcMip, 1, srcSlice, 1); LatteTextureView* destinationView = destinationTexture->GetOrCreateView(dstMip, 1, dstSlice, 1); - texture_bindAndActivate(sourceView, 0); + g_renderer->texture_bindAndActivate(sourceView, 0); catchOpenGLError(); // setup texture attributes _setDepthCompareMode((LatteTextureViewGL*)sourceView, 0); diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp index 3d46f206..5530b4ec 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp @@ -230,6 +230,11 @@ sint32 RendererShaderGL::GetUniformLocation(const char* name) return glGetUniformLocation(m_program, name); } +void RendererShaderGL::SetUniform1iv(sint32 location, void* data, sint32 count) +{ + glProgramUniform1iv(m_program, location, count, (const GLint*)data); +} + void RendererShaderGL::SetUniform2fv(sint32 location, void* data, sint32 count) { glProgramUniform2fv(m_program, location, count, (const GLfloat*)data); diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h index 60c51cc1..abc62358 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h @@ -18,6 +18,7 @@ public: GLuint GetShaderObject() const { cemu_assert_debug(m_isCompiled); return m_shader_object; } sint32 GetUniformLocation(const char* name) override; + void SetUniform1iv(sint32 location, void* data, sint32 count) override; void SetUniform2fv(sint32 location, void* data, sint32 count) override; void SetUniform4iv(sint32 location, void* data, sint32 count) override; diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/TextureReadbackGL.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/TextureReadbackGL.cpp index b2966706..56011dab 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/TextureReadbackGL.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/TextureReadbackGL.cpp @@ -1,5 +1,4 @@ #include "Cafe/HW/Latte/Renderer/Renderer.h" -#include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h" #include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLTextureReadback.h" #include "Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h" @@ -94,7 +93,8 @@ LatteTextureReadbackInfoGL::~LatteTextureReadbackInfoGL() void LatteTextureReadbackInfoGL::StartTransfer() { cemu_assert(m_textureView); - ((OpenGLRenderer*)g_renderer.get())->texture_bindAndActivate(m_textureView, 0); + + g_renderer->texture_bindAndActivate(m_textureView, 0); // create unsynchronized buffer glGenBuffers(1, &texImageBufferGL); glBindBuffer(GL_PIXEL_PACK_BUFFER, texImageBufferGL); diff --git a/src/Cafe/HW/Latte/Renderer/Renderer.h b/src/Cafe/HW/Latte/Renderer/Renderer.h index 93edaf8d..61ff10c8 100644 --- a/src/Cafe/HW/Latte/Renderer/Renderer.h +++ b/src/Cafe/HW/Latte/Renderer/Renderer.h @@ -110,9 +110,13 @@ public: virtual void texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) = 0; virtual void texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) = 0; - virtual LatteTexture* texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) = 0; + virtual LatteTexture* texture_createTextureEx(uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) = 0; - virtual void texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) = 0; + virtual void texture_bindAndActivate(LatteTextureView* textureView, uint32 textureUnit) = 0; + virtual void texture_bindAndActivateRawTex(LatteTexture* texture, uint32 textureUnit) = 0; + virtual void texture_bindOnly(LatteTextureView* textureView, uint32 textureUnit) = 0; + virtual void texture_rememberBoundTexture(uint32 textureUnit) = 0; + virtual void texture_restoreBoundTexture(uint32 textureUnit) = 0; virtual void texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth) = 0; virtual LatteTextureReadbackInfo* texture_createReadback(LatteTextureView* textureView) = 0; @@ -131,6 +135,8 @@ public: // shader virtual RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool compileAsync, bool isGfxPackSource) = 0; + virtual void shader_bind(RendererShader* shader) = 0; + virtual void shader_unbind(RendererShader::ShaderType shaderType) = 0; // streamout virtual void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) = 0; diff --git a/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp b/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp index cdbeb3f3..ae528944 100644 --- a/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp +++ b/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp @@ -233,6 +233,12 @@ void RendererOutputShader::SetUniformParameters(const LatteTextureView& texture_ } } +void RendererOutputShader::Bind() const +{ + g_renderer->shader_bind(m_vertex_shader); + g_renderer->shader_bind(m_fragment_shader); +} + RendererOutputShader* RendererOutputShader::s_copy_shader; RendererOutputShader* RendererOutputShader::s_copy_shader_ud; diff --git a/src/Cafe/HW/Latte/Renderer/RendererOuputShader.h b/src/Cafe/HW/Latte/Renderer/RendererOuputShader.h index 398ac663..253990e2 100644 --- a/src/Cafe/HW/Latte/Renderer/RendererOuputShader.h +++ b/src/Cafe/HW/Latte/Renderer/RendererOuputShader.h @@ -18,6 +18,7 @@ public: virtual ~RendererOutputShader() = default; void SetUniformParameters(const LatteTextureView& texture_view, const Vector2i& input_res, const Vector2i& output_res) const; + void Bind() const; RendererShader* GetVertexShader() const { diff --git a/src/Cafe/HW/Latte/Renderer/RendererShader.h b/src/Cafe/HW/Latte/Renderer/RendererShader.h index e3f254c6..1c15211f 100644 --- a/src/Cafe/HW/Latte/Renderer/RendererShader.h +++ b/src/Cafe/HW/Latte/Renderer/RendererShader.h @@ -19,7 +19,8 @@ public: virtual bool WaitForCompiled() = 0; virtual sint32 GetUniformLocation(const char* name) = 0; - + + virtual void SetUniform1iv(sint32 location, void* data, sint32 count) = 0; virtual void SetUniform2fv(sint32 location, void* data, sint32 count) = 0; virtual void SetUniform4iv(sint32 location, void* data, sint32 count) = 0; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.cpp index b5f62707..b41760bc 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.cpp @@ -3,9 +3,9 @@ #include "Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h" #include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h" -LatteTextureVk::LatteTextureVk(class VulkanRenderer* vkRenderer, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, +LatteTextureVk::LatteTextureVk(class VulkanRenderer* vkRenderer, uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) - : LatteTexture(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth), m_vkr(vkRenderer) + : LatteTexture(textureUnit, dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth), m_vkr(vkRenderer) { vkObjTex = new VKRObjectTexture(); diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h b/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h index 714c4e17..2131ed9c 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h @@ -9,7 +9,7 @@ class LatteTextureVk : public LatteTexture { public: - LatteTextureVk(class VulkanRenderer* vkRenderer, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, + LatteTextureVk(class VulkanRenderer* vkRenderer, uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth); ~LatteTextureVk(); diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp index 970f5517..e4c87d62 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp @@ -139,7 +139,7 @@ public: } } - void StopThreads() + ~_ShaderVkThreadPool() { m_shutdownThread.store(true); for (uint32 i = 0; i < s_threads.size(); ++i) @@ -149,11 +149,6 @@ public: s_threads.clear(); } - ~_ShaderVkThreadPool() - { - StopThreads(); - } - void CompilerThreadFunc() { while (!m_shutdownThread.load(std::memory_order::relaxed)) @@ -181,8 +176,6 @@ public: } } - bool HasThreadsRunning() const { return !m_shutdownThread; } - public: std::vector s_threads; @@ -202,8 +195,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() @@ -211,22 +204,17 @@ 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(); return 0; } +void RendererShaderVk::SetUniform1iv(sint32 location, void* data, sint32 count) +{ + cemu_assert_suspicious(); +} + void RendererShaderVk::SetUniform2fv(sint32 location, void* data, sint32 count) { cemu_assert_suspicious(); @@ -469,4 +457,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 f9c3ede1..561145f9 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h @@ -28,10 +28,8 @@ public: 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; void SetUniform4iv(sint32 location, void* data, sint32 count) override; VkShaderModule& GetShaderModule() { return m_shader_module; } diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 44214606..052ca21a 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -591,9 +591,6 @@ 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() @@ -601,8 +598,6 @@ 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(); @@ -1090,6 +1085,17 @@ RendererShader* VulkanRenderer::shader_create(RendererShader::ShaderType type, u return new RendererShaderVk(type, baseHash, auxHash, isGameShader, isGfxPackShader, source); } +void VulkanRenderer::shader_bind(RendererShader* shader) +{ + // does nothing on Vulkan + // remove from main render backend and internalize into GL backend +} + +void VulkanRenderer::shader_unbind(RendererShader::ShaderType shaderType) +{ + // does nothing on Vulkan +} + bool VulkanRenderer::CheckDeviceExtensionSupport(const VkPhysicalDevice device, FeatureControl& info) { std::vector availableDeviceExtensions; @@ -3326,13 +3332,18 @@ void VulkanRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, barrier_image(vkTexture, barrierSubresourceRange, VK_IMAGE_LAYOUT_GENERAL); } -LatteTexture* VulkanRenderer::texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, +LatteTexture* VulkanRenderer::texture_createTextureEx(uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) { - return new LatteTextureVk(this, dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth); + return new LatteTextureVk(this, textureUnit, dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth); } -void VulkanRenderer::texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) +void VulkanRenderer::texture_bindAndActivate(LatteTextureView* textureView, uint32 textureUnit) +{ + m_state.boundTexture[textureUnit] = static_cast(textureView); +} + +void VulkanRenderer::texture_bindOnly(LatteTextureView* textureView, uint32 textureUnit) { m_state.boundTexture[textureUnit] = static_cast(textureView); } diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h index b61a0b40..3d68f844 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h @@ -300,10 +300,15 @@ public: void texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) override; - LatteTexture* texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) override; + LatteTexture* texture_createTextureEx(uint32 textureUnit, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) override; - void texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) override; + void texture_bindAndActivate(LatteTextureView* textureView, uint32 textureUnit) override; + void texture_bindOnly(LatteTextureView* textureView, uint32 textureUnit) override; + void texture_bindAndActivateRawTex(LatteTexture* texture, uint32 textureUnit) override {}; + + void texture_rememberBoundTexture(uint32 textureUnit) override {}; + void texture_restoreBoundTexture(uint32 textureUnit) override {}; void texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth) override; LatteTextureReadbackInfo* texture_createReadback(LatteTextureView* textureView) override; @@ -345,6 +350,8 @@ public: void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override; RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool isGameShader, bool isGfxPackShader) override; + void shader_bind(RendererShader* shader) override; + void shader_unbind(RendererShader::ShaderType shaderType) override; void* indexData_reserveIndexMemory(uint32 size, uint32& offset, uint32& bufferIndex) override; void indexData_uploadIndexMemory(uint32 offset, uint32 size) override; diff --git a/src/Cafe/IOSU/PDM/iosu_pdm.cpp b/src/Cafe/IOSU/PDM/iosu_pdm.cpp index e54529a9..45b4a1d8 100644 --- a/src/Cafe/IOSU/PDM/iosu_pdm.cpp +++ b/src/Cafe/IOSU/PDM/iosu_pdm.cpp @@ -1,5 +1,4 @@ #include "iosu_pdm.h" -#include "Cafe/CafeSystem.h" #include "config/ActiveSettings.h" #include "Common/FileStream.h" #include "util/helpers/Semaphore.h" @@ -18,8 +17,7 @@ namespace iosu { namespace pdm { - std::recursive_mutex sPlaystatsLock; - std::recursive_mutex sDiaryLock; + std::mutex sDiaryLock; fs::path GetPDFile(const char* filename) { @@ -82,16 +80,14 @@ namespace iosu static_assert((NUM_PLAY_STATS_ENTRIES * sizeof(PlayStatsEntry)) == 0x1400); } - void OpenPlaystats() + void LoadPlaystats() { - 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) { @@ -102,39 +98,18 @@ namespace iosu { delete PlayStats.fs; PlayStats.fs = nullptr; - cemuLog_log(LogType::Force, "PlayStats.dat malformed. Time tracking wont be used"); + cemuLog_log(LogType::Force, "PlayStats.dat malformed"); // 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; @@ -146,7 +121,7 @@ namespace iosu return nullptr; } - void PlayStats_WriteEntryNoLock(PlayStatsEntry* entry, bool writeEntryCount = false) + void PlayStats_WriteEntry(PlayStatsEntry* entry, bool writeEntryCount = false) { if (!PlayStats.fs) return; @@ -166,15 +141,8 @@ 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) @@ -200,7 +168,7 @@ namespace iosu newEntry->numTimesLaunched = 1; newEntry->totalMinutesPlayed = 0; newEntry->ukn12 = 0; - PlayStats_WriteEntryNoLock(newEntry, entryCountChanged); + PlayStats_WriteEntry(newEntry, entryCountChanged); return newEntry; } @@ -208,7 +176,6 @@ 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) { @@ -222,12 +189,11 @@ 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_WriteEntryNoLock(entry); + PlayStats_WriteEntry(entry); } struct PlayDiaryHeader @@ -252,7 +218,6 @@ namespace iosu void CreatePlayDiary() { MakeDirectory(); - cemu_assert_debug(!PlayDiaryData.fs); PlayDiaryData.fs = FileStream::createFile2(GetPDFile("PlayDiary.dat")); if (!PlayDiaryData.fs) { @@ -265,7 +230,7 @@ namespace iosu PlayDiaryData.fs->writeData(&PlayDiaryData.header, sizeof(PlayDiaryHeader)); } - void OpenPlayDiary() + void LoadPlayDiary() { std::unique_lock _lock(sDiaryLock); cemu_assert_debug(!PlayDiaryData.fs); @@ -303,26 +268,6 @@ 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); @@ -407,59 +352,25 @@ namespace iosu } } - class : public ::IOSUModule + void Initialize() { - 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; - - IOSUModule* GetModule() + // todo - add support for per-account handling + LoadPlaystats(); + LoadPlayDiary(); + } + + void StartTrackingTime(uint64 titleId) { - return static_cast(&sIOSUModuleNNPDM); + sPDMRequestExitThread = false; + sPDMTimeTrackingThread = std::thread(TimeTrackingThread, titleId); + } + + void Stop() + { + sPDMRequestExitThread.store(true); + sPDMSem.increment(); + if(sPDMTimeTrackingThread.joinable()) + sPDMTimeTrackingThread.join(); } }; diff --git a/src/Cafe/IOSU/PDM/iosu_pdm.h b/src/Cafe/IOSU/PDM/iosu_pdm.h index 0dd8a39d..fbafbc02 100644 --- a/src/Cafe/IOSU/PDM/iosu_pdm.h +++ b/src/Cafe/IOSU/PDM/iosu_pdm.h @@ -1,10 +1,13 @@ #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 @@ -31,7 +34,5 @@ namespace iosu }; bool GetStatForGamelist(uint64 titleId, GameListStat& stat); - - IOSUModule* GetModule(); }; }; \ No newline at end of file diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.h b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.h index 2c53f118..16ebd29a 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.h +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.h @@ -256,8 +256,10 @@ namespace nn this->flags = 0; memset(this->titleText, 0, sizeof(this->titleText)); memset(this->description, 0, sizeof(this->description)); - for (int i = 0; i < 5; i++) - memset(this->searchKeys[i], 0, sizeof(this->searchKeys[0])); + int v2 = 0; + do + memset(this->searchKeys[v2++], 0, sizeof(this->searchKeys[v2++])); + while (v2 < 5); } static UploadCommunityDataParam* __ctor(UploadCommunityDataParam* _this) { diff --git a/src/Cafe/OS/libs/nsysnet/nsysnet.cpp b/src/Cafe/OS/libs/nsysnet/nsysnet.cpp index 128c19a5..e0224148 100644 --- a/src/Cafe/OS/libs/nsysnet/nsysnet.cpp +++ b/src/Cafe/OS/libs/nsysnet/nsysnet.cpp @@ -13,7 +13,6 @@ #define WSAESHUTDOWN ESHUTDOWN #define WSAECONNABORTED ECONNABORTED #define WSAHOST_NOT_FOUND EAI_NONAME -#define WSAENOTCONN ENOTCONN #define GETLASTERR errno @@ -41,7 +40,6 @@ #define WU_SO_RCVBUF 0x1002 #define WU_SO_LASTERROR 0x1007 #define WU_SO_NBIO 0x1014 -#define WU_SO_BIO 0x1015 #define WU_SO_NONBLOCK 0x1016 #define WU_TCP_NODELAY 0x2004 @@ -55,7 +53,6 @@ #define WU_SO_SUCCESS 0x0000 #define WU_SO_EWOULDBLOCK 0x0006 #define WU_SO_ECONNRESET 0x0008 -#define WU_SO_ENOTCONN 0x0009 #define WU_SO_EINVAL 0x000B #define WU_SO_EINPROGRESS 0x0016 #define WU_SO_EAFNOSUPPORT 0x0021 @@ -151,11 +148,8 @@ sint32 _translateError(sint32 returnCode, sint32 wsaError, sint32 mode = _ERROR_ case WSAESHUTDOWN: _setSockError(WU_SO_ESHUTDOWN); break; - case WSAENOTCONN: - _setSockError(WU_SO_ENOTCONN); - break; default: - cemuLog_logDebug(LogType::Force, "Unhandled wsaError {}", wsaError); + cemuLog_logDebug(LogType::Force, "Unhandled wsaError {}\n", wsaError); _setSockError(99999); // unhandled error } return -1; @@ -163,7 +157,7 @@ sint32 _translateError(sint32 returnCode, sint32 wsaError, sint32 mode = _ERROR_ void nsysnetExport_socketlasterr(PPCInterpreter_t* hCPU) { - cemuLog_logDebug(LogType::Socket, "socketlasterr() -> {}", _getSockError()); + cemuLog_log(LogType::Socket, "socketlasterr() -> {}", _getSockError()); osLib_returnFromFunction(hCPU, _getSockError()); } @@ -491,9 +485,9 @@ void nsysnetExport_setsockopt(PPCInterpreter_t* hCPU) if (r != 0) cemu_assert_suspicious(); } - else if (optname == WU_SO_NBIO || optname == WU_SO_BIO) + else if (optname == WU_SO_NBIO) { - // similar to WU_SO_NONBLOCK but always sets blocking (_BIO) or non-blocking (_NBIO) mode regardless of option value + // similar to WU_SO_NONBLOCK but always sets non-blocking mode regardless of option value if (optlen == 4) { sint32 optvalLE = _swapEndianU32(*(uint32*)optval); @@ -504,10 +498,9 @@ void nsysnetExport_setsockopt(PPCInterpreter_t* hCPU) } else cemu_assert_suspicious(); - bool setNonBlocking = optname == WU_SO_NBIO; - u_long mode = setNonBlocking ? 1 : 0; + u_long mode = 1; _socket_nonblock(vs->s, mode); - vs->isNonBlocking = setNonBlocking; + vs->isNonBlocking = true; } else if (optname == WU_SO_NONBLOCK) { diff --git a/src/Common/GLInclude/GLInclude.h b/src/Common/GLInclude/GLInclude.h index bf7a6bf8..6f5d33db 100644 --- a/src/Common/GLInclude/GLInclude.h +++ b/src/Common/GLInclude/GLInclude.h @@ -42,177 +42,6 @@ typedef struct __GLXFBConfigRec *GLXFBConfig; #undef GLFUNC #undef EGLFUNC -// DSA-style helpers with fallback to legacy API if DSA is not supported - -#define DSA_FORCE_DISABLE false // set to true to simulate DSA not being supported - -static GLenum GetGLBindingFromTextureTarget(GLenum texTarget) -{ - switch(texTarget) - { - case GL_TEXTURE_1D: return GL_TEXTURE_BINDING_1D; - case GL_TEXTURE_2D: return GL_TEXTURE_BINDING_2D; - case GL_TEXTURE_3D: return GL_TEXTURE_BINDING_3D; - case GL_TEXTURE_2D_ARRAY: return GL_TEXTURE_BINDING_2D_ARRAY; - case GL_TEXTURE_CUBE_MAP: return GL_TEXTURE_BINDING_CUBE_MAP; - case GL_TEXTURE_CUBE_MAP_ARRAY: return GL_TEXTURE_BINDING_CUBE_MAP_ARRAY; - default: - cemu_assert_unimplemented(); - return 0; - } -} - -static GLuint glCreateTextureWrapper(GLenum target) -{ - GLuint tex; - if (glCreateTextures && !DSA_FORCE_DISABLE) - { - glCreateTextures(target, 1, &tex); - return tex; - } - GLint originalTexture; - glGetIntegerv(GetGLBindingFromTextureTarget(target), &originalTexture); - glGenTextures(1, &tex); - glBindTexture(target, tex); - glBindTexture(target, originalTexture); - return tex; -} - -static void glTextureStorage1DWrapper(GLenum target, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width) -{ - if (glTextureStorage1D && !DSA_FORCE_DISABLE) - { - glTextureStorage1D(texture, levels, internalformat, width); - return; - } - GLenum binding = GetGLBindingFromTextureTarget(target); - GLint originalTexture; - glGetIntegerv(binding, &originalTexture); - glBindTexture(target, texture); - glTexStorage1D(target, levels, internalformat, width); - glBindTexture(target, originalTexture); -} - -static void glTextureStorage2DWrapper(GLenum target, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) -{ - if (glTextureStorage2D && !DSA_FORCE_DISABLE) - { - glTextureStorage2D(texture, levels, internalformat, width, height); - return; - } - GLenum binding = GetGLBindingFromTextureTarget(target); - GLint originalTexture; - glGetIntegerv(binding, &originalTexture); - glBindTexture(target, texture); - glTexStorage2D(target, levels, internalformat, width, height); - glBindTexture(target, originalTexture); -} - -static void glTextureStorage3DWrapper(GLenum target, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) -{ - if (glTextureStorage3D && !DSA_FORCE_DISABLE) - { - glTextureStorage3D(texture, levels, internalformat, width, height, depth); - return; - } - GLenum binding = GetGLBindingFromTextureTarget(target); - GLint originalTexture; - glGetIntegerv(binding, &originalTexture); - glBindTexture(target, texture); - glTexStorage3D(target, levels, internalformat, width, height, depth); - glBindTexture(target, originalTexture); -} - -static void glTextureSubImage1DWrapper(GLenum target, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels) -{ - if (glTextureSubImage1D && !DSA_FORCE_DISABLE) - { - glTextureSubImage1D(texture, level, xoffset, width, format, type, pixels); - return; - } - GLenum binding = GetGLBindingFromTextureTarget(target); - GLint originalTexture; - glGetIntegerv(binding, &originalTexture); - glBindTexture(target, texture); - glTexSubImage1D(target, level, xoffset, width, format, type, pixels); - glBindTexture(target, originalTexture); -} - -static void glCompressedTextureSubImage1DWrapper(GLenum target, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data) -{ - if (glCompressedTextureSubImage1D && !DSA_FORCE_DISABLE) - { - glCompressedTextureSubImage1D(texture, level, xoffset, width, format, imageSize, data); - return; - } - GLenum binding = GetGLBindingFromTextureTarget(target); - GLint originalTexture; - glGetIntegerv(binding, &originalTexture); - glBindTexture(target, texture); - glCompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, data); - glBindTexture(target, originalTexture); -} - -static void glTextureSubImage2DWrapper(GLenum target, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) -{ - if (glTextureSubImage2D && !DSA_FORCE_DISABLE) - { - glTextureSubImage2D(texture, level, xoffset, yoffset, width, height, format, type, pixels); - return; - } - GLenum binding = GetGLBindingFromTextureTarget(target); - GLint originalTexture; - glGetIntegerv(binding, &originalTexture); - glBindTexture(target, texture); - glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); - glBindTexture(target, originalTexture); -} - -static void glCompressedTextureSubImage2DWrapper(GLenum target, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) -{ - if (glCompressedTextureSubImage2D && !DSA_FORCE_DISABLE) - { - glCompressedTextureSubImage2D(texture, level, xoffset, yoffset, width, height, format, imageSize, data); - return; - } - GLenum binding = GetGLBindingFromTextureTarget(target); - GLint originalTexture; - glGetIntegerv(binding, &originalTexture); - glBindTexture(target, texture); - glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); - glBindTexture(target, originalTexture); -} - -static void glTextureSubImage3DWrapper(GLenum target, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) -{ - if(glTextureSubImage3D && !DSA_FORCE_DISABLE) - { - glTextureSubImage3D(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); - return; - } - GLenum binding = GetGLBindingFromTextureTarget(target); - GLint originalTexture; - glGetIntegerv(binding, &originalTexture); - glBindTexture(target, texture); - glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); - glBindTexture(target, originalTexture); -} - -static void glCompressedTextureSubImage3DWrapper(GLenum target, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data) -{ - if(glCompressedTextureSubImage3D && !DSA_FORCE_DISABLE) - { - glCompressedTextureSubImage3D(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); - return; - } - GLenum binding = GetGLBindingFromTextureTarget(target); - GLint originalTexture; - glGetIntegerv(binding, &originalTexture); - glBindTexture(target, texture); - glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); - glBindTexture(target, originalTexture); -} - // this prevents Windows GL.h from being included: #define __gl_h_ #define __GL_H__ diff --git a/src/Common/GLInclude/glFunctions.h b/src/Common/GLInclude/glFunctions.h index 76308fdb..4cf25a6b 100644 --- a/src/Common/GLInclude/glFunctions.h +++ b/src/Common/GLInclude/glFunctions.h @@ -171,13 +171,10 @@ GLFUNC(PFNGLTEXSTORAGE2DPROC, glTexStorage2D) GLFUNC(PFNGLTEXSTORAGE3DPROC, glTexStorage3D) GLFUNC(PFNGLTEXIMAGE3DPROC, glTexImage3D) GLFUNC(PFNGLTEXSUBIMAGE3DPROC, glTexSubImage3D) -GLFUNC(PFNGLCOMPRESSEDTEXIMAGE1DPROC, glCompressedTexImage1D) GLFUNC(PFNGLCOMPRESSEDTEXIMAGE2DPROC, glCompressedTexImage2D) GLFUNC(PFNGLCOMPRESSEDTEXIMAGE3DPROC, glCompressedTexImage3D) -GLFUNC(PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC, glCompressedTexSubImage1D) GLFUNC(PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC, glCompressedTexSubImage2D) GLFUNC(PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC, glCompressedTexSubImage3D) -GLFUNC(PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC, glCompressedTextureSubImage1D) GLFUNC(PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC, glCompressedTextureSubImage2D) GLFUNC(PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC, glCompressedTextureSubImage3D) GLFUNC(PFNGLCOPYIMAGESUBDATAPROC, glCopyImageSubData) @@ -187,17 +184,12 @@ GLFUNC(PFNGLINVALIDATETEXIMAGEPROC, glInvalidateTexImage) // texture DSA -GLFUNC(PFNGLCREATETEXTURESPROC, glCreateTextures) GLFUNC(PFNGLBINDTEXTUREUNITPROC, glBindTextureUnit) GLFUNC(PFNGLGETTEXTURELEVELPARAMETERIVPROC, glGetTextureLevelParameteriv) GLFUNC(PFNGLTEXTUREPARAMETERIPROC, glTextureParameteri) GLFUNC(PFNGLGETTEXTURESUBIMAGEPROC, glGetTextureSubImage) -GLFUNC(PFNGLTEXTURESUBIMAGE1DPROC, glTextureSubImage1D) GLFUNC(PFNGLTEXTURESUBIMAGE2DPROC, glTextureSubImage2D); GLFUNC(PFNGLTEXTURESUBIMAGE3DPROC, glTextureSubImage3D) -GLFUNC(PFNGLTEXTURESTORAGE1DPROC, glTextureStorage1D) -GLFUNC(PFNGLTEXTURESTORAGE2DPROC, glTextureStorage2D) -GLFUNC(PFNGLTEXTURESTORAGE3DPROC, glTextureStorage3D) // instancing / draw diff --git a/src/audio/CubebAPI.cpp b/src/audio/CubebAPI.cpp index 09e45011..2b4aec41 100644 --- a/src/audio/CubebAPI.cpp +++ b/src/audio/CubebAPI.cpp @@ -188,15 +188,20 @@ std::vector CubebAPI::GetDevices() return {}; std::vector result; - result.reserve(devices.count); + result.reserve(devices.count + 1); // Reserve space for the default device + + // Add the default device to the list + auto defaultDevice = std::make_shared(nullptr, "default", L"Default Device"); + result.emplace_back(defaultDevice); + for (size_t i = 0; i < devices.count; ++i) { - //const auto& device = devices.device[i]; + // const auto& device = devices.device[i]; if (devices.device[i].state == CUBEB_DEVICE_STATE_ENABLED) { auto device = std::make_shared(devices.device[i].devid, devices.device[i].device_id, - boost::nowide::widen( - devices.device[i].friendly_name)); + boost::nowide::widen( + devices.device[i].friendly_name)); result.emplace_back(device); } } diff --git a/src/audio/CubebInputAPI.cpp b/src/audio/CubebInputAPI.cpp index de030fdc..c0fa73f4 100644 --- a/src/audio/CubebInputAPI.cpp +++ b/src/audio/CubebInputAPI.cpp @@ -180,15 +180,20 @@ std::vector CubebInputAPI::GetDevices() return {}; std::vector result; - result.reserve(devices.count); + result.reserve(devices.count + 1); // Reserve space for the default device + + // Add the default device to the list + auto defaultDevice = std::make_shared(nullptr, "default", L"Default Device"); + result.emplace_back(defaultDevice); + for (size_t i = 0; i < devices.count; ++i) { - //const auto& device = devices.device[i]; + // const auto& device = devices.device[i]; if (devices.device[i].state == CUBEB_DEVICE_STATE_ENABLED) { auto device = std::make_shared(devices.device[i].devid, devices.device[i].device_id, - boost::nowide::widen( - devices.device[i].friendly_name)); + boost::nowide::widen( + devices.device[i].friendly_name)); result.emplace_back(device); } } diff --git a/src/gui/GraphicPacksWindow2.cpp b/src/gui/GraphicPacksWindow2.cpp index 78b344d5..13fec49a 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->GetVirtualPath(), m_filter)) + if (boost::icontains(p->GetPath(), m_filter)) found = true; else { @@ -82,7 +82,7 @@ void GraphicPacksWindow2::FillGraphicPackList() const continue; } - const auto& path = p->GetVirtualPath(); + const auto& path = p->GetPath(); auto tokens = TokenizeView(path, '/'); auto node = root; for(size_t i=0; iGetNormalizedPathString()); + auto filename = MakeRelativePath(ActiveSettings::GetUserDataPath(), _utf8ToPath(gp->GetFilename())).lexically_normal(); if (gp->IsEnabled()) { data.graphic_pack_entries.try_emplace(filename); @@ -603,29 +603,34 @@ void GraphicPacksWindow2::OnCheckForUpdates(wxCommandEvent& event) { if (!CafeSystem::IsTitleRunning()) { - // 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 + std::vector old_packs = GraphicPack2::GetGraphicPacks(); RefreshGraphicPacks(); FillGraphicPackList(); - // remove packs which are still present - for(auto& it : GraphicPack2::GetGraphicPacks()) - previouslyEnabledPacks.erase(it->GetNormalizedPathString()); - if(!previouslyEnabledPacks.empty()) + + // check if enabled graphic packs are lost: + const auto& new_packs = GraphicPack2::GetGraphicPacks(); + std::stringstream lost_packs; + for(const auto& p : old_packs) { - std::string lost_packs; - for(auto& it : previouslyEnabledPacks) + 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()) { - lost_packs.append(it.second); - lost_packs.push_back('\n'); + lost_packs << p->GetPath() << "\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" << wxString::FromUTF8(lost_packs) << " \n" << _("You may need to set them up again."); + message << "\n \n" << lost_packs_str << " \n" << _("You may need to set them up again."); wxMessageBox(message, _("Warning"), wxOK | wxCENTRE | wxICON_INFORMATION, this); } } diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index 9f7873a1..53b4dc3b 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -70,9 +70,18 @@ if (ENABLE_WIIMOTE) api/Wiimote/NativeWiimoteController.h api/Wiimote/NativeWiimoteController.cpp api/Wiimote/WiimoteDevice.h + ) + if (ENABLE_HIDAPI) + target_sources(CemuInput PRIVATE api/Wiimote/hidapi/HidapiWiimote.cpp api/Wiimote/hidapi/HidapiWiimote.h - ) + ) + elseif (WIN32) + target_sources(CemuInput PRIVATE + api/Wiimote/windows/WinWiimoteDevice.cpp + api/Wiimote/windows/WinWiimoteDevice.h + ) + endif() endif () diff --git a/src/input/api/Wiimote/WiimoteControllerProvider.cpp b/src/input/api/Wiimote/WiimoteControllerProvider.cpp index 55f28c01..0ca00a1a 100644 --- a/src/input/api/Wiimote/WiimoteControllerProvider.cpp +++ b/src/input/api/Wiimote/WiimoteControllerProvider.cpp @@ -2,7 +2,11 @@ #include "input/api/Wiimote/NativeWiimoteController.h" #include "input/api/Wiimote/WiimoteMessages.h" +#ifdef HAS_HIDAPI #include "input/api/Wiimote/hidapi/HidapiWiimote.h" +#elif BOOST_OS_WINDOWS +#include "input/api/Wiimote/windows/WinWiimoteDevice.h" +#endif #include #include diff --git a/src/input/api/Wiimote/windows/WinWiimoteDevice.cpp b/src/input/api/Wiimote/windows/WinWiimoteDevice.cpp new file mode 100644 index 00000000..09d73013 --- /dev/null +++ b/src/input/api/Wiimote/windows/WinWiimoteDevice.cpp @@ -0,0 +1,130 @@ +#include "input/api/Wiimote/windows/WinWiimoteDevice.h" + +#include +#include + +#pragma comment(lib, "Setupapi.lib") +#pragma comment(lib, "hid.lib") + +WinWiimoteDevice::WinWiimoteDevice(HANDLE handle, std::vector identifier) + : m_handle(handle), m_identifier(std::move(identifier)) +{ + m_overlapped.hEvent = CreateEvent(nullptr, TRUE, TRUE, nullptr); +} + +WinWiimoteDevice::~WinWiimoteDevice() +{ + CancelIo(m_handle); + ResetEvent(m_overlapped.hEvent); + CloseHandle(m_handle); +} + +bool WinWiimoteDevice::write_data(const std::vector& data) +{ + return HidD_SetOutputReport(m_handle, (void*)data.data(), (ULONG)data.size()); +} + +std::optional> WinWiimoteDevice::read_data() +{ + DWORD read = 0; + std::array buffer{}; + + if (!ReadFile(m_handle, buffer.data(), (DWORD)buffer.size(), &read, &m_overlapped)) + { + const auto error = GetLastError(); + if (error == ERROR_DEVICE_NOT_CONNECTED) + return {}; + else if (error == ERROR_IO_PENDING) + { + const auto wait_result = WaitForSingleObject(m_overlapped.hEvent, 100); + if (wait_result == WAIT_TIMEOUT) + { + CancelIo(m_handle); + ResetEvent(m_overlapped.hEvent); + return {}; + } + else if (wait_result == WAIT_FAILED) + return {}; + + if (GetOverlappedResult(m_handle, &m_overlapped, &read, FALSE) == FALSE) + return {}; + } + else if (error == ERROR_INVALID_HANDLE) + { + ResetEvent(m_overlapped.hEvent); + return {}; + } + else + { + cemu_assert_debug(false); + } + } + + ResetEvent(m_overlapped.hEvent); + if (read == 0) + return {}; + + return {{buffer.cbegin(), buffer.cbegin() + read}}; +} + +std::vector WinWiimoteDevice::get_devices() +{ + std::vector result; + + GUID hid_guid; + HidD_GetHidGuid(&hid_guid); + + const auto device_info = SetupDiGetClassDevs(&hid_guid, nullptr, nullptr, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)); + + for (DWORD index = 0; ; ++index) + { + SP_DEVICE_INTERFACE_DATA device_data{}; + device_data.cbSize = sizeof(device_data); + if (SetupDiEnumDeviceInterfaces(device_info, nullptr, &hid_guid, index, &device_data) == FALSE) + break; + + DWORD device_data_len; + if (SetupDiGetDeviceInterfaceDetail(device_info, &device_data, nullptr, 0, &device_data_len, nullptr) == FALSE + && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + continue; + + std::vector detail_data_buffer; + detail_data_buffer.resize(device_data_len); + + const auto detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)detail_data_buffer.data(); + detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + if (SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, device_data_len, nullptr, nullptr) + == FALSE) + continue; + + HANDLE device_handle = CreateFile(detail_data->DevicePath, (GENERIC_READ | GENERIC_WRITE), + (FILE_SHARE_READ | FILE_SHARE_WRITE), nullptr, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, nullptr); + if (device_handle == INVALID_HANDLE_VALUE) + continue; + + HIDD_ATTRIBUTES attributes{}; + attributes.Size = sizeof(attributes); + if (HidD_GetAttributes(device_handle, &attributes) == FALSE) + { + CloseHandle(device_handle); + continue; + } + + if (attributes.VendorID != 0x057e || (attributes.ProductID != 0x0306 && attributes.ProductID != 0x0330)) + { + CloseHandle(device_handle); + continue; + } + + result.emplace_back(std::make_shared(device_handle, detail_data_buffer)); + } + + return result; +} + +bool WinWiimoteDevice::operator==(WiimoteDevice& o) const +{ + return m_identifier == static_cast(o).m_identifier; +} diff --git a/src/input/api/Wiimote/windows/WinWiimoteDevice.h b/src/input/api/Wiimote/windows/WinWiimoteDevice.h new file mode 100644 index 00000000..077882db --- /dev/null +++ b/src/input/api/Wiimote/windows/WinWiimoteDevice.h @@ -0,0 +1,24 @@ +#pragma once + +#include "input/api/Wiimote/WiimoteDevice.h" + +class WinWiimoteDevice : public WiimoteDevice +{ +public: + WinWiimoteDevice(HANDLE handle, std::vector identifier); + ~WinWiimoteDevice(); + + bool write_data(const std::vector& data) override; + std::optional> read_data() override; + + static std::vector get_devices(); + + bool operator==(WiimoteDevice& o) const override; + +private: + HANDLE m_handle; + OVERLAPPED m_overlapped{}; + std::vector m_identifier; +}; + +using WiimoteDevice_t = WinWiimoteDevice; diff --git a/src/resource/MacOSXBundleInfo.plist.in b/src/resource/MacOSXBundleInfo.plist.in index 98064735..c181b388 100644 --- a/src/resource/MacOSXBundleInfo.plist.in +++ b/src/resource/MacOSXBundleInfo.plist.in @@ -26,22 +26,7 @@ NSHumanReadableCopyright ${MACOSX_BUNDLE_COPYRIGHT} - LSApplicationCategoryType - ${MACOSX_BUNDLE_CATEGORY} - LSMinimumSystemVersion - ${MACOSX_MINIMUM_SYSTEM_VERSION} - CFBundleDocumentTypes - - - CFBundleTypeExtensions - - ${MACOSX_BUNDLE_TYPE_EXTENSION} - - CFBundleTypeName - Wii U File - CFBundleTypeRole - Viewer - - + LSApplicationCategoryType + ${MACOSX_BUNDLE_CATEGORY} - + \ No newline at end of file diff --git a/vcpkg.json b/vcpkg.json index d14a1a8a..7ea8058e 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -26,7 +26,10 @@ "boost-static-string", "boost-random", "fmt", - "hidapi", + { + "name": "hidapi", + "platform": "!windows" + }, "libpng", "glm", {