Initial work
This commit is contained in:
parent
f617fb542a
commit
1876b346fe
518 changed files with 15170 additions and 12486 deletions
|
@ -0,0 +1,61 @@
|
|||
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 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
13
Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs
Normal file
13
Ryujinx.Graphics.Shader/IntermediateRepresentation/INode.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
{
|
||||
interface INode
|
||||
{
|
||||
Operand Dest { get; set; }
|
||||
|
||||
int SourcesCount { get; }
|
||||
|
||||
Operand GetSource(int index);
|
||||
|
||||
void SetSource(int index, Operand operand);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
{
|
||||
[Flags]
|
||||
enum Instruction
|
||||
{
|
||||
Absolute = 1,
|
||||
Add,
|
||||
BitfieldExtractS32,
|
||||
BitfieldExtractU32,
|
||||
BitfieldInsert,
|
||||
BitfieldReverse,
|
||||
BitwiseAnd,
|
||||
BitwiseExclusiveOr,
|
||||
BitwiseNot,
|
||||
BitwiseOr,
|
||||
Branch,
|
||||
BranchIfFalse,
|
||||
BranchIfTrue,
|
||||
Ceiling,
|
||||
Clamp,
|
||||
ClampU32,
|
||||
Comment,
|
||||
CompareEqual,
|
||||
CompareGreater,
|
||||
CompareGreaterOrEqual,
|
||||
CompareGreaterOrEqualU32,
|
||||
CompareGreaterU32,
|
||||
CompareLess,
|
||||
CompareLessOrEqual,
|
||||
CompareLessOrEqualU32,
|
||||
CompareLessU32,
|
||||
CompareNotEqual,
|
||||
ConditionalSelect,
|
||||
ConvertFPToS32,
|
||||
ConvertS32ToFP,
|
||||
ConvertU32ToFP,
|
||||
Copy,
|
||||
Cosine,
|
||||
Discard,
|
||||
Divide,
|
||||
EmitVertex,
|
||||
EndPrimitive,
|
||||
ExponentB2,
|
||||
Floor,
|
||||
FusedMultiplyAdd,
|
||||
IsNan,
|
||||
LoadAttribute,
|
||||
LoadConstant,
|
||||
LoadGlobal,
|
||||
LoadLocal,
|
||||
LoadStorage,
|
||||
LogarithmB2,
|
||||
LogicalAnd,
|
||||
LogicalExclusiveOr,
|
||||
LogicalNot,
|
||||
LogicalOr,
|
||||
LoopBreak,
|
||||
LoopContinue,
|
||||
MarkLabel,
|
||||
Maximum,
|
||||
MaximumU32,
|
||||
Minimum,
|
||||
MinimumU32,
|
||||
Multiply,
|
||||
Negate,
|
||||
PackDouble2x32,
|
||||
PackHalf2x16,
|
||||
ReciprocalSquareRoot,
|
||||
Return,
|
||||
ShiftLeft,
|
||||
ShiftRightS32,
|
||||
ShiftRightU32,
|
||||
Sine,
|
||||
SquareRoot,
|
||||
StoreGlobal,
|
||||
StoreLocal,
|
||||
StoreStorage,
|
||||
Subtract,
|
||||
TextureSample,
|
||||
TextureSize,
|
||||
Truncate,
|
||||
UnpackDouble2x32,
|
||||
UnpackHalf2x16,
|
||||
|
||||
Count,
|
||||
FP = 1 << 16,
|
||||
Mask = 0xffff
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
{
|
||||
static class IrConsts
|
||||
{
|
||||
public const int False = 0;
|
||||
public const int True = -1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
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 InterpolationQualifier Interpolation { 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, InterpolationQualifier iq = InterpolationQualifier.None) : this()
|
||||
{
|
||||
Type = type;
|
||||
Value = value;
|
||||
Interpolation = iq;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
{
|
||||
static class OperandHelper
|
||||
{
|
||||
public static Operand Attribute(int value, InterpolationQualifier iq = InterpolationQualifier.None)
|
||||
{
|
||||
return new Operand(OperandType.Attribute, value, iq);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
{
|
||||
enum OperandType
|
||||
{
|
||||
Attribute,
|
||||
Constant,
|
||||
ConstantBuffer,
|
||||
Label,
|
||||
LocalVariable,
|
||||
Register,
|
||||
Undefined
|
||||
}
|
||||
}
|
101
Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs
Normal file
101
Ryujinx.Graphics.Shader/IntermediateRepresentation/Operation.cs
Normal file
|
@ -0,0 +1,101 @@
|
|||
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
{
|
||||
class Operation : INode
|
||||
{
|
||||
public Instruction Inst { get; private set; }
|
||||
|
||||
private Operand _dest;
|
||||
|
||||
public Operand Dest
|
||||
{
|
||||
get => _dest;
|
||||
set => _dest = AssignDest(value);
|
||||
}
|
||||
|
||||
private Operand[] _sources;
|
||||
|
||||
public int SourcesCount => _sources.Length;
|
||||
|
||||
public int ComponentIndex { get; }
|
||||
|
||||
public Operation(Instruction inst, Operand dest, params Operand[] sources)
|
||||
{
|
||||
Inst = inst;
|
||||
Dest = dest;
|
||||
|
||||
// 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 compIndex,
|
||||
Operand dest,
|
||||
params Operand[] sources) : this(inst, dest, sources)
|
||||
{
|
||||
ComponentIndex = compIndex;
|
||||
}
|
||||
|
||||
private Operand AssignDest(Operand dest)
|
||||
{
|
||||
if (dest != null && dest.Type == OperandType.LocalVariable)
|
||||
{
|
||||
dest.AsgOp = this;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
public Operand GetSource(int index)
|
||||
{
|
||||
return _sources[index];
|
||||
}
|
||||
|
||||
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 TurnIntoCopy(Operand source)
|
||||
{
|
||||
Inst = Instruction.Copy;
|
||||
|
||||
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 };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
{
|
||||
class PhiNode : INode
|
||||
{
|
||||
private Operand _dest;
|
||||
|
||||
public Operand Dest
|
||||
{
|
||||
get => _dest;
|
||||
set => _dest = AssignDest(value);
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
{
|
||||
[Flags]
|
||||
enum TextureFlags
|
||||
{
|
||||
None = 0,
|
||||
Bindless = 1 << 0,
|
||||
Gather = 1 << 1,
|
||||
IntCoords = 1 << 2,
|
||||
LodBias = 1 << 3,
|
||||
LodLevel = 1 << 4,
|
||||
Offset = 1 << 5,
|
||||
Offsets = 1 << 6
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
{
|
||||
class TextureOperation : Operation
|
||||
{
|
||||
public TextureTarget Target { get; }
|
||||
public TextureFlags Flags { get; }
|
||||
|
||||
public int Handle { get; }
|
||||
|
||||
public TextureOperation(
|
||||
Instruction inst,
|
||||
TextureTarget target,
|
||||
TextureFlags flags,
|
||||
int handle,
|
||||
int compIndex,
|
||||
Operand dest,
|
||||
params Operand[] sources) : base(inst, compIndex, dest, sources)
|
||||
{
|
||||
Target = target;
|
||||
Flags = flags;
|
||||
Handle = handle;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue