aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs')
-rw-r--r--Ryujinx.Graphics.Shader/Translation/TranslatorContext.cs160
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);
+ }
+ }
+}