305 lines
8.6 KiB
C#
305 lines
8.6 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
|
||
|
namespace Ryujinx.Graphics.Gpu.Engine.Threed.Blender
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Blend microcode instruction.
|
||
|
/// </summary>
|
||
|
enum Instruction
|
||
|
{
|
||
|
Mmadd = 0,
|
||
|
Mmsub = 1,
|
||
|
Min = 2,
|
||
|
Max = 3,
|
||
|
Rcp = 4,
|
||
|
Add = 5,
|
||
|
Sub = 6
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Blend microcode condition code.
|
||
|
/// </summary>
|
||
|
enum CC
|
||
|
{
|
||
|
F = 0,
|
||
|
T = 1,
|
||
|
EQ = 2,
|
||
|
NE = 3,
|
||
|
LT = 4,
|
||
|
LE = 5,
|
||
|
GT = 6,
|
||
|
GE = 7
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Blend microcode opend B or D value.
|
||
|
/// </summary>
|
||
|
enum OpBD
|
||
|
{
|
||
|
ConstantZero = 0x0,
|
||
|
ConstantOne = 0x1,
|
||
|
SrcRGB = 0x2,
|
||
|
SrcAAA = 0x3,
|
||
|
OneMinusSrcAAA = 0x4,
|
||
|
DstRGB = 0x5,
|
||
|
DstAAA = 0x6,
|
||
|
OneMinusDstAAA = 0x7,
|
||
|
Temp0 = 0x9,
|
||
|
Temp1 = 0xa,
|
||
|
Temp2 = 0xb,
|
||
|
PBR = 0xc,
|
||
|
ConstantRGB = 0xd
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Blend microcode operand A or C value.
|
||
|
/// </summary>
|
||
|
enum OpAC
|
||
|
{
|
||
|
SrcRGB = 0,
|
||
|
DstRGB = 1,
|
||
|
SrcAAA = 2,
|
||
|
DstAAA = 3,
|
||
|
Temp0 = 4,
|
||
|
Temp1 = 5,
|
||
|
Temp2 = 6,
|
||
|
PBR = 7
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Blend microcode destination operand.
|
||
|
/// </summary>
|
||
|
enum OpDst
|
||
|
{
|
||
|
Temp0 = 0,
|
||
|
Temp1 = 1,
|
||
|
Temp2 = 2,
|
||
|
PBR = 3
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Blend microcode input swizzle.
|
||
|
/// </summary>
|
||
|
enum Swizzle
|
||
|
{
|
||
|
RGB = 0,
|
||
|
GBR = 1,
|
||
|
RRR = 2,
|
||
|
GGG = 3,
|
||
|
BBB = 4,
|
||
|
RToA = 5
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Blend microcode output components.
|
||
|
/// </summary>
|
||
|
enum WriteMask
|
||
|
{
|
||
|
RGB = 0,
|
||
|
R = 1,
|
||
|
G = 2,
|
||
|
B = 3
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Floating-point RGB color values.
|
||
|
/// </summary>
|
||
|
struct RgbFloat
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Red component value.
|
||
|
/// </summary>
|
||
|
public float R { get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Green component value.
|
||
|
/// </summary>
|
||
|
public float G { get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Blue component value.
|
||
|
/// </summary>
|
||
|
public float B { get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a new floating-point RGB value.
|
||
|
/// </summary>
|
||
|
/// <param name="r">Red component value</param>
|
||
|
/// <param name="g">Green component value</param>
|
||
|
/// <param name="b">Blue component value</param>
|
||
|
public RgbFloat(float r, float g, float b)
|
||
|
{
|
||
|
R = r;
|
||
|
G = g;
|
||
|
B = b;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Blend microcode destination operand, including swizzle, write mask and condition code update flag.
|
||
|
/// </summary>
|
||
|
struct Dest
|
||
|
{
|
||
|
public static Dest Temp0 => new Dest(OpDst.Temp0, Swizzle.RGB, WriteMask.RGB, false);
|
||
|
public static Dest Temp1 => new Dest(OpDst.Temp1, Swizzle.RGB, WriteMask.RGB, false);
|
||
|
public static Dest Temp2 => new Dest(OpDst.Temp2, Swizzle.RGB, WriteMask.RGB, false);
|
||
|
public static Dest PBR => new Dest(OpDst.PBR, Swizzle.RGB, WriteMask.RGB, false);
|
||
|
|
||
|
public Dest GBR => new Dest(Dst, Swizzle.GBR, WriteMask, WriteCC);
|
||
|
public Dest RRR => new Dest(Dst, Swizzle.RRR, WriteMask, WriteCC);
|
||
|
public Dest GGG => new Dest(Dst, Swizzle.GGG, WriteMask, WriteCC);
|
||
|
public Dest BBB => new Dest(Dst, Swizzle.BBB, WriteMask, WriteCC);
|
||
|
public Dest RToA => new Dest(Dst, Swizzle.RToA, WriteMask, WriteCC);
|
||
|
|
||
|
public Dest R => new Dest(Dst, Swizzle, WriteMask.R, WriteCC);
|
||
|
public Dest G => new Dest(Dst, Swizzle, WriteMask.G, WriteCC);
|
||
|
public Dest B => new Dest(Dst, Swizzle, WriteMask.B, WriteCC);
|
||
|
|
||
|
public Dest CC => new Dest(Dst, Swizzle, WriteMask, true);
|
||
|
|
||
|
public OpDst Dst { get; }
|
||
|
public Swizzle Swizzle { get; }
|
||
|
public WriteMask WriteMask { get; }
|
||
|
public bool WriteCC { get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a new blend microcode destination operand.
|
||
|
/// </summary>
|
||
|
/// <param name="dst">Operand</param>
|
||
|
/// <param name="swizzle">Swizzle</param>
|
||
|
/// <param name="writeMask">Write maks</param>
|
||
|
/// <param name="writeCC">Indicates if condition codes should be updated</param>
|
||
|
public Dest(OpDst dst, Swizzle swizzle, WriteMask writeMask, bool writeCC)
|
||
|
{
|
||
|
Dst = dst;
|
||
|
Swizzle = swizzle;
|
||
|
WriteMask = writeMask;
|
||
|
WriteCC = writeCC;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Blend microcode operaiton.
|
||
|
/// </summary>
|
||
|
struct UcodeOp
|
||
|
{
|
||
|
public readonly uint Word;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a new blend microcode operation.
|
||
|
/// </summary>
|
||
|
/// <param name="cc">Condition code that controls whenever the operation is executed or not</param>
|
||
|
/// <param name="inst">Instruction</param>
|
||
|
/// <param name="constIndex">Index on the constant table of the constant used by any constant operand</param>
|
||
|
/// <param name="dest">Destination operand</param>
|
||
|
/// <param name="srcA">First input operand</param>
|
||
|
/// <param name="srcB">Second input operand</param>
|
||
|
/// <param name="srcC">Third input operand</param>
|
||
|
/// <param name="srcD">Fourth input operand</param>
|
||
|
public UcodeOp(CC cc, Instruction inst, int constIndex, Dest dest, OpAC srcA, OpBD srcB, OpAC srcC, OpBD srcD)
|
||
|
{
|
||
|
Word = (uint)cc |
|
||
|
((uint)inst << 3) |
|
||
|
((uint)constIndex << 6) |
|
||
|
((uint)srcA << 9) |
|
||
|
((uint)srcB << 12) |
|
||
|
((uint)srcC << 16) |
|
||
|
((uint)srcD << 19) |
|
||
|
((uint)dest.Swizzle << 23) |
|
||
|
((uint)dest.WriteMask << 26) |
|
||
|
((uint)dest.Dst << 28) |
|
||
|
(dest.WriteCC ? (1u << 31) : 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Blend microcode assembler.
|
||
|
/// </summary>
|
||
|
struct UcodeAssembler
|
||
|
{
|
||
|
private List<uint> _code;
|
||
|
private RgbFloat[] _constants;
|
||
|
private int _constantIndex;
|
||
|
|
||
|
public void Mul(CC cc, Dest dest, OpAC srcA, OpBD srcB)
|
||
|
{
|
||
|
Assemble(cc, Instruction.Mmadd, dest, srcA, srcB, OpAC.SrcRGB, OpBD.ConstantZero);
|
||
|
}
|
||
|
|
||
|
public void Madd(CC cc, Dest dest, OpAC srcA, OpBD srcB, OpAC srcC)
|
||
|
{
|
||
|
Assemble(cc, Instruction.Mmadd, dest, srcA, srcB, srcC, OpBD.ConstantOne);
|
||
|
}
|
||
|
|
||
|
public void Mmadd(CC cc, Dest dest, OpAC srcA, OpBD srcB, OpAC srcC, OpBD srcD)
|
||
|
{
|
||
|
Assemble(cc, Instruction.Mmadd, dest, srcA, srcB, srcC, srcD);
|
||
|
}
|
||
|
|
||
|
public void Mmsub(CC cc, Dest dest, OpAC srcA, OpBD srcB, OpAC srcC, OpBD srcD)
|
||
|
{
|
||
|
Assemble(cc, Instruction.Mmsub, dest, srcA, srcB, srcC, srcD);
|
||
|
}
|
||
|
|
||
|
public void Min(CC cc, Dest dest, OpAC srcA, OpBD srcB)
|
||
|
{
|
||
|
Assemble(cc, Instruction.Min, dest, srcA, srcB, OpAC.SrcRGB, OpBD.ConstantZero);
|
||
|
}
|
||
|
|
||
|
public void Max(CC cc, Dest dest, OpAC srcA, OpBD srcB)
|
||
|
{
|
||
|
Assemble(cc, Instruction.Max, dest, srcA, srcB, OpAC.SrcRGB, OpBD.ConstantZero);
|
||
|
}
|
||
|
|
||
|
public void Rcp(CC cc, Dest dest, OpAC srcA)
|
||
|
{
|
||
|
Assemble(cc, Instruction.Rcp, dest, srcA, OpBD.ConstantZero, OpAC.SrcRGB, OpBD.ConstantZero);
|
||
|
}
|
||
|
|
||
|
public void Mov(CC cc, Dest dest, OpBD srcB)
|
||
|
{
|
||
|
Assemble(cc, Instruction.Add, dest, OpAC.SrcRGB, srcB, OpAC.SrcRGB, OpBD.ConstantZero);
|
||
|
}
|
||
|
|
||
|
public void Add(CC cc, Dest dest, OpBD srcB, OpBD srcD)
|
||
|
{
|
||
|
Assemble(cc, Instruction.Add, dest, OpAC.SrcRGB, srcB, OpAC.SrcRGB, srcD);
|
||
|
}
|
||
|
|
||
|
public void Sub(CC cc, Dest dest, OpBD srcB, OpBD srcD)
|
||
|
{
|
||
|
Assemble(cc, Instruction.Sub, dest, OpAC.SrcRGB, srcB, OpAC.SrcRGB, srcD);
|
||
|
}
|
||
|
|
||
|
private void Assemble(CC cc, Instruction inst, Dest dest, OpAC srcA, OpBD srcB, OpAC srcC, OpBD srcD)
|
||
|
{
|
||
|
(_code ??= new List<uint>()).Add(new UcodeOp(cc, inst, _constantIndex, dest, srcA, srcB, srcC, srcD).Word);
|
||
|
}
|
||
|
|
||
|
public void SetConstant(int index, float r, float g, float b)
|
||
|
{
|
||
|
if (_constants == null)
|
||
|
{
|
||
|
_constants = new RgbFloat[index + 1];
|
||
|
}
|
||
|
else if (_constants.Length <= index)
|
||
|
{
|
||
|
Array.Resize(ref _constants, index + 1);
|
||
|
}
|
||
|
|
||
|
_constants[index] = new RgbFloat(r, g, b);
|
||
|
_constantIndex = index;
|
||
|
}
|
||
|
|
||
|
public uint[] GetCode()
|
||
|
{
|
||
|
return _code?.ToArray();
|
||
|
}
|
||
|
|
||
|
public RgbFloat[] GetConstants()
|
||
|
{
|
||
|
return _constants;
|
||
|
}
|
||
|
}
|
||
|
}
|