aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/Translation/Translator.cs
diff options
context:
space:
mode:
authorMary <me@thog.eu>2020-11-13 00:15:34 +0100
committerGitHub <noreply@github.com>2020-11-13 00:15:34 +0100
commit48f6570557fc76496936514d94e3ccddf55ec633 (patch)
treece455833899cb33a312e5853a7a3d191bb5d18d9 /Ryujinx.Graphics.Shader/Translation/Translator.cs
parent7166e82c3cf1fd8cf2fce3281017ee88122684d8 (diff)
Salieri: shader cache (#1701)
Here come Salieri, my implementation of a disk shader cache! "I'm sure you know why I named it that." "It doesn't really mean anything." This implementation collects shaders at runtime and cache them to be later compiled when starting a game.
Diffstat (limited to 'Ryujinx.Graphics.Shader/Translation/Translator.cs')
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Translator.cs162
1 files changed, 39 insertions, 123 deletions
diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs
index 3485b5ed..85a46d19 100644
--- a/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -3,7 +3,6 @@ using Ryujinx.Graphics.Shader.Decoders;
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr;
using Ryujinx.Graphics.Shader.Translation.Optimizations;
-using System;
using System.Collections.Generic;
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
@@ -14,7 +13,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
private const int HeaderSize = 0x50;
- private struct FunctionCode
+ internal struct FunctionCode
{
public Operation[] Code { get; }
@@ -24,7 +23,7 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
- public static ShaderProgram Translate(
+ public static TranslatorContext CreateContext(
ulong address,
IGpuAccessor gpuAccessor,
TranslationFlags flags,
@@ -32,10 +31,12 @@ namespace Ryujinx.Graphics.Shader.Translation
{
counts ??= new TranslationCounts();
- return Translate(DecodeShader(address, gpuAccessor, flags, counts, out ShaderConfig config), config);
+ Block[][] cfg = DecodeShader(address, gpuAccessor, flags, counts, out ShaderConfig config);
+
+ return new TranslatorContext(address, cfg, config);
}
- public static ShaderProgram Translate(
+ public static TranslatorContext CreateContext(
ulong addressA,
ulong addressB,
IGpuAccessor gpuAccessor,
@@ -44,15 +45,13 @@ namespace Ryujinx.Graphics.Shader.Translation
{
counts ??= new TranslationCounts();
- FunctionCode[] funcA = DecodeShader(addressA, gpuAccessor, flags | TranslationFlags.VertexA, counts, out ShaderConfig configA);
- FunctionCode[] funcB = DecodeShader(addressB, gpuAccessor, flags, counts, out ShaderConfig config);
-
- config.SetUsedFeature(configA.UsedFeatures);
+ Block[][] cfgA = DecodeShader(addressA, gpuAccessor, flags | TranslationFlags.VertexA, counts, out ShaderConfig configA);
+ Block[][] cfgB = DecodeShader(addressB, gpuAccessor, flags, counts, out ShaderConfig configB);
- return Translate(Combine(funcA, funcB), config, configA.Size);
+ return new TranslatorContext(addressA, addressB, cfgA, cfgB, configA, configB);
}
- private static ShaderProgram Translate(FunctionCode[] functions, ShaderConfig config, int sizeA = 0)
+ internal static ShaderProgram Translate(FunctionCode[] functions, ShaderConfig config, out ShaderProgramInfo shaderProgramInfo, int sizeA = 0)
{
var cfgs = new ControlFlowGraph[functions.Length];
var frus = new RegisterUsage.FunctionRegisterUsage[functions.Length];
@@ -106,7 +105,7 @@ namespace Ryujinx.Graphics.Shader.Translation
GlslProgram program = GlslGenerator.Generate(sInfo, config);
- ShaderProgramInfo spInfo = new ShaderProgramInfo(
+ shaderProgramInfo = new ShaderProgramInfo(
program.CBufferDescriptors,
program.SBufferDescriptors,
program.TextureDescriptors,
@@ -115,10 +114,10 @@ namespace Ryujinx.Graphics.Shader.Translation
string glslCode = program.Code;
- return new ShaderProgram(spInfo, config.Stage, glslCode, config.Size, sizeA);
+ return new ShaderProgram(config.Stage, glslCode, config.Size, sizeA);
}
- private static FunctionCode[] DecodeShader(
+ private static Block[][] DecodeShader(
ulong address,
IGpuAccessor gpuAccessor,
TranslationFlags flags,
@@ -126,6 +125,7 @@ namespace Ryujinx.Graphics.Shader.Translation
out ShaderConfig config)
{
Block[][] cfg;
+ ulong maxEndAddress = 0;
if ((flags & TranslationFlags.Compute) != 0)
{
@@ -140,13 +140,34 @@ namespace Ryujinx.Graphics.Shader.Translation
cfg = Decoder.Decode(gpuAccessor, address + HeaderSize);
}
- if (cfg == null)
+ for (int funcIndex = 0; funcIndex < cfg.Length; funcIndex++)
{
- gpuAccessor.Log("Invalid branch detected, failed to build CFG.");
+ for (int blkIndex = 0; blkIndex < cfg[funcIndex].Length; blkIndex++)
+ {
+ Block block = cfg[funcIndex][blkIndex];
+
+ if (maxEndAddress < block.EndAddress)
+ {
+ maxEndAddress = block.EndAddress;
+ }
- return Array.Empty<FunctionCode>();
+ for (int index = 0; index < block.OpCodes.Count; index++)
+ {
+ if (block.OpCodes[index] is OpCodeTextureBase texture)
+ {
+ config.TextureHandlesForCache.Add(texture.HandleOffset);
+ }
+ }
+ }
}
+ config.SizeAdd((int)maxEndAddress + (flags.HasFlag(TranslationFlags.Compute) ? 0 : HeaderSize));
+
+ return cfg;
+ }
+
+ internal static FunctionCode[] EmitShader(Block[][] cfg, ShaderConfig config)
+ {
Dictionary<ulong, int> funcIds = new Dictionary<ulong, int>();
for (int funcIndex = 0; funcIndex < cfg.Length; funcIndex++)
@@ -156,8 +177,6 @@ namespace Ryujinx.Graphics.Shader.Translation
List<FunctionCode> funcs = new List<FunctionCode>();
- ulong maxEndAddress = 0;
-
for (int funcIndex = 0; funcIndex < cfg.Length; funcIndex++)
{
EmitterContext context = new EmitterContext(config, funcIndex != 0, funcIds);
@@ -166,11 +185,6 @@ namespace Ryujinx.Graphics.Shader.Translation
{
Block block = cfg[funcIndex][blkIndex];
- if (maxEndAddress < block.EndAddress)
- {
- maxEndAddress = block.EndAddress;
- }
-
context.CurrBlock = block;
context.MarkLabel(context.GetLabel(block.Address));
@@ -181,12 +195,10 @@ namespace Ryujinx.Graphics.Shader.Translation
funcs.Add(new FunctionCode(context.GetOperations()));
}
- config.SizeAdd((int)maxEndAddress + (flags.HasFlag(TranslationFlags.Compute) ? 0 : HeaderSize));
-
return funcs.ToArray();
}
- internal static void EmitOps(EmitterContext context, Block block)
+ private static void EmitOps(EmitterContext context, Block block)
{
for (int opIndex = 0; opIndex < block.OpCodes.Count; opIndex++)
{
@@ -267,101 +279,5 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
}
-
- private static FunctionCode[] Combine(FunctionCode[] a, FunctionCode[] b)
- {
- // Here we combine two shaders.
- // For shader A:
- // - All user attribute stores on shader A are turned into copies to a
- // temporary variable. It's assumed that shader B will consume them.
- // - All return instructions are turned into branch instructions, the
- // branch target being the start of the shader B code.
- // For shader B:
- // - All user attribute loads on shader B are turned into copies from a
- // temporary variable, as long that attribute is written by shader A.
- FunctionCode[] output = new FunctionCode[a.Length + b.Length - 1];
-
- List<Operation> ops = new List<Operation>(a.Length + b.Length);
-
- Operand[] temps = new Operand[AttributeConsts.UserAttributesCount * 4];
-
- Operand lblB = Label();
-
- for (int index = 0; index < a[0].Code.Length; index++)
- {
- Operation operation = a[0].Code[index];
-
- if (IsUserAttribute(operation.Dest))
- {
- int tIndex = (operation.Dest.Value - AttributeConsts.UserAttributeBase) / 4;
-
- Operand temp = temps[tIndex];
-
- if (temp == null)
- {
- temp = Local();
-
- temps[tIndex] = temp;
- }
-
- operation.Dest = temp;
- }
-
- if (operation.Inst == Instruction.Return)
- {
- ops.Add(new Operation(Instruction.Branch, lblB));
- }
- else
- {
- ops.Add(operation);
- }
- }
-
- ops.Add(new Operation(Instruction.MarkLabel, lblB));
-
- for (int index = 0; index < b[0].Code.Length; index++)
- {
- Operation operation = b[0].Code[index];
-
- for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++)
- {
- Operand src = operation.GetSource(srcIndex);
-
- if (IsUserAttribute(src))
- {
- Operand temp = temps[(src.Value - AttributeConsts.UserAttributeBase) / 4];
-
- if (temp != null)
- {
- operation.SetSource(srcIndex, temp);
- }
- }
- }
-
- ops.Add(operation);
- }
-
- output[0] = new FunctionCode(ops.ToArray());
-
- for (int i = 1; i < a.Length; i++)
- {
- output[i] = a[i];
- }
-
- for (int i = 1; i < b.Length; i++)
- {
- output[a.Length + i - 1] = b[i];
- }
-
- return output;
- }
-
- private static bool IsUserAttribute(Operand operand)
- {
- return operand != null &&
- operand.Type == OperandType.Attribute &&
- operand.Value >= AttributeConsts.UserAttributeBase &&
- operand.Value < AttributeConsts.UserAttributeEnd;
- }
}
} \ No newline at end of file