diff options
Diffstat (limited to 'Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs')
-rw-r--r-- | Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs b/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs new file mode 100644 index 00000000..3092e077 --- /dev/null +++ b/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs @@ -0,0 +1,160 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System.Collections.Generic; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; +using static Ryujinx.Graphics.Shader.Translation.Translator; + +namespace Ryujinx.Graphics.Shader.Translation +{ + public class TranslatorContext + { + private readonly Block[][] _cfg; + private readonly Block[][] _cfgA; + private ShaderConfig _config; + private ShaderConfig _configA; + + public ulong Address { get; } + public ulong AddressA { get; } + + public ShaderStage Stage => _config.Stage; + public int Size => _config.Size; + public int SizeA => _configA != null ? _configA.Size : 0; + + public HashSet<int> TextureHandlesForCache => _config.TextureHandlesForCache; + + public IGpuAccessor GpuAccessor => _config.GpuAccessor; + + internal TranslatorContext(ulong address, Block[][] cfg, ShaderConfig config) + { + Address = address; + AddressA = 0; + _config = config; + _configA = null; + _cfg = cfg; + _cfgA = null; + } + + internal TranslatorContext(ulong addressA, ulong addressB, Block[][] cfgA, Block[][] cfgB, ShaderConfig configA, ShaderConfig configB) + { + Address = addressB; + AddressA = addressA; + _config = configB; + _configA = configA; + _cfg = cfgB; + _cfgA = cfgA; + } + + private static bool IsUserAttribute(Operand operand) + { + return operand != null && + operand.Type == OperandType.Attribute && + operand.Value >= AttributeConsts.UserAttributeBase && + operand.Value < AttributeConsts.UserAttributeEnd; + } + + 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; + } + + public ShaderProgram Translate(out ShaderProgramInfo shaderProgramInfo) + { + FunctionCode[] code = EmitShader(_cfg, _config); + + if (_configA != null) + { + FunctionCode[] codeA = EmitShader(_cfgA, _configA); + + _config.SetUsedFeature(_configA.UsedFeatures); + + code = Combine(codeA, code); + } + + return Translator.Translate(code, _config, out shaderProgramInfo, SizeA); + } + } +} |