aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/Translation
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Shader/Translation')
-rw-r--r--Ryujinx.Graphics.Shader/Translation/AggregateType.cs18
-rw-r--r--Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs1
-rw-r--r--Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs166
-rw-r--r--Ryujinx.Graphics.Shader/Translation/EmitterContext.cs111
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs57
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Ssa.cs77
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Translator.cs9
7 files changed, 412 insertions, 27 deletions
diff --git a/Ryujinx.Graphics.Shader/Translation/AggregateType.cs b/Ryujinx.Graphics.Shader/Translation/AggregateType.cs
new file mode 100644
index 00000000..dcd1e0bd
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Translation/AggregateType.cs
@@ -0,0 +1,18 @@
+namespace Ryujinx.Graphics.Shader.Translation
+{
+ enum AggregateType
+ {
+ Invalid,
+ Void,
+ Bool,
+ FP32,
+ FP64,
+ S32,
+ U32,
+
+ ElementTypeMask = 0xff,
+
+ Vector = 1 << 8,
+ Array = 1 << 9
+ }
+}
diff --git a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
index ada60ab9..0c3ab08e 100644
--- a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
+++ b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
@@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public const int TessLevelInner0 = 0x010;
public const int TessLevelInner1 = 0x014;
public const int Layer = 0x064;
+ public const int ViewportIndex = 0x068;
public const int PointSize = 0x06c;
public const int PositionX = 0x070;
public const int PositionY = 0x074;
diff --git a/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs b/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs
new file mode 100644
index 00000000..9af5bacf
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs
@@ -0,0 +1,166 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Shader.Translation
+{
+ struct AttributeInfo
+ {
+ private static readonly Dictionary<int, AttributeInfo> BuiltInAttributes = new Dictionary<int, AttributeInfo>()
+ {
+ { AttributeConsts.TessLevelOuter0, new AttributeInfo(AttributeConsts.TessLevelOuter0, 0, 4, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.TessLevelOuter1, new AttributeInfo(AttributeConsts.TessLevelOuter0, 1, 4, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.TessLevelOuter2, new AttributeInfo(AttributeConsts.TessLevelOuter0, 2, 4, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.TessLevelOuter3, new AttributeInfo(AttributeConsts.TessLevelOuter0, 3, 4, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.TessLevelInner0, new AttributeInfo(AttributeConsts.TessLevelInner0, 0, 2, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.TessLevelInner1, new AttributeInfo(AttributeConsts.TessLevelInner0, 1, 2, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.Layer, new AttributeInfo(AttributeConsts.Layer, 0, 1, AggregateType.S32) },
+ { AttributeConsts.ViewportIndex, new AttributeInfo(AttributeConsts.ViewportIndex, 0, 1, AggregateType.S32) },
+ { AttributeConsts.PointSize, new AttributeInfo(AttributeConsts.PointSize, 0, 1, AggregateType.FP32) },
+ { AttributeConsts.PositionX, new AttributeInfo(AttributeConsts.PositionX, 0, 4, AggregateType.Vector | AggregateType.FP32) },
+ { AttributeConsts.PositionY, new AttributeInfo(AttributeConsts.PositionX, 1, 4, AggregateType.Vector | AggregateType.FP32) },
+ { AttributeConsts.PositionZ, new AttributeInfo(AttributeConsts.PositionX, 2, 4, AggregateType.Vector | AggregateType.FP32) },
+ { AttributeConsts.PositionW, new AttributeInfo(AttributeConsts.PositionX, 3, 4, AggregateType.Vector | AggregateType.FP32) },
+ { AttributeConsts.ClipDistance0, new AttributeInfo(AttributeConsts.ClipDistance0, 0, 8, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.ClipDistance1, new AttributeInfo(AttributeConsts.ClipDistance0, 1, 8, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.ClipDistance2, new AttributeInfo(AttributeConsts.ClipDistance0, 2, 8, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.ClipDistance3, new AttributeInfo(AttributeConsts.ClipDistance0, 3, 8, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.ClipDistance4, new AttributeInfo(AttributeConsts.ClipDistance0, 4, 8, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.ClipDistance5, new AttributeInfo(AttributeConsts.ClipDistance0, 5, 8, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.ClipDistance6, new AttributeInfo(AttributeConsts.ClipDistance0, 6, 8, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.ClipDistance7, new AttributeInfo(AttributeConsts.ClipDistance0, 7, 8, AggregateType.Array | AggregateType.FP32) },
+ { AttributeConsts.PointCoordX, new AttributeInfo(AttributeConsts.PointCoordX, 0, 2, AggregateType.Vector | AggregateType.FP32) },
+ { AttributeConsts.PointCoordY, new AttributeInfo(AttributeConsts.PointCoordX, 1, 2, AggregateType.Vector | AggregateType.FP32) },
+ { AttributeConsts.TessCoordX, new AttributeInfo(AttributeConsts.TessCoordX, 0, 2, AggregateType.Vector | AggregateType.FP32) },
+ { AttributeConsts.TessCoordY, new AttributeInfo(AttributeConsts.TessCoordX, 1, 2, AggregateType.Vector | AggregateType.FP32) },
+ { AttributeConsts.InstanceId, new AttributeInfo(AttributeConsts.InstanceId, 0, 1, AggregateType.S32) },
+ { AttributeConsts.VertexId, new AttributeInfo(AttributeConsts.VertexId, 0, 1, AggregateType.S32) },
+ { AttributeConsts.FrontFacing, new AttributeInfo(AttributeConsts.FrontFacing, 0, 1, AggregateType.Bool) },
+
+ // Special.
+ { AttributeConsts.FragmentOutputDepth, new AttributeInfo(AttributeConsts.FragmentOutputDepth, 0, 1, AggregateType.FP32) },
+ { AttributeConsts.ThreadKill, new AttributeInfo(AttributeConsts.ThreadKill, 0, 1, AggregateType.Bool) },
+ { AttributeConsts.ThreadIdX, new AttributeInfo(AttributeConsts.ThreadIdX, 0, 3, AggregateType.Vector | AggregateType.U32) },
+ { AttributeConsts.ThreadIdY, new AttributeInfo(AttributeConsts.ThreadIdX, 1, 3, AggregateType.Vector | AggregateType.U32) },
+ { AttributeConsts.ThreadIdZ, new AttributeInfo(AttributeConsts.ThreadIdX, 2, 3, AggregateType.Vector | AggregateType.U32) },
+ { AttributeConsts.CtaIdX, new AttributeInfo(AttributeConsts.CtaIdX, 0, 3, AggregateType.Vector | AggregateType.U32) },
+ { AttributeConsts.CtaIdY, new AttributeInfo(AttributeConsts.CtaIdX, 1, 3, AggregateType.Vector | AggregateType.U32) },
+ { AttributeConsts.CtaIdZ, new AttributeInfo(AttributeConsts.CtaIdX, 2, 3, AggregateType.Vector | AggregateType.U32) },
+ { AttributeConsts.LaneId, new AttributeInfo(AttributeConsts.LaneId, 0, 1, AggregateType.U32) },
+ { AttributeConsts.InvocationId, new AttributeInfo(AttributeConsts.InvocationId, 0, 1, AggregateType.S32) },
+ { AttributeConsts.PrimitiveId, new AttributeInfo(AttributeConsts.PrimitiveId, 0, 1, AggregateType.S32) },
+ { AttributeConsts.PatchVerticesIn, new AttributeInfo(AttributeConsts.PatchVerticesIn, 0, 1, AggregateType.S32) },
+ { AttributeConsts.EqMask, new AttributeInfo(AttributeConsts.EqMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
+ { AttributeConsts.GeMask, new AttributeInfo(AttributeConsts.GeMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
+ { AttributeConsts.GtMask, new AttributeInfo(AttributeConsts.GtMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
+ { AttributeConsts.LeMask, new AttributeInfo(AttributeConsts.LeMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
+ { AttributeConsts.LtMask, new AttributeInfo(AttributeConsts.LtMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
+ };
+
+ public int BaseValue { get; }
+ public int Value { get; }
+ public int Length { get; }
+ public AggregateType Type { get; }
+ public bool IsBuiltin { get; }
+ public bool IsValid => Type != AggregateType.Invalid;
+
+ public AttributeInfo(int baseValue, int index, int length, AggregateType type, bool isBuiltin = true)
+ {
+ BaseValue = baseValue;
+ Value = baseValue + index * 4;
+ Length = length;
+ Type = type;
+ IsBuiltin = isBuiltin;
+ }
+
+ public int GetInnermostIndex()
+ {
+ return (Value - BaseValue) / 4;
+ }
+
+ public static bool Validate(ShaderConfig config, int value, bool isOutAttr)
+ {
+ return From(config, value, isOutAttr).IsValid;
+ }
+
+ public static AttributeInfo From(ShaderConfig config, int value, bool isOutAttr)
+ {
+ value &= ~3;
+
+ if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
+ {
+ int location = (value - AttributeConsts.UserAttributeBase) / 16;
+
+ AggregateType elemType;
+
+ if (config.Stage == ShaderStage.Vertex && !isOutAttr)
+ {
+ elemType = config.GpuAccessor.QueryAttributeType(location) switch
+ {
+ AttributeType.Sint => AggregateType.S32,
+ AttributeType.Uint => AggregateType.U32,
+ _ => AggregateType.FP32
+ };
+ }
+ else
+ {
+ elemType = AggregateType.FP32;
+ }
+
+ return new AttributeInfo(value & ~0xf, (value >> 2) & 3, 4, AggregateType.Vector | elemType, false);
+ }
+ else if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd)
+ {
+ return new AttributeInfo(value & ~0xf, (value >> 2) & 3, 4, AggregateType.Vector | AggregateType.FP32, false);
+ }
+ else if (value == AttributeConsts.SupportBlockViewInverseX || value == AttributeConsts.SupportBlockViewInverseY)
+ {
+ return new AttributeInfo(value, 0, 1, AggregateType.FP32);
+ }
+ else if (BuiltInAttributes.TryGetValue(value, out AttributeInfo info))
+ {
+ return info;
+ }
+
+ return new AttributeInfo(value, 0, 0, AggregateType.Invalid);
+ }
+
+ public static bool IsArrayBuiltIn(int attr)
+ {
+ if (attr <= AttributeConsts.TessLevelInner1 ||
+ attr == AttributeConsts.TessCoordX ||
+ attr == AttributeConsts.TessCoordY)
+ {
+ return false;
+ }
+
+ return (attr & AttributeConsts.SpecialMask) == 0;
+ }
+
+ public static bool IsArrayAttributeGlsl(ShaderStage stage, bool isOutAttr)
+ {
+ if (isOutAttr)
+ {
+ return stage == ShaderStage.TessellationControl;
+ }
+ else
+ {
+ return stage == ShaderStage.TessellationControl ||
+ stage == ShaderStage.TessellationEvaluation ||
+ stage == ShaderStage.Geometry;
+ }
+ }
+
+ public static bool IsArrayAttributeSpirv(ShaderStage stage, bool isOutAttr)
+ {
+ if (isOutAttr)
+ {
+ return false;
+ }
+ else
+ {
+ return stage == ShaderStage.TessellationControl ||
+ stage == ShaderStage.TessellationEvaluation ||
+ stage == ShaderStage.Geometry;
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 332b3e02..51823240 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -2,6 +2,7 @@ using Ryujinx.Graphics.Shader.Decoders;
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Numerics;
using System.Runtime.CompilerServices;
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
@@ -30,6 +31,19 @@ namespace Ryujinx.Graphics.Shader.Translation
IsNonMain = isNonMain;
_operations = new List<Operation>();
_labels = new Dictionary<ulong, Operand>();
+
+ EmitStart();
+ }
+
+ private void EmitStart()
+ {
+ if (Config.Stage == ShaderStage.Vertex &&
+ Config.Options.TargetApi == TargetApi.Vulkan &&
+ (Config.Options.Flags & TranslationFlags.VertexA) == 0)
+ {
+ // Vulkan requires the point size to be always written on the shader if the primitive topology is points.
+ this.Copy(Attribute(AttributeConsts.PointSize), ConstF(Config.GpuAccessor.QueryPointSize()));
+ }
}
public T GetOp<T>() where T : unmanaged
@@ -43,7 +57,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
Operation operation = new Operation(inst, dest, sources);
- Add(operation);
+ _operations.Add(operation);
return dest;
}
@@ -167,6 +181,15 @@ namespace Ryujinx.Graphics.Shader.Translation
this.Copy(Attribute(AttributeConsts.PositionX), this.FPFusedMultiplyAdd(x, xScale, negativeOne));
this.Copy(Attribute(AttributeConsts.PositionY), this.FPFusedMultiplyAdd(y, yScale, negativeOne));
}
+
+ if (Config.Options.TargetApi == TargetApi.Vulkan && Config.GpuAccessor.QueryTransformDepthMinusOneToOne())
+ {
+ Operand z = Attribute(AttributeConsts.PositionZ | AttributeConsts.LoadOutputMask);
+ Operand w = Attribute(AttributeConsts.PositionW | AttributeConsts.LoadOutputMask);
+ Operand halfW = this.FPMultiply(w, ConstF(0.5f));
+
+ this.Copy(Attribute(AttributeConsts.PositionZ), this.FPFusedMultiplyAdd(z, ConstF(0.5f), halfW));
+ }
}
public void PrepareForVertexReturn(out Operand oldXLocal, out Operand oldYLocal, out Operand oldZLocal)
@@ -184,8 +207,15 @@ namespace Ryujinx.Graphics.Shader.Translation
oldYLocal = null;
}
- // Will be used by Vulkan backend for depth mode emulation.
- oldZLocal = null;
+ if (Config.Options.TargetApi == TargetApi.Vulkan && Config.GpuAccessor.QueryTransformDepthMinusOneToOne())
+ {
+ oldZLocal = Local();
+ this.Copy(oldZLocal, Attribute(AttributeConsts.PositionZ | AttributeConsts.LoadOutputMask));
+ }
+ else
+ {
+ oldZLocal = null;
+ }
PrepareForVertexReturn();
}
@@ -203,10 +233,50 @@ namespace Ryujinx.Graphics.Shader.Translation
{
PrepareForVertexReturn();
}
+ else if (Config.Stage == ShaderStage.Geometry)
+ {
+ void WriteOutput(int index, int primIndex)
+ {
+ Operand x = this.LoadAttribute(Const(index), Const(0), Const(primIndex));
+ Operand y = this.LoadAttribute(Const(index + 4), Const(0), Const(primIndex));
+ Operand z = this.LoadAttribute(Const(index + 8), Const(0), Const(primIndex));
+ Operand w = this.LoadAttribute(Const(index + 12), Const(0), Const(primIndex));
+
+ this.Copy(Attribute(index), x);
+ this.Copy(Attribute(index + 4), y);
+ this.Copy(Attribute(index + 8), z);
+ this.Copy(Attribute(index + 12), w);
+ }
+
+ if (Config.GpPassthrough)
+ {
+ int inputVertices = Config.GpuAccessor.QueryPrimitiveTopology().ToInputVertices();
+
+ for (int primIndex = 0; primIndex < inputVertices; primIndex++)
+ {
+ WriteOutput(AttributeConsts.PositionX, primIndex);
+
+ int passthroughAttributes = Config.PassthroughAttributes;
+ while (passthroughAttributes != 0)
+ {
+ int index = BitOperations.TrailingZeroCount(passthroughAttributes);
+ WriteOutput(AttributeConsts.UserAttributeBase + index * 16, primIndex);
+ Config.SetOutputUserAttribute(index, perPatch: false);
+ passthroughAttributes &= ~(1 << index);
+ }
+
+ this.EmitVertex();
+ }
+
+ this.EndPrimitive();
+ }
+ }
else if (Config.Stage == ShaderStage.Fragment)
{
GenerateAlphaToCoverageDitherDiscard();
+ bool supportsBgra = Config.GpuAccessor.QueryHostSupportsBgraFormat();
+
if (Config.OmapDepth)
{
Operand dest = Attribute(AttributeConsts.FragmentOutputDepth);
@@ -216,7 +286,40 @@ namespace Ryujinx.Graphics.Shader.Translation
this.Copy(dest, src);
}
- bool supportsBgra = Config.GpuAccessor.QueryHostSupportsBgraFormat();
+ AlphaTestOp alphaTestOp = Config.GpuAccessor.QueryAlphaTestCompare();
+
+ if (alphaTestOp != AlphaTestOp.Always && (Config.OmapTargets & 8) != 0)
+ {
+ if (alphaTestOp == AlphaTestOp.Never)
+ {
+ this.Discard();
+ }
+ else
+ {
+ Instruction comparator = alphaTestOp switch
+ {
+ AlphaTestOp.Equal => Instruction.CompareEqual,
+ AlphaTestOp.Greater => Instruction.CompareGreater,
+ AlphaTestOp.GreaterOrEqual => Instruction.CompareGreaterOrEqual,
+ AlphaTestOp.Less => Instruction.CompareLess,
+ AlphaTestOp.LessOrEqual => Instruction.CompareLessOrEqual,
+ AlphaTestOp.NotEqual => Instruction.CompareNotEqual,
+ _ => 0
+ };
+
+ Debug.Assert(comparator != 0, $"Invalid alpha test operation \"{alphaTestOp}\".");
+
+ Operand alpha = Register(3, RegisterType.Gpr);
+ Operand alphaRef = ConstF(Config.GpuAccessor.QueryAlphaTestReference());
+ Operand alphaPass = Add(Instruction.FP32 | comparator, Local(), alpha, alphaRef);
+ Operand alphaPassLabel = Label();
+
+ this.BranchIfTrue(alphaPassLabel, alphaPass);
+ this.Discard();
+ this.MarkLabel(alphaPassLabel);
+ }
+ }
+
int regIndexBase = 0;
for (int rtIndex = 0; rtIndex < 8; rtIndex++)
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index bac83861..221ca1d4 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -1,4 +1,5 @@
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using Ryujinx.Graphics.Shader.StructuredIr;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,6 +12,8 @@ namespace Ryujinx.Graphics.Shader.Translation
// TODO: Non-hardcoded array size.
public const int SamplerArraySize = 4;
+ private const int ThreadsPerWarp = 32;
+
public ShaderStage Stage { get; }
public bool GpPassthrough { get; }
@@ -130,7 +133,7 @@ namespace Ryujinx.Graphics.Shader.Translation
ThreadsPerInputPrimitive = header.ThreadsPerInputPrimitive;
OutputTopology = header.OutputTopology;
MaxOutputVertices = header.MaxOutputVertexCount;
- LocalMemorySize = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize;
+ LocalMemorySize = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize + (header.ShaderLocalMemoryCrsSize / ThreadsPerWarp);
ImapTypes = header.ImapTypes;
OmapTargets = header.OmapTargets;
OmapSampleMask = header.OmapSampleMask;
@@ -581,7 +584,7 @@ namespace Ryujinx.Graphics.Shader.Translation
return _cachedImageDescriptors ??= GetTextureOrImageDescriptors(_usedImages, GpuAccessor.QueryBindingImage);
}
- private static TextureDescriptor[] GetTextureOrImageDescriptors(Dictionary<TextureInfo, TextureMeta> dict, Func<int, int> getBindingCallback)
+ private static TextureDescriptor[] GetTextureOrImageDescriptors(Dictionary<TextureInfo, TextureMeta> dict, Func<int, bool, int> getBindingCallback)
{
var descriptors = new TextureDescriptor[dict.Count];
@@ -591,7 +594,8 @@ namespace Ryujinx.Graphics.Shader.Translation
var info = kv.Key;
var meta = kv.Value;
- int binding = getBindingCallback(i);
+ bool isBuffer = (meta.Type & SamplerType.Mask) == SamplerType.TextureBuffer;
+ int binding = getBindingCallback(i, isBuffer);
descriptors[i] = new TextureDescriptor(binding, meta.Type, info.Format, info.CbufSlot, info.Handle);
descriptors[i].SetFlag(meta.UsageFlags);
@@ -600,5 +604,52 @@ namespace Ryujinx.Graphics.Shader.Translation
return descriptors;
}
+
+ public (TextureDescriptor, int) FindTextureDescriptor(AstTextureOperation texOp)
+ {
+ TextureDescriptor[] descriptors = GetTextureDescriptors();
+
+ for (int i = 0; i < descriptors.Length; i++)
+ {
+ var descriptor = descriptors[i];
+
+ if (descriptor.CbufSlot == texOp.CbufSlot &&
+ descriptor.HandleIndex == texOp.Handle &&
+ descriptor.Format == texOp.Format)
+ {
+ return (descriptor, i);
+ }
+ }
+
+ return (default, -1);
+ }
+
+ private static int FindDescriptorIndex(TextureDescriptor[] array, AstTextureOperation texOp)
+ {
+ for (int i = 0; i < array.Length; i++)
+ {
+ var descriptor = array[i];
+
+ if (descriptor.Type == texOp.Type &&
+ descriptor.CbufSlot == texOp.CbufSlot &&
+ descriptor.HandleIndex == texOp.Handle &&
+ descriptor.Format == texOp.Format)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ public int FindTextureDescriptorIndex(AstTextureOperation texOp)
+ {
+ return FindDescriptorIndex(GetTextureDescriptors(), texOp);
+ }
+
+ public int FindImageDescriptorIndex(AstTextureOperation texOp)
+ {
+ return FindDescriptorIndex(GetImageDescriptors(), texOp);
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/Ssa.cs b/Ryujinx.Graphics.Shader/Translation/Ssa.cs
index ff0fa2b7..8c63d72d 100644
--- a/Ryujinx.Graphics.Shader/Translation/Ssa.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Ssa.cs
@@ -63,6 +63,51 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
+ private class LocalDefMap
+ {
+ private Operand[] _map;
+ private int[] _uses;
+ public int UseCount { get; private set; }
+
+ public LocalDefMap()
+ {
+ _map = new Operand[RegisterConsts.TotalCount];
+ _uses = new int[RegisterConsts.TotalCount];
+ }
+
+ public Operand Get(int key)
+ {
+ return _map[key];
+ }
+
+ public void Add(int key, Operand operand)
+ {
+ if (_map[key] == null)
+ {
+ _uses[UseCount++] = key;
+ }
+
+ _map[key] = operand;
+ }
+
+ public Operand GetUse(int index, out int key)
+ {
+ key = _uses[index];
+
+ return _map[key];
+ }
+
+ public void Clear()
+ {
+ for (int i = 0; i < UseCount; i++)
+ {
+ _map[_uses[i]] = null;
+ }
+
+ UseCount = 0;
+ }
+ }
+
private struct Definition
{
public BasicBlock Block { get; }
@@ -78,6 +123,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public static void Rename(BasicBlock[] blocks)
{
DefMap[] globalDefs = new DefMap[blocks.Length];
+ LocalDefMap localDefs = new LocalDefMap();
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
{
@@ -89,13 +135,11 @@ namespace Ryujinx.Graphics.Shader.Translation
// First pass, get all defs and locals uses.
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
{
- Operand[] localDefs = new Operand[RegisterConsts.TotalCount];
-
Operand RenameLocal(Operand operand)
{
if (operand != null && operand.Type == OperandType.Register)
{
- Operand local = localDefs[GetKeyFromRegister(operand.GetRegister())];
+ Operand local = localDefs.Get(GetKeyFromRegister(operand.GetRegister()));
operand = local ?? operand;
}
@@ -124,7 +168,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
Operand local = Local();
- localDefs[GetKeyFromRegister(dest.GetRegister())] = local;
+ localDefs.Add(GetKeyFromRegister(dest.GetRegister()), local);
operation.SetDest(index, local);
}
@@ -134,16 +178,12 @@ namespace Ryujinx.Graphics.Shader.Translation
node = node.Next;
}
- for (int index = 0; index < RegisterConsts.TotalCount; index++)
+ int localUses = localDefs.UseCount;
+ for (int index = 0; index < localUses; index++)
{
- Operand local = localDefs[index];
+ Operand local = localDefs.GetUse(index, out int key);
- if (local == null)
- {
- continue;
- }
-
- Register reg = GetRegisterFromKey(index);
+ Register reg = GetRegisterFromKey(key);
globalDefs[block.Index].TryAddOperand(reg, local);
@@ -160,13 +200,13 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
}
+
+ localDefs.Clear();
}
// Second pass, rename variables with definitions on different blocks.
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
{
- Operand[] localDefs = new Operand[RegisterConsts.TotalCount];
-
BasicBlock block = blocks[blkIndex];
Operand RenameGlobal(Operand operand)
@@ -175,7 +215,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
int key = GetKeyFromRegister(operand.GetRegister());
- Operand local = localDefs[key];
+ Operand local = localDefs.Get(key);
if (local != null)
{
@@ -184,7 +224,7 @@ namespace Ryujinx.Graphics.Shader.Translation
operand = FindDefinitionForCurr(globalDefs, block, operand.GetRegister());
- localDefs[key] = operand;
+ localDefs.Add(key, operand);
}
return operand;
@@ -200,6 +240,11 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
}
+
+ if (blkIndex < blocks.Length - 1)
+ {
+ localDefs.Clear();
+ }
}
}
diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs
index e1614e66..7bddf459 100644
--- a/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -1,4 +1,5 @@
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
+using Ryujinx.Graphics.Shader.CodeGen.Spirv;
using Ryujinx.Graphics.Shader.Decoders;
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr;
@@ -72,16 +73,15 @@ namespace Ryujinx.Graphics.Shader.Translation
Ssa.Rename(cfg.Blocks);
Optimizer.RunPass(cfg.Blocks, config);
-
Rewriter.RunPass(cfg.Blocks, config);
}
funcs[i] = new Function(cfg.Blocks, $"fun{i}", false, inArgumentsCount, outArgumentsCount);
}
- StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(funcs, config);
+ var sInfo = StructuredProgram.MakeStructuredProgram(funcs, config);
- ShaderProgramInfo info = new ShaderProgramInfo(
+ var info = new ShaderProgramInfo(
config.GetConstantBufferDescriptors(),
config.GetStorageBufferDescriptors(),
config.GetTextureDescriptors(),
@@ -95,6 +95,7 @@ namespace Ryujinx.Graphics.Shader.Translation
return config.Options.TargetLanguage switch
{
TargetLanguage.Glsl => new ShaderProgram(info, TargetLanguage.Glsl, GlslGenerator.Generate(sInfo, config)),
+ TargetLanguage.Spirv => new ShaderProgram(info, TargetLanguage.Spirv, SpirvGenerator.Generate(sInfo, config)),
_ => throw new NotImplementedException(config.Options.TargetLanguage.ToString())
};
}
@@ -105,7 +106,7 @@ namespace Ryujinx.Graphics.Shader.Translation
DecodedProgram program;
ulong maxEndAddress = 0;
- if ((options.Flags & TranslationFlags.Compute) != 0)
+ if (options.Flags.HasFlag(TranslationFlags.Compute))
{
config = new ShaderConfig(gpuAccessor, options);