Shader Cache: Move bindless checking from translation to decode (#2145)

This commit is contained in:
mageven 2021-03-27 05:20:26 +05:30 committed by GitHub
parent 32be8caa9d
commit a5d5ca0635
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 49 deletions

View File

@ -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);

View File

@ -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()));

View File

@ -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);
}
} }
} }
} }