From 244c3e564809e028b03114c601ab311986092475 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Mon, 25 Mar 2024 20:58:30 +0100 Subject: [PATCH] Latte: Enable framebuffer size optimization if gfx packs are aware Graphic packs can now set "colorbufferOptimizationAware = true" to enable the framebuffer texture size optimization added in #706. If no graphic packs with texture rules are active then the optimization is enabled automatically now. --- src/Cafe/GraphicPack/GraphicPack2.cpp | 4 ++++ src/Cafe/GraphicPack/GraphicPack2.h | 3 +++ src/Cafe/HW/Latte/Core/Latte.h | 2 ++ src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp | 21 ++++++++++---------- src/Cafe/HW/Latte/Core/LatteTexture.cpp | 7 ++++--- src/Cafe/HW/Latte/Core/LatteThread.cpp | 17 ++++++++++++++++ 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/Cafe/GraphicPack/GraphicPack2.cpp b/src/Cafe/GraphicPack/GraphicPack2.cpp index b581316e8b..27d423b9d9 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2.cpp @@ -280,6 +280,10 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules) m_enabled = m_default_enabled; } + auto option_allowRendertargetSizeOptimization = rules.FindOption("colorbufferOptimizationAware"); + if (option_allowRendertargetSizeOptimization) + m_allowRendertargetSizeOptimization = boost::iequals(*option_allowRendertargetSizeOptimization, "true") || boost::iequals(*option_allowRendertargetSizeOptimization, "1"); + auto option_vendorFilter = rules.FindOption("vendorFilter"); if (option_vendorFilter) { diff --git a/src/Cafe/GraphicPack/GraphicPack2.h b/src/Cafe/GraphicPack/GraphicPack2.h index 6b07cce991..9b6a86d4fc 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.h +++ b/src/Cafe/GraphicPack/GraphicPack2.h @@ -113,6 +113,7 @@ class GraphicPack2 const std::string& GetVirtualPath() const { return m_virtualPath; } // returns the path in the gfx tree hierarchy const std::string& GetDescription() const { return m_description; } bool IsDefaultEnabled() const { return m_default_enabled; } + bool AllowRendertargetSizeOptimization() const { return m_allowRendertargetSizeOptimization; } void SetEnabled(bool state) { m_enabled = state; } @@ -217,6 +218,8 @@ class GraphicPack2 bool m_default_enabled = false; + bool m_allowRendertargetSizeOptimization = false; // gfx pack supports framebuffers with non-padded sizes, which is an optional optimization introduced with Cemu 2.0-74 + // filter std::optional m_renderer_api; std::optional m_gfx_vendor; diff --git a/src/Cafe/HW/Latte/Core/Latte.h b/src/Cafe/HW/Latte/Core/Latte.h index d9419a6a5b..e8cb2be4a8 100644 --- a/src/Cafe/HW/Latte/Core/Latte.h +++ b/src/Cafe/HW/Latte/Core/Latte.h @@ -25,6 +25,8 @@ struct LatteGPUState_t // context control uint32 contextControl0; uint32 contextControl1; + // optional features + bool allowFramebufferSizeOptimization{false}; // allow using scissor box as size hint to determine non-padded rendertarget size // draw context struct { diff --git a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp index 300697127c..f165e25705 100644 --- a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp +++ b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp @@ -267,14 +267,15 @@ LatteTextureView* LatteMRT::GetColorAttachmentTexture(uint32 index, bool createN // colorbuffer width/height has to be padded to 8/32 alignment but the actual resolution might be smaller // use the scissor box as a clue to figure out the original resolution if possible -#if 0 - uint32 scissorBoxWidth = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_BR.get_BR_X(); - uint32 scissorBoxHeight = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_BR.get_BR_Y(); - if (((scissorBoxWidth + 7) & ~7) == colorBufferWidth) - colorBufferWidth = scissorBoxWidth; - if (((colorBufferHeight + 31) & ~31) == colorBufferHeight) - colorBufferHeight = scissorBoxHeight; -#endif + if(LatteGPUState.allowFramebufferSizeOptimization) + { + uint32 scissorBoxWidth = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_BR.get_BR_X(); + uint32 scissorBoxHeight = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_BR.get_BR_Y(); + if (((scissorBoxWidth + 7) & ~7) == colorBufferWidth) + colorBufferWidth = scissorBoxWidth; + if (((colorBufferHeight + 31) & ~31) == colorBufferHeight) + colorBufferHeight = scissorBoxHeight; + } // log resolution changes if the above heuristic takes effect // this is useful to find resolutions which need to be updated in gfx pack texture rules @@ -303,7 +304,7 @@ LatteTextureView* LatteMRT::GetColorAttachmentTexture(uint32 index, bool createN if (colorBufferView == nullptr) { // create color buffer view - colorBufferView = LatteTexture_CreateMapping(colorBufferPhysMem, 0, colorBufferWidth, colorBufferHeight, (viewFirstSlice + viewNumSlices), colorBufferPitch, colorBufferTileMode, colorBufferSwizzle>>8, viewFirstMip, 1, viewFirstSlice, viewNumSlices, (Latte::E_GX2SURFFMT)colorBufferFormat, (viewFirstSlice + viewNumSlices)>1? Latte::E_DIM::DIM_2D_ARRAY: Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, false); + colorBufferView = LatteTexture_CreateMapping(colorBufferPhysMem, 0, colorBufferWidth, colorBufferHeight, (viewFirstSlice + viewNumSlices), colorBufferPitch, colorBufferTileMode, colorBufferSwizzle>>8, viewFirstMip, 1, viewFirstSlice, viewNumSlices, (Latte::E_GX2SURFFMT)colorBufferFormat, (viewFirstSlice + viewNumSlices)>1? Latte::E_DIM::DIM_2D_ARRAY: Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, false, true); LatteGPUState.repeatTextureInitialization = true; checkForTextureChanges = false; } @@ -582,7 +583,7 @@ bool LatteMRT::UpdateCurrentFBO() if (!depthBufferView) { // create new depth buffer view and if it doesn't exist then also create the texture - depthBufferView = LatteTexture_CreateMapping(depthBufferPhysMem, 0, depthBufferWidth, depthBufferHeight, depthBufferViewFirstSlice+1, depthBufferPitch, depthBufferTileMode, depthBufferSwizzle, 0, 1, depthBufferViewFirstSlice, 1, depthBufferFormat, depthBufferViewFirstSlice > 0 ? Latte::E_DIM::DIM_2D_ARRAY : Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, true); + depthBufferView = LatteTexture_CreateMapping(depthBufferPhysMem, 0, depthBufferWidth, depthBufferHeight, depthBufferViewFirstSlice+1, depthBufferPitch, depthBufferTileMode, depthBufferSwizzle, 0, 1, depthBufferViewFirstSlice, 1, depthBufferFormat, depthBufferViewFirstSlice > 0 ? Latte::E_DIM::DIM_2D_ARRAY : Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, true, true); LatteGPUState.repeatTextureInitialization = true; } else diff --git a/src/Cafe/HW/Latte/Core/LatteTexture.cpp b/src/Cafe/HW/Latte/Core/LatteTexture.cpp index d6f576d4e2..3754fb1979 100644 --- a/src/Cafe/HW/Latte/Core/LatteTexture.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTexture.cpp @@ -1,5 +1,4 @@ #include "Cafe/HW/Latte/Core/Latte.h" -#include "Cafe/HW/Latte/Core/LatteDraw.h" #include "Cafe/HW/Latte/Core/LatteShader.h" #include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h" #include "Cafe/HW/Latte/Core/LatteTexture.h" @@ -9,6 +8,8 @@ #include "Cafe/GraphicPack/GraphicPack2.h" +#include + struct TexMemOccupancyEntry { uint32 addrStart; @@ -963,7 +964,7 @@ void LatteTexture_RecreateTextureWithDifferentMipSliceCount(LatteTexture* textur } // create new texture representation -// if allowCreateNewDataTexture is true, a new texture will be created if necessary. If it is false, only existing textures may be used, except if a data-compatible version of the requested texture already exists and it's not view compatible +// 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 (todo - we should differentiate between Latte compatible views and renderer 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) { @@ -980,7 +981,7 @@ LatteTextureView* LatteTexture_CreateMapping(MPTR physAddr, MPTR physMipAddr, si // todo, depth and numSlice are redundant sint32 sliceCount = firstSlice + numSlice; - std::vector list_overlappingTextures; + boost::container::small_vector list_overlappingTextures; for (sint32 sliceIndex = 0; sliceIndex < sliceCount; sliceIndex++) { sint32 mipIndex = 0; diff --git a/src/Cafe/HW/Latte/Core/LatteThread.cpp b/src/Cafe/HW/Latte/Core/LatteThread.cpp index bd312d9369..fd9334eff3 100644 --- a/src/Cafe/HW/Latte/Core/LatteThread.cpp +++ b/src/Cafe/HW/Latte/Core/LatteThread.cpp @@ -175,6 +175,23 @@ int Latte_ThreadEntry() // before doing anything with game specific shaders, we need to wait for graphic packs to finish loading GraphicPack2::WaitUntilReady(); + // if legacy packs are enabled we cannot use the rendertarget resolution optimization + LatteGPUState.allowFramebufferSizeOptimization = true; + for(auto& pack : GraphicPack2::GetActiveGraphicPacks()) + { + if(pack->AllowRendertargetSizeOptimization()) + continue; + for(auto& rule : pack->GetTextureRules()) + { + if(rule.filter_settings.width >= 0 || rule.filter_settings.height >= 0 || rule.filter_settings.depth >= 0 || + rule.overwrite_settings.width >= 0 || rule.overwrite_settings.height >= 0 || rule.overwrite_settings.depth >= 0) + { + LatteGPUState.allowFramebufferSizeOptimization = false; + cemuLog_log(LogType::Force, "Graphic pack {} prevents rendertarget size optimization.", pack->GetName()); + break; + } + } + } // load disk shader cache LatteShaderCache_Load(); // init registers