Shader: Add fallback for LDG from "ube" buffer ranges. (#4027)
We have a conversion from LDG on the compute shader to a special constant buffer binding that's used to exceed hardware limits on compute, but it was only running if the byte offset could be identified. The fallback that checks all of the bindings at runtime only checks the storage buffers. This PR adds checking ube ranges to the LoadGlobal fallback. This extends the changes in #4011 to only check ube entries which are accessed by the shader. Fixes particles affected by the wind in The Legend of Zelda: Breath of the Wild. May fix other weird issues with compute shaders in some games. Try a bunch of games and drivers to make sure they don't blow up loading constants willynilly from searchable buffers.
This commit is contained in:
@ -8,11 +8,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
{
|
||||
static class GlobalToStorage
|
||||
{
|
||||
public static void RunPass(BasicBlock block, ShaderConfig config, ref int sbUseMask)
|
||||
public static void RunPass(BasicBlock block, ShaderConfig config, ref int sbUseMask, ref int ubeUseMask)
|
||||
{
|
||||
int sbStart = GetStorageBaseCbOffset(config.Stage);
|
||||
int sbEnd = sbStart + StorageDescsSize;
|
||||
|
||||
int ubeStart = UbeBaseOffset;
|
||||
int ubeEnd = UbeBaseOffset + UbeDescsSize;
|
||||
|
||||
for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
|
||||
{
|
||||
for (int index = 0; index < node.Value.SourcesCount; index++)
|
||||
@ -25,6 +28,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
{
|
||||
sbUseMask |= 1 << storageIndex;
|
||||
}
|
||||
|
||||
if (config.Stage == ShaderStage.Compute)
|
||||
{
|
||||
int constantIndex = GetStorageIndex(src, ubeStart, ubeEnd);
|
||||
|
||||
if (constantIndex >= 0)
|
||||
{
|
||||
ubeUseMask |= 1 << constantIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(node.Value is Operation operation))
|
||||
@ -54,7 +67,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
// so NVN "emulates" more constant buffers using global memory access.
|
||||
// Here we try to replace the global access back to a constant buffer
|
||||
// load.
|
||||
storageIndex = SearchForStorageBase(block, source, UbeBaseOffset, UbeBaseOffset + UbeDescsSize);
|
||||
storageIndex = SearchForStorageBase(block, source, ubeStart, ubeStart + ubeEnd);
|
||||
|
||||
if (storageIndex >= 0)
|
||||
{
|
||||
@ -64,7 +77,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
}
|
||||
}
|
||||
|
||||
config.SetAccessibleStorageBuffersMask(sbUseMask);
|
||||
config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask);
|
||||
}
|
||||
|
||||
private static LinkedListNode<INode> ReplaceGlobalWithStorage(BasicBlock block, LinkedListNode<INode> node, ShaderConfig config, int storageIndex)
|
||||
|
@ -12,16 +12,17 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
RunOptimizationPasses(blocks);
|
||||
|
||||
int sbUseMask = 0;
|
||||
int ubeUseMask = 0;
|
||||
|
||||
// Those passes are looking for specific patterns and only needs to run once.
|
||||
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
|
||||
{
|
||||
GlobalToStorage.RunPass(blocks[blkIndex], config, ref sbUseMask);
|
||||
GlobalToStorage.RunPass(blocks[blkIndex], config, ref sbUseMask, ref ubeUseMask);
|
||||
BindlessToIndexed.RunPass(blocks[blkIndex], config);
|
||||
BindlessElimination.RunPass(blocks[blkIndex], config);
|
||||
}
|
||||
|
||||
config.SetAccessibleStorageBuffersMask(sbUseMask);
|
||||
config.SetAccessibleBufferMasks(sbUseMask, ubeUseMask);
|
||||
|
||||
// Run optimizations one last time to remove any code that is now optimizable after above passes.
|
||||
RunOptimizationPasses(blocks);
|
||||
|
Reference in New Issue
Block a user