diff options
author | gdkchan <gab.dark.100@gmail.com> | 2021-08-11 17:27:00 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-11 22:27:00 +0200 |
commit | ed754af8d5046d2fd7218c742521e38ab17cbcfe (patch) | |
tree | d47eda40349a7b4b3fc34d9db9ddeea8f2d0676a /Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | |
parent | 10d649e6d3ad3e4af32d2b41e718bb0a2924da67 (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.cs | 212 |
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); } |