Skip to content

Commit

Permalink
Latte: Enable colorbuffer optimization if gfx packs are aware
Browse files Browse the repository at this point in the history
The optimization for colorbuffer resolution introduced in PR cemu-project#706 is now enabled. This optimization changes the resolution of certain framebuffer textures, which may conflict with the texture resolution rules set by some graphic packs. As a result, if a graphic pack that specifies texture resolution rules is in use, the optimization will automatically be turned off to prevent any issues.

To circumvent this, graphic packs can now include the setting "colorbufferOptimizationAware = true" in their rules.txt. This setting indicates that the pack has been updated to handle the resolution changes introduced by the optimization. Cemu will allow the optimization to remain enabled if resolution packs have this flag set.
  • Loading branch information
Exzap committed Mar 25, 2024
1 parent 731713d commit 962867a
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 13 deletions.
4 changes: 4 additions & 0 deletions src/Cafe/GraphicPack/GraphicPack2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
3 changes: 3 additions & 0 deletions src/Cafe/GraphicPack/GraphicPack2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down Expand Up @@ -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<RendererAPI> m_renderer_api;
std::optional<GfxVendor> m_gfx_vendor;
Expand Down
2 changes: 2 additions & 0 deletions src/Cafe/HW/Latte/Core/Latte.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
21 changes: 11 additions & 10 deletions src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions src/Cafe/HW/Latte/Core/LatteTexture.cpp
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -9,6 +8,8 @@

#include "Cafe/GraphicPack/GraphicPack2.h"

#include <boost/container/small_vector.hpp>

struct TexMemOccupancyEntry
{
uint32 addrStart;
Expand Down Expand Up @@ -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)
{
Expand All @@ -980,7 +981,7 @@ LatteTextureView* LatteTexture_CreateMapping(MPTR physAddr, MPTR physMipAddr, si
// todo, depth and numSlice are redundant

sint32 sliceCount = firstSlice + numSlice;
std::vector<LatteTexture*> list_overlappingTextures;
boost::container::small_vector<LatteTexture*, 16> list_overlappingTextures;
for (sint32 sliceIndex = 0; sliceIndex < sliceCount; sliceIndex++)
{
sint32 mipIndex = 0;
Expand Down
17 changes: 17 additions & 0 deletions src/Cafe/HW/Latte/Core/LatteThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 colorbuffer 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
Expand Down

0 comments on commit 962867a

Please sign in to comment.