Shader Cache: Move bindless checking from translation to decode (#2145)
This commit is contained in:
parent
32be8caa9d
commit
a5d5ca0635
3 changed files with 57 additions and 49 deletions
|
@ -426,6 +426,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
Hash128 programCodeHash = default;
|
Hash128 programCodeHash = default;
|
||||||
GuestShaderCacheEntry[] shaderCacheEntries = null;
|
GuestShaderCacheEntry[] shaderCacheEntries = null;
|
||||||
|
|
||||||
|
// Current shader cache doesn't support bindless textures
|
||||||
|
if (shaderContexts[0].UsedFeatures.HasFlag(FeatureFlags.Bindless))
|
||||||
|
{
|
||||||
|
isShaderCacheEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (isShaderCacheEnabled)
|
if (isShaderCacheEnabled)
|
||||||
{
|
{
|
||||||
isShaderCacheReadOnly = _cacheManager.IsReadOnly;
|
isShaderCacheReadOnly = _cacheManager.IsReadOnly;
|
||||||
|
@ -448,8 +454,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
// The shader isn't currently cached, translate it and compile it.
|
// The shader isn't currently cached, translate it and compile it.
|
||||||
ShaderCodeHolder shader = TranslateShader(shaderContexts[0]);
|
ShaderCodeHolder shader = TranslateShader(shaderContexts[0]);
|
||||||
|
|
||||||
bool isDiskShaderCacheIncompatible = shaderContexts[0].UsedFeatures.HasFlag(FeatureFlags.Bindless);
|
|
||||||
|
|
||||||
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
|
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
|
||||||
|
|
||||||
IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null);
|
IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null);
|
||||||
|
@ -458,7 +462,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
cpShader = new ShaderBundle(hostProgram, shader);
|
cpShader = new ShaderBundle(hostProgram, shader);
|
||||||
|
|
||||||
if (isShaderCacheEnabled && !isDiskShaderCacheIncompatible)
|
if (isShaderCacheEnabled)
|
||||||
{
|
{
|
||||||
_cpProgramsDiskCache.Add(programCodeHash, cpShader);
|
_cpProgramsDiskCache.Add(programCodeHash, cpShader);
|
||||||
|
|
||||||
|
@ -536,6 +540,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
Hash128 programCodeHash = default;
|
Hash128 programCodeHash = default;
|
||||||
GuestShaderCacheEntry[] shaderCacheEntries = null;
|
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)
|
if (isShaderCacheEnabled)
|
||||||
{
|
{
|
||||||
isShaderCacheReadOnly = _cacheManager.IsReadOnly;
|
isShaderCacheReadOnly = _cacheManager.IsReadOnly;
|
||||||
|
@ -564,17 +578,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
shaders[3] = TranslateShader(shaderContexts[4]);
|
shaders[3] = TranslateShader(shaderContexts[4]);
|
||||||
shaders[4] = TranslateShader(shaderContexts[5]);
|
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>();
|
List<IShader> hostShaders = new List<IShader>();
|
||||||
|
|
||||||
for (int stage = 0; stage < Constants.ShaderStages; stage++)
|
for (int stage = 0; stage < Constants.ShaderStages; stage++)
|
||||||
|
@ -599,7 +602,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
gpShaders = new ShaderBundle(hostProgram, shaders);
|
gpShaders = new ShaderBundle(hostProgram, shaders);
|
||||||
|
|
||||||
if (isShaderCacheEnabled && !isDiskShaderCacheIncompatible)
|
if (isShaderCacheEnabled)
|
||||||
{
|
{
|
||||||
_gpProgramsDiskCache.Add(programCodeHash, gpShaders);
|
_gpProgramsDiskCache.Add(programCodeHash, gpShaders);
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,10 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
||||||
{
|
{
|
||||||
static class Decoder
|
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[]>();
|
List<Block[]> funcs = new List<Block[]>();
|
||||||
|
|
||||||
Queue<ulong> funcQueue = new Queue<ulong>();
|
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)
|
if (currBlock.OpCodes.Count != 0)
|
||||||
{
|
{
|
||||||
|
@ -229,9 +232,11 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
||||||
IGpuAccessor gpuAccessor,
|
IGpuAccessor gpuAccessor,
|
||||||
Block block,
|
Block block,
|
||||||
ulong limitAddress,
|
ulong limitAddress,
|
||||||
ulong startAddress)
|
ulong startAddress,
|
||||||
|
out bool hasBindless)
|
||||||
{
|
{
|
||||||
ulong address = block.Address;
|
ulong address = block.Address;
|
||||||
|
hasBindless = false;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -272,6 +277,15 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
||||||
|
|
||||||
OpCode op = makeOp(emitter, opAddress, opCode);
|
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);
|
block.OpCodes.Add(op);
|
||||||
}
|
}
|
||||||
while (!IsControlFlowChange(block.GetLastOp()));
|
while (!IsControlFlowChange(block.GetLastOp()));
|
||||||
|
|
|
@ -36,22 +36,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return new TranslatorContext(address, cfg, config);
|
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)
|
internal static ShaderProgram Translate(FunctionCode[] functions, ShaderConfig config, out ShaderProgramInfo shaderProgramInfo)
|
||||||
{
|
{
|
||||||
var cfgs = new ControlFlowGraph[functions.Length];
|
var cfgs = new ControlFlowGraph[functions.Length];
|
||||||
|
@ -91,8 +75,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
Dominance.FindDominators(cfg);
|
Dominance.FindDominators(cfg);
|
||||||
Dominance.FindDominanceFrontiers(cfg.Blocks);
|
Dominance.FindDominanceFrontiers(cfg.Blocks);
|
||||||
|
|
||||||
ScanForBindless(cfg.Blocks, config);
|
|
||||||
|
|
||||||
Ssa.Rename(cfg.Blocks);
|
Ssa.Rename(cfg.Blocks);
|
||||||
|
|
||||||
Optimizer.RunPass(cfg.Blocks, config);
|
Optimizer.RunPass(cfg.Blocks, config);
|
||||||
|
@ -129,35 +111,44 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
Block[][] cfg;
|
Block[][] cfg;
|
||||||
ulong maxEndAddress = 0;
|
ulong maxEndAddress = 0;
|
||||||
|
|
||||||
|
bool hasBindless = false;
|
||||||
|
|
||||||
if ((flags & TranslationFlags.Compute) != 0)
|
if ((flags & TranslationFlags.Compute) != 0)
|
||||||
{
|
{
|
||||||
config = new ShaderConfig(gpuAccessor, flags, counts);
|
config = new ShaderConfig(gpuAccessor, flags, counts);
|
||||||
|
|
||||||
cfg = Decoder.Decode(gpuAccessor, address);
|
cfg = Decoder.Decode(gpuAccessor, address, out hasBindless);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, flags, counts);
|
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];
|
for (int blkIndex = 0; blkIndex < cfg[funcIndex].Length; blkIndex++)
|
||||||
|
|
||||||
if (maxEndAddress < block.EndAddress)
|
|
||||||
{
|
{
|
||||||
maxEndAddress = block.EndAddress;
|
Block block = cfg[funcIndex][blkIndex];
|
||||||
}
|
|
||||||
|
|
||||||
for (int index = 0; index < block.OpCodes.Count; index++)
|
if (maxEndAddress < block.EndAddress)
|
||||||
{
|
|
||||||
if (block.OpCodes[index] is OpCodeTextureBase texture)
|
|
||||||
{
|
{
|
||||||
config.TextureHandlesForCache.Add(texture.HandleOffset);
|
maxEndAddress = block.EndAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int index = 0; index < block.OpCodes.Count; index++)
|
||||||
|
{
|
||||||
|
if (block.OpCodes[index] is OpCodeTextureBase texture)
|
||||||
|
{
|
||||||
|
config.TextureHandlesForCache.Add(texture.HandleOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue