aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs33
-rw-r--r--Ryujinx.Graphics.Shader/Decoders/Decoder.cs20
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Translator.cs53
3 files changed, 57 insertions, 49 deletions
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index d99a402b..d4ced7c8 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -426,6 +426,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
Hash128 programCodeHash = default;
GuestShaderCacheEntry[] shaderCacheEntries = null;
+ // Current shader cache doesn't support bindless textures
+ if (shaderContexts[0].UsedFeatures.HasFlag(FeatureFlags.Bindless))
+ {
+ isShaderCacheEnabled = false;
+ }
+
if (isShaderCacheEnabled)
{
isShaderCacheReadOnly = _cacheManager.IsReadOnly;
@@ -448,8 +454,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
// The shader isn't currently cached, translate it and compile it.
ShaderCodeHolder shader = TranslateShader(shaderContexts[0]);
- bool isDiskShaderCacheIncompatible = shaderContexts[0].UsedFeatures.HasFlag(FeatureFlags.Bindless);
-
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null);
@@ -458,7 +462,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
cpShader = new ShaderBundle(hostProgram, shader);
- if (isShaderCacheEnabled && !isDiskShaderCacheIncompatible)
+ if (isShaderCacheEnabled)
{
_cpProgramsDiskCache.Add(programCodeHash, cpShader);
@@ -536,6 +540,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
Hash128 programCodeHash = default;
GuestShaderCacheEntry[] shaderCacheEntries = null;
+ // Current shader cache doesn't support bindless textures
+ for (int i = 0; i < shaderContexts.Length; i++)
+ {
+ if (shaderContexts[i] != null && shaderContexts[i].UsedFeatures.HasFlag(FeatureFlags.Bindless))
+ {
+ isShaderCacheEnabled = false;
+ break;
+ }
+ }
+
if (isShaderCacheEnabled)
{
isShaderCacheReadOnly = _cacheManager.IsReadOnly;
@@ -564,17 +578,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
shaders[3] = TranslateShader(shaderContexts[4]);
shaders[4] = TranslateShader(shaderContexts[5]);
- bool isDiskShaderCacheIncompatible = false;
-
- for (int i = 0; i < shaderContexts.Length; i++)
- {
- if (shaderContexts[i] != null && shaderContexts[i].UsedFeatures.HasFlag(FeatureFlags.Bindless))
- {
- isDiskShaderCacheIncompatible = true;
- break;
- }
- }
-
List<IShader> hostShaders = new List<IShader>();
for (int stage = 0; stage < Constants.ShaderStages; stage++)
@@ -599,7 +602,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
gpShaders = new ShaderBundle(hostProgram, shaders);
- if (isShaderCacheEnabled && !isDiskShaderCacheIncompatible)
+ if (isShaderCacheEnabled)
{
_gpProgramsDiskCache.Add(programCodeHash, gpShaders);
diff --git a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
index ca45aab5..795a26cc 100644
--- a/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
+++ b/Ryujinx.Graphics.Shader/Decoders/Decoder.cs
@@ -9,8 +9,10 @@ namespace Ryujinx.Graphics.Shader.Decoders
{
static class Decoder
{
- public static Block[][] Decode(IGpuAccessor gpuAccessor, ulong startAddress)
+ public static Block[][] Decode(IGpuAccessor gpuAccessor, ulong startAddress, out bool hasBindless)
{
+ hasBindless = false;
+
List<Block[]> funcs = new List<Block[]>();
Queue<ulong> funcQueue = new Queue<ulong>();
@@ -84,7 +86,8 @@ namespace Ryujinx.Graphics.Shader.Decoders
}
}
- FillBlock(gpuAccessor, currBlock, limitAddress, startAddress);
+ FillBlock(gpuAccessor, currBlock, limitAddress, startAddress, out bool blockHasBindless);
+ hasBindless |= blockHasBindless;
if (currBlock.OpCodes.Count != 0)
{
@@ -229,9 +232,11 @@ namespace Ryujinx.Graphics.Shader.Decoders
IGpuAccessor gpuAccessor,
Block block,
ulong limitAddress,
- ulong startAddress)
+ ulong startAddress,
+ out bool hasBindless)
{
ulong address = block.Address;
+ hasBindless = false;
do
{
@@ -272,6 +277,15 @@ namespace Ryujinx.Graphics.Shader.Decoders
OpCode op = makeOp(emitter, opAddress, opCode);
+ // We check these patterns to figure out the presence of bindless access
+ hasBindless |= (op is OpCodeImage image && image.IsBindless) ||
+ (op is OpCodeTxd txd && txd.IsBindless) ||
+ (op is OpCodeTld4B) ||
+ (emitter == InstEmit.TexB) ||
+ (emitter == InstEmit.TldB) ||
+ (emitter == InstEmit.TmmlB) ||
+ (emitter == InstEmit.TxqB);
+
block.OpCodes.Add(op);
}
while (!IsControlFlowChange(block.GetLastOp()));
diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs
index c7eb27e5..9f0f9010 100644
--- a/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -36,22 +36,6 @@ namespace Ryujinx.Graphics.Shader.Translation
return new TranslatorContext(address, cfg, config);
}
- private static void ScanForBindless(BasicBlock[] blocks, ShaderConfig config)
- {
- for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
- {
- // Right now the guest shader cache cannot handle bindless textures correctly.
- for (LinkedListNode<INode> node = blocks[blkIndex].Operations.First; node != null; node = node.Next)
- {
- if (node.Value is TextureOperation texOp && (texOp.Flags & TextureFlags.Bindless) != 0)
- {
- config.SetUsedFeature(FeatureFlags.Bindless);
- break;
- }
- }
- }
- }
-
internal static ShaderProgram Translate(FunctionCode[] functions, ShaderConfig config, out ShaderProgramInfo shaderProgramInfo)
{
var cfgs = new ControlFlowGraph[functions.Length];
@@ -91,8 +75,6 @@ namespace Ryujinx.Graphics.Shader.Translation
Dominance.FindDominators(cfg);
Dominance.FindDominanceFrontiers(cfg.Blocks);
- ScanForBindless(cfg.Blocks, config);
-
Ssa.Rename(cfg.Blocks);
Optimizer.RunPass(cfg.Blocks, config);
@@ -129,35 +111,44 @@ namespace Ryujinx.Graphics.Shader.Translation
Block[][] cfg;
ulong maxEndAddress = 0;
+ bool hasBindless = false;
+
if ((flags & TranslationFlags.Compute) != 0)
{
config = new ShaderConfig(gpuAccessor, flags, counts);
- cfg = Decoder.Decode(gpuAccessor, address);
+ cfg = Decoder.Decode(gpuAccessor, address, out hasBindless);
}
else
{
config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, flags, counts);
- cfg = Decoder.Decode(gpuAccessor, address + HeaderSize);
+ cfg = Decoder.Decode(gpuAccessor, address + HeaderSize, out hasBindless);
}
- for (int funcIndex = 0; funcIndex < cfg.Length; funcIndex++)
+ if (hasBindless)
{
- for (int blkIndex = 0; blkIndex < cfg[funcIndex].Length; blkIndex++)
+ config.SetUsedFeature(FeatureFlags.Bindless);
+ }
+ else // Not bindless, fill up texture handles
+ {
+ for (int funcIndex = 0; funcIndex < cfg.Length; funcIndex++)
{
- Block block = cfg[funcIndex][blkIndex];
-
- if (maxEndAddress < block.EndAddress)
+ for (int blkIndex = 0; blkIndex < cfg[funcIndex].Length; blkIndex++)
{
- maxEndAddress = block.EndAddress;
- }
+ Block block = cfg[funcIndex][blkIndex];
- for (int index = 0; index < block.OpCodes.Count; index++)
- {
- if (block.OpCodes[index] is OpCodeTextureBase texture)
+ if (maxEndAddress < block.EndAddress)
+ {
+ maxEndAddress = block.EndAddress;
+ }
+
+ for (int index = 0; index < block.OpCodes.Count; index++)
{
- config.TextureHandlesForCache.Add(texture.HandleOffset);
+ if (block.OpCodes[index] is OpCodeTextureBase texture)
+ {
+ config.TextureHandlesForCache.Add(texture.HandleOffset);
+ }
}
}
}