diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/IntermediateRepresentation')
15 files changed, 1036 insertions, 0 deletions
diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/BasicBlock.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/BasicBlock.cs new file mode 100644 index 00000000..2aca118b --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/BasicBlock.cs @@ -0,0 +1,91 @@ +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + class BasicBlock + { + public int Index { get; set; } + + public LinkedList<INode> Operations { get; } + + private BasicBlock _next; + private BasicBlock _branch; + + public BasicBlock Next + { + get => _next; + set => _next = AddSuccessor(_next, value); + } + + public BasicBlock Branch + { + get => _branch; + set => _branch = AddSuccessor(_branch, value); + } + + public bool HasBranch => _branch != null; + public bool Reachable => Index == 0 || Predecessors.Count != 0; + + public List<BasicBlock> Predecessors { get; } + + public HashSet<BasicBlock> DominanceFrontiers { get; } + + public BasicBlock ImmediateDominator { get; set; } + + public BasicBlock() + { + Operations = new LinkedList<INode>(); + + Predecessors = new List<BasicBlock>(); + + DominanceFrontiers = new HashSet<BasicBlock>(); + } + + public BasicBlock(int index) : this() + { + Index = index; + } + + private BasicBlock AddSuccessor(BasicBlock oldBlock, BasicBlock newBlock) + { + oldBlock?.Predecessors.Remove(this); + newBlock?.Predecessors.Add(this); + + return newBlock; + } + + public INode GetLastOp() + { + return Operations.Last?.Value; + } + + public void Append(INode node) + { + INode lastOp = GetLastOp(); + + if (lastOp is Operation operation && IsControlFlowInst(operation.Inst)) + { + Operations.AddBefore(Operations.Last, node); + } + else + { + Operations.AddLast(node); + } + } + + private static bool IsControlFlowInst(Instruction inst) + { + switch (inst) + { + case Instruction.Branch: + case Instruction.BranchIfFalse: + case Instruction.BranchIfTrue: + case Instruction.Discard: + case Instruction.Return: + return true; + } + + return false; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/CommentNode.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/CommentNode.cs new file mode 100644 index 00000000..d4d87b06 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/CommentNode.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + class CommentNode : Operation + { + public string Comment { get; } + + public CommentNode(string comment) : base(Instruction.Comment, null) + { + Comment = comment; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Function.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Function.cs new file mode 100644 index 00000000..e535c3fc --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Function.cs @@ -0,0 +1,23 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + class Function + { + public BasicBlock[] Blocks { get; } + + public string Name { get; } + + public bool ReturnsValue { get; } + + public int InArgumentsCount { get; } + public int OutArgumentsCount { get; } + + public Function(BasicBlock[] blocks, string name, bool returnsValue, int inArgumentsCount, int outArgumentsCount) + { + Blocks = blocks; + Name = name; + ReturnsValue = returnsValue; + InArgumentsCount = inArgumentsCount; + OutArgumentsCount = outArgumentsCount; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs new file mode 100644 index 00000000..0f545e56 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + interface INode + { + Operand Dest { get; set; } + + int DestsCount { get; } + int SourcesCount { get; } + + Operand GetDest(int index); + Operand GetSource(int index); + + void SetSource(int index, Operand operand); + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs new file mode 100644 index 00000000..d7c4a961 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Instruction.cs @@ -0,0 +1,178 @@ +using System; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + [Flags] + enum Instruction + { + Absolute = 1, + Add, + AtomicAdd, + AtomicAnd, + AtomicCompareAndSwap, + AtomicMinS32, + AtomicMinU32, + AtomicMaxS32, + AtomicMaxU32, + AtomicOr, + AtomicSwap, + AtomicXor, + Ballot, + Barrier, + BitCount, + BitfieldExtractS32, + BitfieldExtractU32, + BitfieldInsert, + BitfieldReverse, + BitwiseAnd, + BitwiseExclusiveOr, + BitwiseNot, + BitwiseOr, + Branch, + BranchIfFalse, + BranchIfTrue, + Call, + Ceiling, + Clamp, + ClampU32, + Comment, + CompareEqual, + CompareGreater, + CompareGreaterOrEqual, + CompareGreaterOrEqualU32, + CompareGreaterU32, + CompareLess, + CompareLessOrEqual, + CompareLessOrEqualU32, + CompareLessU32, + CompareNotEqual, + ConditionalSelect, + ConvertFP32ToFP64, + ConvertFP64ToFP32, + ConvertFP32ToS32, + ConvertFP32ToU32, + ConvertFP64ToS32, + ConvertFP64ToU32, + ConvertS32ToFP32, + ConvertS32ToFP64, + ConvertU32ToFP32, + ConvertU32ToFP64, + Copy, + Cosine, + Ddx, + Ddy, + Discard, + Divide, + EmitVertex, + EndPrimitive, + ExponentB2, + FSIBegin, + FSIEnd, + FindLSB, + FindMSBS32, + FindMSBU32, + Floor, + FusedMultiplyAdd, + GroupMemoryBarrier, + ImageLoad, + ImageStore, + ImageAtomic, + IsNan, + Load, + LoadConstant, + LoadGlobal, + LoadLocal, + LoadShared, + LoadStorage, + Lod, + LogarithmB2, + LogicalAnd, + LogicalExclusiveOr, + LogicalNot, + LogicalOr, + LoopBreak, + LoopContinue, + MarkLabel, + Maximum, + MaximumU32, + MemoryBarrier, + Minimum, + MinimumU32, + Multiply, + MultiplyHighS32, + MultiplyHighU32, + Negate, + PackDouble2x32, + PackHalf2x16, + ReciprocalSquareRoot, + Return, + Round, + ShiftLeft, + ShiftRightS32, + ShiftRightU32, + Shuffle, + ShuffleDown, + ShuffleUp, + ShuffleXor, + Sine, + SquareRoot, + Store, + StoreGlobal, + StoreGlobal16, + StoreGlobal8, + StoreLocal, + StoreShared, + StoreShared16, + StoreShared8, + StoreStorage, + StoreStorage16, + StoreStorage8, + Subtract, + SwizzleAdd, + TextureSample, + TextureSize, + Truncate, + UnpackDouble2x32, + UnpackHalf2x16, + VectorExtract, + VoteAll, + VoteAllEqual, + VoteAny, + + Count, + + FP32 = 1 << 16, + FP64 = 1 << 17, + + Mask = 0xffff + } + + static class InstructionExtensions + { + public static bool IsAtomic(this Instruction inst) + { + switch (inst & Instruction.Mask) + { + case Instruction.AtomicAdd: + case Instruction.AtomicAnd: + case Instruction.AtomicCompareAndSwap: + case Instruction.AtomicMaxS32: + case Instruction.AtomicMaxU32: + case Instruction.AtomicMinS32: + case Instruction.AtomicMinU32: + case Instruction.AtomicOr: + case Instruction.AtomicSwap: + case Instruction.AtomicXor: + return true; + } + + return false; + } + + public static bool IsTextureQuery(this Instruction inst) + { + inst &= Instruction.Mask; + return inst == Instruction.Lod || inst == Instruction.TextureSize; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/IoVariable.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/IoVariable.cs new file mode 100644 index 00000000..a2163d14 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/IoVariable.cs @@ -0,0 +1,51 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + enum IoVariable + { + Invalid, + + BackColorDiffuse, + BackColorSpecular, + BaseInstance, + BaseVertex, + ClipDistance, + CtaId, + DrawIndex, + FogCoord, + FragmentCoord, + FragmentOutputColor, + FragmentOutputDepth, + FragmentOutputIsBgra, // TODO: Remove and use constant buffer access. + FrontColorDiffuse, + FrontColorSpecular, + FrontFacing, + InstanceId, + InstanceIndex, + InvocationId, + Layer, + PatchVertices, + PointCoord, + PointSize, + Position, + PrimitiveId, + SubgroupEqMask, + SubgroupGeMask, + SubgroupGtMask, + SubgroupLaneId, + SubgroupLeMask, + SubgroupLtMask, + SupportBlockViewInverse, // TODO: Remove and use constant buffer access. + SupportBlockRenderScale, // TODO: Remove and use constant buffer access. + TessellationCoord, + TessellationLevelInner, + TessellationLevelOuter, + TextureCoord, + ThreadId, + ThreadKill, + UserDefined, + VertexId, + VertexIndex, + ViewportIndex, + ViewportMask + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/IrConsts.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/IrConsts.cs new file mode 100644 index 00000000..c264e47d --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/IrConsts.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + static class IrConsts + { + public const int False = 0; + public const int True = -1; + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operand.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operand.cs new file mode 100644 index 00000000..1df88a3d --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operand.cs @@ -0,0 +1,79 @@ +using Ryujinx.Graphics.Shader.Decoders; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + class Operand + { + private const int CbufSlotBits = 5; + private const int CbufSlotLsb = 32 - CbufSlotBits; + private const int CbufSlotMask = (1 << CbufSlotBits) - 1; + + public OperandType Type { get; } + + public int Value { get; } + + public INode AsgOp { get; set; } + + public HashSet<INode> UseOps { get; } + + private Operand() + { + UseOps = new HashSet<INode>(); + } + + public Operand(OperandType type) : this() + { + Type = type; + } + + public Operand(OperandType type, int value) : this() + { + Type = type; + Value = value; + } + + public Operand(Register reg) : this() + { + Type = OperandType.Register; + Value = PackRegInfo(reg.Index, reg.Type); + } + + public Operand(int slot, int offset) : this() + { + Type = OperandType.ConstantBuffer; + Value = PackCbufInfo(slot, offset); + } + + private static int PackCbufInfo(int slot, int offset) + { + return (slot << CbufSlotLsb) | offset; + } + + private static int PackRegInfo(int index, RegisterType type) + { + return ((int)type << 24) | index; + } + + public int GetCbufSlot() + { + return (Value >> CbufSlotLsb) & CbufSlotMask; + } + + public int GetCbufOffset() + { + return Value & ~(CbufSlotMask << CbufSlotLsb); + } + + public Register GetRegister() + { + return new Register(Value & 0xffffff, (RegisterType)(Value >> 24)); + } + + public float AsFloat() + { + return BitConverter.Int32BitsToSingle(Value); + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandHelper.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandHelper.cs new file mode 100644 index 00000000..37c349e8 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandHelper.cs @@ -0,0 +1,62 @@ +using Ryujinx.Graphics.Shader.Decoders; +using System; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + static class OperandHelper + { + public static Operand Argument(int value) + { + return new Operand(OperandType.Argument, value); + } + + public static Operand Cbuf(int slot, int offset) + { + return new Operand(slot, offset); + } + + public static Operand Const(int value) + { + return new Operand(OperandType.Constant, value); + } + + public static Operand ConstF(float value) + { + return new Operand(OperandType.Constant, BitConverter.SingleToInt32Bits(value)); + } + + public static Operand Label() + { + return new Operand(OperandType.Label); + } + + public static Operand Local() + { + return new Operand(OperandType.LocalVariable); + } + + public static Operand Register(int index, RegisterType type) + { + return Register(new Register(index, type)); + } + + public static Operand Register(Register reg) + { + if (reg.IsRZ) + { + return Const(0); + } + else if (reg.IsPT) + { + return Const(IrConsts.True); + } + + return new Operand(reg); + } + + public static Operand Undef() + { + return new Operand(OperandType.Undefined); + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandType.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandType.cs new file mode 100644 index 00000000..4d2da734 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandType.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + enum OperandType + { + Argument, + Constant, + ConstantBuffer, + Label, + LocalVariable, + Register, + Undefined + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs new file mode 100644 index 00000000..99179f15 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs @@ -0,0 +1,257 @@ +using System; +using System.Diagnostics; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + class Operation : INode + { + public Instruction Inst { get; private set; } + public StorageKind StorageKind { get; } + + private Operand[] _dests; + + public Operand Dest + { + get + { + return _dests.Length != 0 ? _dests[0] : null; + } + set + { + if (value != null && value.Type == OperandType.LocalVariable) + { + value.AsgOp = this; + } + + if (value != null) + { + _dests = new[] { value }; + } + else + { + _dests = Array.Empty<Operand>(); + } + } + } + + public int DestsCount => _dests.Length; + + private Operand[] _sources; + + public int SourcesCount => _sources.Length; + + public int Index { get; } + + private Operation(Operand[] sources) + { + // The array may be modified externally, so we store a copy. + _sources = (Operand[])sources.Clone(); + + for (int index = 0; index < _sources.Length; index++) + { + Operand source = _sources[index]; + + if (source.Type == OperandType.LocalVariable) + { + source.UseOps.Add(this); + } + } + } + + public Operation(Instruction inst, int index, Operand[] dests, Operand[] sources) : this(sources) + { + Inst = inst; + Index = index; + + if (dests != null) + { + // The array may be modified externally, so we store a copy. + _dests = (Operand[])dests.Clone(); + + for (int dstIndex = 0; dstIndex < dests.Length; dstIndex++) + { + Operand dest = dests[dstIndex]; + + if (dest != null && dest.Type == OperandType.LocalVariable) + { + dest.AsgOp = this; + } + } + } + else + { + _dests = Array.Empty<Operand>(); + } + } + + public Operation(Instruction inst, Operand dest, params Operand[] sources) : this(sources) + { + Inst = inst; + + if (dest != null) + { + dest.AsgOp = this; + + _dests = new[] { dest }; + } + else + { + _dests = Array.Empty<Operand>(); + } + } + + public Operation(Instruction inst, StorageKind storageKind, Operand dest, params Operand[] sources) : this(sources) + { + Inst = inst; + StorageKind = storageKind; + + if (dest != null) + { + dest.AsgOp = this; + + _dests = new[] { dest }; + } + else + { + _dests = Array.Empty<Operand>(); + } + } + + public Operation(Instruction inst, int index, Operand dest, params Operand[] sources) : this(inst, dest, sources) + { + Index = index; + } + + public void AppendDests(Operand[] operands) + { + int startIndex = _dests.Length; + + Array.Resize(ref _dests, startIndex + operands.Length); + + for (int index = 0; index < operands.Length; index++) + { + Operand dest = operands[index]; + + if (dest != null && dest.Type == OperandType.LocalVariable) + { + Debug.Assert(dest.AsgOp == null); + dest.AsgOp = this; + } + + _dests[startIndex + index] = dest; + } + } + + public void AppendSources(Operand[] operands) + { + int startIndex = _sources.Length; + + Array.Resize(ref _sources, startIndex + operands.Length); + + for (int index = 0; index < operands.Length; index++) + { + Operand source = operands[index]; + + if (source.Type == OperandType.LocalVariable) + { + source.UseOps.Add(this); + } + + _sources[startIndex + index] = source; + } + } + + public Operand GetDest(int index) + { + return _dests[index]; + } + + public Operand GetSource(int index) + { + return _sources[index]; + } + + public void SetDest(int index, Operand dest) + { + Operand oldDest = _dests[index]; + + if (oldDest != null && oldDest.Type == OperandType.LocalVariable) + { + oldDest.AsgOp = null; + } + + if (dest != null && dest.Type == OperandType.LocalVariable) + { + dest.AsgOp = this; + } + + _dests[index] = dest; + } + + public void SetSource(int index, Operand source) + { + Operand oldSrc = _sources[index]; + + if (oldSrc != null && oldSrc.Type == OperandType.LocalVariable) + { + oldSrc.UseOps.Remove(this); + } + + if (source != null && source.Type == OperandType.LocalVariable) + { + source.UseOps.Add(this); + } + + _sources[index] = source; + } + + public void InsertSource(int index, Operand source) + { + Operand[] newSources = new Operand[_sources.Length + 1]; + + Array.Copy(_sources, 0, newSources, 0, index); + Array.Copy(_sources, index, newSources, index + 1, _sources.Length - index); + + newSources[index] = source; + + _sources = newSources; + } + + protected void RemoveSource(int index) + { + SetSource(index, null); + + Operand[] newSources = new Operand[_sources.Length - 1]; + + Array.Copy(_sources, 0, newSources, 0, index); + Array.Copy(_sources, index + 1, newSources, index, _sources.Length - (index + 1)); + + _sources = newSources; + } + + public void TurnIntoCopy(Operand source) + { + TurnInto(Instruction.Copy, source); + } + + public void TurnInto(Instruction newInst, Operand source) + { + Inst = newInst; + + foreach (Operand oldSrc in _sources) + { + if (oldSrc != null && oldSrc.Type == OperandType.LocalVariable) + { + oldSrc.UseOps.Remove(this); + } + } + + if (source.Type == OperandType.LocalVariable) + { + source.UseOps.Add(this); + } + + _sources = new Operand[] { source }; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/PhiNode.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/PhiNode.cs new file mode 100644 index 00000000..8fa25ae9 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/PhiNode.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + class PhiNode : INode + { + private Operand _dest; + + public Operand Dest + { + get => _dest; + set => _dest = AssignDest(value); + } + + public int DestsCount => _dest != null ? 1 : 0; + + private HashSet<BasicBlock> _blocks; + + private class PhiSource + { + public BasicBlock Block { get; } + public Operand Operand { get; set; } + + public PhiSource(BasicBlock block, Operand operand) + { + Block = block; + Operand = operand; + } + } + + private List<PhiSource> _sources; + + public int SourcesCount => _sources.Count; + + public PhiNode(Operand dest) + { + _blocks = new HashSet<BasicBlock>(); + + _sources = new List<PhiSource>(); + + dest.AsgOp = this; + + Dest = dest; + } + + private Operand AssignDest(Operand dest) + { + if (dest != null && dest.Type == OperandType.LocalVariable) + { + dest.AsgOp = this; + } + + return dest; + } + + public void AddSource(BasicBlock block, Operand operand) + { + if (_blocks.Add(block)) + { + if (operand.Type == OperandType.LocalVariable) + { + operand.UseOps.Add(this); + } + + _sources.Add(new PhiSource(block, operand)); + } + } + + public Operand GetDest(int index) + { + if (index != 0) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + return _dest; + } + + public Operand GetSource(int index) + { + return _sources[index].Operand; + } + + public BasicBlock GetBlock(int index) + { + return _sources[index].Block; + } + + public void SetSource(int index, Operand source) + { + Operand oldSrc = _sources[index].Operand; + + if (oldSrc != null && oldSrc.Type == OperandType.LocalVariable) + { + oldSrc.UseOps.Remove(this); + } + + if (source.Type == OperandType.LocalVariable) + { + source.UseOps.Add(this); + } + + _sources[index].Operand = source; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/StorageKind.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/StorageKind.cs new file mode 100644 index 00000000..59357443 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/StorageKind.cs @@ -0,0 +1,39 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + enum StorageKind + { + None, + Input, + InputPerPatch, + Output, + OutputPerPatch, + ConstantBuffer, + StorageBuffer, + LocalMemory, + SharedMemory, + GlobalMemory + } + + static class StorageKindExtensions + { + public static bool IsInputOrOutput(this StorageKind storageKind) + { + return storageKind == StorageKind.Input || + storageKind == StorageKind.InputPerPatch || + storageKind == StorageKind.Output || + storageKind == StorageKind.OutputPerPatch; + } + + public static bool IsOutput(this StorageKind storageKind) + { + return storageKind == StorageKind.Output || + storageKind == StorageKind.OutputPerPatch; + } + + public static bool IsPerPatch(this StorageKind storageKind) + { + return storageKind == StorageKind.InputPerPatch || + storageKind == StorageKind.OutputPerPatch; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureFlags.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureFlags.cs new file mode 100644 index 00000000..6c20e856 --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureFlags.cs @@ -0,0 +1,32 @@ +using System; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + [Flags] + enum TextureFlags + { + None = 0, + Bindless = 1 << 0, + Gather = 1 << 1, + Derivatives = 1 << 2, + IntCoords = 1 << 3, + LodBias = 1 << 4, + LodLevel = 1 << 5, + Offset = 1 << 6, + Offsets = 1 << 7, + Coherent = 1 << 8, + + AtomicMask = 15 << 16, + + Add = 0 << 16, + Minimum = 1 << 16, + Maximum = 2 << 16, + Increment = 3 << 16, + Decrement = 4 << 16, + BitwiseAnd = 5 << 16, + BitwiseOr = 6 << 16, + BitwiseXor = 7 << 16, + Swap = 8 << 16, + CAS = 9 << 16 + } +}
\ No newline at end of file diff --git a/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs new file mode 100644 index 00000000..6ab868cd --- /dev/null +++ b/src/Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs @@ -0,0 +1,69 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + class TextureOperation : Operation + { + public const int DefaultCbufSlot = -1; + + public SamplerType Type { get; set; } + public TextureFormat Format { get; set; } + public TextureFlags Flags { get; private set; } + + public int CbufSlot { get; private set; } + public int Handle { get; private set; } + + public TextureOperation( + Instruction inst, + SamplerType type, + TextureFormat format, + TextureFlags flags, + int cbufSlot, + int handle, + int compIndex, + Operand[] dests, + Operand[] sources) : base(inst, compIndex, dests, sources) + { + Type = type; + Format = format; + Flags = flags; + CbufSlot = cbufSlot; + Handle = handle; + } + + public TextureOperation( + Instruction inst, + SamplerType type, + TextureFormat format, + TextureFlags flags, + int handle, + int compIndex, + Operand[] dests, + Operand[] sources) : this(inst, type, format, flags, DefaultCbufSlot, handle, compIndex, dests, sources) + { + } + + public void TurnIntoIndexed(int handle) + { + Type |= SamplerType.Indexed; + Flags &= ~TextureFlags.Bindless; + Handle = handle; + } + + public void SetHandle(int handle, int cbufSlot = DefaultCbufSlot) + { + if ((Flags & TextureFlags.Bindless) != 0) + { + Flags &= ~TextureFlags.Bindless; + + RemoveSource(0); + } + + CbufSlot = cbufSlot; + Handle = handle; + } + + public void SetLodLevelFlag() + { + Flags |= TextureFlags.LodLevel; + } + } +}
\ No newline at end of file |
