aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2021-08-11 17:27:00 -0300
committerGitHub <noreply@github.com>2021-08-11 22:27:00 +0200
commited754af8d5046d2fd7218c742521e38ab17cbcfe (patch)
treed47eda40349a7b4b3fc34d9db9ddeea8f2d0676a /Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
parent10d649e6d3ad3e4af32d2b41e718bb0a2924da67 (diff)
Make sure attributes used on subsequent shader stages are initialized (#2538)
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs212
1 files changed, 124 insertions, 88 deletions
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index db5a3bff..2c1fb084 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary>
/// Version of the codegen (to be changed when codegen or guest format change).
/// </summary>
- private const ulong ShaderCodeGenVersion = 2494;
+ private const ulong ShaderCodeGenVersion = 2538;
// Progress reporting helpers
private volatile int _shaderCount;
@@ -290,81 +290,77 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
Task compileTask = Task.Run(() =>
{
- // Reconstruct code holder.
- for (int i = 0; i < entries.Length; i++)
- {
- GuestShaderCacheEntry entry = entries[i];
-
- if (entry == null)
- {
- continue;
- }
+ TranslatorContext[] shaderContexts = null;
- ShaderProgram program;
+ if (!isHostProgramValid)
+ {
+ shaderContexts = new TranslatorContext[1 + entries.Length];
- if (entry.Header.SizeA != 0)
+ for (int i = 0; i < entries.Length; i++)
{
- ShaderProgramInfo shaderProgramInfo;
+ GuestShaderCacheEntry entry = entries[i];
- if (isHostProgramValid)
+ if (entry == null)
{
- program = new ShaderProgram(entry.Header.Stage, "");
- shaderProgramInfo = hostShaderEntries[i].ToShaderProgramInfo();
+ continue;
}
- else
- {
- var binaryCode = new Memory<byte>(entry.Code);
- var gpuAccessor = new CachedGpuAccessor(
- _context,
- binaryCode,
- binaryCode.Slice(binaryCode.Length - entry.Header.Cb1DataSize),
- entry.Header.GpuAccessorHeader,
- entry.TextureDescriptors);
+ var binaryCode = new Memory<byte>(entry.Code);
- var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags);
- var options2 = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags | TranslationFlags.VertexA);
+ var gpuAccessor = new CachedGpuAccessor(
+ _context,
+ binaryCode,
+ binaryCode.Slice(binaryCode.Length - entry.Header.Cb1DataSize),
+ entry.Header.GpuAccessorHeader,
+ entry.TextureDescriptors);
+
+ var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags);
+
+ shaderContexts[i + 1] = Translator.CreateContext(0, gpuAccessor, options, counts);
- TranslatorContext translatorContext = Translator.CreateContext(0, gpuAccessor, options, counts);
- TranslatorContext translatorContext2 = Translator.CreateContext((ulong)entry.Header.Size, gpuAccessor, options2, counts);
+ if (entry.Header.SizeA != 0)
+ {
+ var options2 = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags | TranslationFlags.VertexA);
- program = translatorContext.Translate(out shaderProgramInfo, translatorContext2);
+ shaderContexts[0] = Translator.CreateContext((ulong)entry.Header.Size, gpuAccessor, options2, counts);
}
+ }
+ }
- // NOTE: Vertex B comes first in the shader cache.
- byte[] code = entry.Code.AsSpan().Slice(0, entry.Header.Size - entry.Header.Cb1DataSize).ToArray();
- byte[] code2 = entry.Code.AsSpan().Slice(entry.Header.Size, entry.Header.SizeA).ToArray();
+ // Reconstruct code holder.
+ for (int i = 0; i < entries.Length; i++)
+ {
+ GuestShaderCacheEntry entry = entries[i];
- shaders[i] = new ShaderCodeHolder(program, shaderProgramInfo, code, code2);
+ if (entry == null)
+ {
+ continue;
+ }
+
+ ShaderProgram program;
+ ShaderProgramInfo shaderProgramInfo;
+
+ if (isHostProgramValid)
+ {
+ program = new ShaderProgram(entry.Header.Stage, "");
+ shaderProgramInfo = hostShaderEntries[i].ToShaderProgramInfo();
}
else
{
- ShaderProgramInfo shaderProgramInfo;
+ int stageIndex = i + 1;
- if (isHostProgramValid)
- {
- program = new ShaderProgram(entry.Header.Stage, "");
- shaderProgramInfo = hostShaderEntries[i].ToShaderProgramInfo();
- }
- else
- {
- var binaryCode = new Memory<byte>(entry.Code);
+ TranslatorContext currentStage = shaderContexts[stageIndex];
+ TranslatorContext nextStage = GetNextStageContext(shaderContexts, stageIndex);
+ TranslatorContext vertexA = stageIndex == 1 ? shaderContexts[0] : null;
- var gpuAccessor = new CachedGpuAccessor(
- _context,
- binaryCode,
- binaryCode.Slice(binaryCode.Length - entry.Header.Cb1DataSize),
- entry.Header.GpuAccessorHeader,
- entry.TextureDescriptors);
+ program = currentStage.Translate(out shaderProgramInfo, nextStage, vertexA);
+ }
- var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags);
- program = Translator.CreateContext(0, gpuAccessor, options, counts).Translate(out shaderProgramInfo);
- }
+ // NOTE: Vertex B comes first in the shader cache.
+ byte[] code = entry.Code.AsSpan().Slice(0, entry.Header.Size - entry.Header.Cb1DataSize).ToArray();
+ byte[] code2 = entry.Header.SizeA != 0 ? entry.Code.AsSpan().Slice(entry.Header.Size, entry.Header.SizeA).ToArray() : null;
- byte[] code = entry.Code.AsSpan().Slice(0, entry.Header.Size - entry.Header.Cb1DataSize).ToArray();
-
- shaders[i] = new ShaderCodeHolder(program, shaderProgramInfo, code);
- }
+ shaders[i] = new ShaderCodeHolder(program, shaderProgramInfo, code, code2);
shaderPrograms.Add(program);
}
@@ -591,7 +587,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
}
// The shader isn't currently cached, translate it and compile it.
- ShaderCodeHolder shader = TranslateShader(channel.MemoryManager, shaderContexts[0]);
+ ShaderCodeHolder shader = TranslateShader(_dumper, channel.MemoryManager, shaderContexts[0], null, null);
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
@@ -715,11 +711,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
// The shader isn't currently cached, translate it and compile it.
ShaderCodeHolder[] shaders = new ShaderCodeHolder[Constants.ShaderStages];
- shaders[0] = TranslateShader(channel.MemoryManager, shaderContexts[1], shaderContexts[0]);
- shaders[1] = TranslateShader(channel.MemoryManager, shaderContexts[2]);
- shaders[2] = TranslateShader(channel.MemoryManager, shaderContexts[3]);
- shaders[3] = TranslateShader(channel.MemoryManager, shaderContexts[4]);
- shaders[4] = TranslateShader(channel.MemoryManager, shaderContexts[5]);
+ for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++)
+ {
+ shaders[stageIndex] = TranslateShader(_dumper, channel.MemoryManager, shaderContexts, stageIndex + 1);
+ }
List<IShader> hostShaders = new List<IShader>();
@@ -942,53 +937,94 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary>
/// Translates a previously generated translator context to something that the host API accepts.
/// </summary>
+ /// <param name="dumper">Optional shader code dumper</param>
/// <param name="memoryManager">Memory manager used to access the GPU memory where the shader is located</param>
- /// <param name="translatorContext">Current translator context to translate</param>
- /// <param name="translatorContext2">Optional translator context of the shader that should be combined</param>
+ /// <param name="stages">Translator context of all available shader stages</param>
+ /// <param name="stageIndex">Index on the stages array to translate</param>
/// <returns>Compiled graphics shader code</returns>
- private ShaderCodeHolder TranslateShader(
+ private static ShaderCodeHolder TranslateShader(
+ ShaderDumper dumper,
MemoryManager memoryManager,
- TranslatorContext translatorContext,
- TranslatorContext translatorContext2 = null)
+ TranslatorContext[] stages,
+ int stageIndex)
{
- if (translatorContext == null)
+ TranslatorContext currentStage = stages[stageIndex];
+ TranslatorContext nextStage = GetNextStageContext(stages, stageIndex);
+ TranslatorContext vertexA = stageIndex == 1 ? stages[0] : null;
+
+ return TranslateShader(dumper, memoryManager, currentStage, nextStage, vertexA);
+ }
+
+ /// <summary>
+ /// Gets the next shader stage context, from an array of contexts and index of the current stage.
+ /// </summary>
+ /// <param name="stages">Translator context of all available shader stages</param>
+ /// <param name="stageIndex">Index on the stages array to translate</param>
+ /// <returns>The translator context of the next stage, or null if inexistent</returns>
+ private static TranslatorContext GetNextStageContext(TranslatorContext[] stages, int stageIndex)
+ {
+ for (int nextStageIndex = stageIndex + 1; nextStageIndex < stages.Length; nextStageIndex++)
{
- return null;
+ if (stages[nextStageIndex] != null)
+ {
+ return stages[nextStageIndex];
+ }
}
- if (translatorContext2 != null)
+ return null;
+ }
+
+ /// <summary>
+ /// Translates a previously generated translator context to something that the host API accepts.
+ /// </summary>
+ /// <param name="dumper">Optional shader code dumper</param>
+ /// <param name="memoryManager">Memory manager used to access the GPU memory where the shader is located</param>
+ /// <param name="currentStage">Translator context of the stage to be translated</param>
+ /// <param name="nextStage">Translator context of the next active stage, if existent</param>
+ /// <param name="vertexA">Optional translator context of the shader that should be combined</param>
+ /// <returns>Compiled graphics shader code</returns>
+ private static ShaderCodeHolder TranslateShader(
+ ShaderDumper dumper,
+ MemoryManager memoryManager,
+ TranslatorContext currentStage,
+ TranslatorContext nextStage,
+ TranslatorContext vertexA)
+ {
+ if (currentStage == null)
{
- byte[] codeA = memoryManager.GetSpan(translatorContext2.Address, translatorContext2.Size).ToArray();
- byte[] codeB = memoryManager.GetSpan(translatorContext.Address, translatorContext.Size).ToArray();
+ return null;
+ }
- _dumper.Dump(codeA, compute: false, out string fullPathA, out string codePathA);
- _dumper.Dump(codeB, compute: false, out string fullPathB, out string codePathB);
+ if (vertexA != null)
+ {
+ byte[] codeA = memoryManager.GetSpan(vertexA.Address, vertexA.Size).ToArray();
+ byte[] codeB = memoryManager.GetSpan(currentStage.Address, currentStage.Size).ToArray();
- ShaderProgram program = translatorContext.Translate(out ShaderProgramInfo shaderProgramInfo, translatorContext2);
+ ShaderDumpPaths pathsA = default;
+ ShaderDumpPaths pathsB = default;
- if (fullPathA != null && fullPathB != null && codePathA != null && codePathB != null)
+ if (dumper != null)
{
- program.Prepend("// " + codePathB);
- program.Prepend("// " + fullPathB);
- program.Prepend("// " + codePathA);
- program.Prepend("// " + fullPathA);
+ pathsA = dumper.Dump(codeA, compute: false);
+ pathsB = dumper.Dump(codeB, compute: false);
}
+ ShaderProgram program = currentStage.Translate(out ShaderProgramInfo shaderProgramInfo, nextStage, vertexA);
+
+ pathsB.Prepend(program);
+ pathsA.Prepend(program);
+
return new ShaderCodeHolder(program, shaderProgramInfo, codeB, codeA);
}
else
{
- byte[] code = memoryManager.GetSpan(translatorContext.Address, translatorContext.Size).ToArray();
+ byte[] code = memoryManager.GetSpan(currentStage.Address, currentStage.Size).ToArray();
- _dumper.Dump(code, translatorContext.Stage == ShaderStage.Compute, out string fullPath, out string codePath);
+ ShaderDumpPaths paths = dumper?.Dump(code, currentStage.Stage == ShaderStage.Compute) ?? default;
- ShaderProgram program = translatorContext.Translate(out ShaderProgramInfo shaderProgramInfo);
+ ShaderProgram program = currentStage.Translate(out ShaderProgramInfo shaderProgramInfo, nextStage);
- if (fullPath != null && codePath != null)
- {
- program.Prepend("// " + codePath);
- program.Prepend("// " + fullPath);
- }
+ paths.Prepend(program);
return new ShaderCodeHolder(program, shaderProgramInfo, code);
}