Started to implement shader decoding support on the GPU

This commit is contained in:
gdkchan 2018-03-21 00:15:47 -03:00
parent eaca9a3d5d
commit e4aeb93be8
13 changed files with 339 additions and 0 deletions

View file

@ -0,0 +1,4 @@
namespace Ryujinx.Graphics.Gal.Shader
{
delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode);
}

View file

@ -0,0 +1,83 @@
namespace Ryujinx.Graphics.Gal.Shader
{
static partial class ShaderDecode
{
public static void Fadd(ShaderIrBlock Block, long OpCode)
{
int Rd = (int)(OpCode >> 0) & 0xff;
int Ra = (int)(OpCode >> 8) & 0xff;
int Ob = (int)(OpCode >> 20) & 0x3fff;
int Cb = (int)(OpCode >> 34) & 0x1f;
bool Nb = ((OpCode >> 45) & 1) != 0;
bool Aa = ((OpCode >> 46) & 1) != 0;
bool Na = ((OpCode >> 48) & 1) != 0;
bool Ab = ((OpCode >> 49) & 1) != 0;
bool Ad = ((OpCode >> 50) & 1) != 0;
Block.AddNode(new ShaderIrNodeLdr(Ra));
if (Aa)
{
Block.AddNode(new ShaderIrNode(ShaderIrInst.Fabs));
}
if (Na)
{
Block.AddNode(new ShaderIrNode(ShaderIrInst.Fneg));
}
Block.AddNode(new ShaderIrNodeLdb(Cb, Ob));
if (Ab)
{
Block.AddNode(new ShaderIrNode(ShaderIrInst.Fabs));
}
if (Nb)
{
Block.AddNode(new ShaderIrNode(ShaderIrInst.Fneg));
}
Block.AddNode(new ShaderIrNode(ShaderIrInst.Fadd));
if (Ad)
{
Block.AddNode(new ShaderIrNode(ShaderIrInst.Fabs));
}
Block.AddNode(new ShaderIrNodeStr(Rd));
}
public static void Ffma(ShaderIrBlock Block, long OpCode)
{
int Rd = (int)(OpCode >> 0) & 0xff;
int Ra = (int)(OpCode >> 8) & 0xff;
int Ob = (int)(OpCode >> 20) & 0x3fff;
int Cb = (int)(OpCode >> 34) & 0x1f;
int Rc = (int)(OpCode >> 39) & 0xff;
bool Nb = ((OpCode >> 48) & 1) != 0;
bool Nc = ((OpCode >> 49) & 1) != 0;
Block.AddNode(new ShaderIrNodeLdr(Ra));
Block.AddNode(new ShaderIrNodeLdb(Cb, Ob));
if (Nb)
{
Block.AddNode(new ShaderIrNode(ShaderIrInst.Fneg));
}
Block.AddNode(new ShaderIrNode(ShaderIrInst.Fmul));
Block.AddNode(new ShaderIrNodeLdr(Rc));
if (Nc)
{
Block.AddNode(new ShaderIrNode(ShaderIrInst.Fneg));
}
Block.AddNode(new ShaderIrNode(ShaderIrInst.Fadd));
Block.AddNode(new ShaderIrNodeStr(Rd));
}
}
}

View file

@ -0,0 +1,29 @@
namespace Ryujinx.Graphics.Gal.Shader
{
static class ShaderDecoder
{
public static ShaderIrBlock DecodeBasicBlock(int[] Code, int Offset)
{
ShaderIrBlock Block = new ShaderIrBlock();
while (Offset + 2 <= Code.Length)
{
uint Word0 = (uint)Code[Offset++];
uint Word1 = (uint)Code[Offset++];
long OpCode = Word0 | (long)Word1 << 32;
ShaderDecodeFunc Decode = ShaderOpCodeTable.GetDecoder(OpCode);
if (Decode == null)
{
continue;
}
Decode(Block, OpCode);
}
return Block;
}
}
}

View file

@ -0,0 +1,24 @@
using System.Collections.Generic;
namespace Ryujinx.Graphics.Gal.Shader
{
class ShaderIrBlock
{
private List<ShaderIrNode> Nodes;
public ShaderIrBlock()
{
Nodes = new List<ShaderIrNode>();
}
public void AddNode(ShaderIrNode Node)
{
Nodes.Add(Node);
}
public ShaderIrNode[] GetNodes()
{
return Nodes.ToArray();
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.Gal.Shader
{
enum ShaderIrInst
{
Fabs,
Fadd,
Fmul,
Fneg,
Ld,
St
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.Gal.Shader
{
class ShaderIrNode
{
public ShaderIrInst Inst;
public ShaderIrNode(ShaderIrInst Inst)
{
this.Inst = Inst;
}
}
}

View file

@ -0,0 +1,14 @@
namespace Ryujinx.Graphics.Gal.Shader
{
class ShaderIrNodeLdb : ShaderIrNode
{
public int Cbuf { get; private set; }
public int Offs { get; private set; }
public ShaderIrNodeLdb(int Cbuf, int Offs) : base(ShaderIrInst.Ld)
{
this.Cbuf = Cbuf;
this.Offs = Offs;
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.Gal.Shader
{
class ShaderIrNodeLdr : ShaderIrNode
{
public int GprIndex { get; private set; }
public ShaderIrNodeLdr(int GprIndex) : base(ShaderIrInst.Ld)
{
this.GprIndex = GprIndex;
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.Gal.Shader
{
class ShaderIrNodeStr : ShaderIrNode
{
public int GprIndex { get; private set; }
public ShaderIrNodeStr(int GprIndex) : base(ShaderIrInst.St)
{
this.GprIndex = GprIndex;
}
}
}

View file

@ -0,0 +1,4 @@
namespace Ryujinx.Graphics.Gal.Shader
{
class ShaderIrOper { }
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.Gal.Shader
{
class ShaderIrOperReg : ShaderIrOper
{
public int GprIndex { get; private set; }
public ShaderIrOperReg(int GprIndex)
{
this.GprIndex = GprIndex;
}
}
}

View file

@ -0,0 +1,71 @@
using System;
namespace Ryujinx.Graphics.Gal.Shader
{
static class ShaderOpCodeTable
{
private const int EncodingBits = 14;
private static ShaderDecodeFunc[] OpCodes;
static ShaderOpCodeTable()
{
OpCodes = new ShaderDecodeFunc[1 << EncodingBits];
#region Instructions
Set("0100110001011x", ShaderDecode.Fadd);
Set("010010011xxxxx", ShaderDecode.Ffma);
#endregion
}
private static void Set(string Encoding, ShaderDecodeFunc Func)
{
if (Encoding.Length != EncodingBits)
{
throw new ArgumentException(nameof(Encoding));
}
int Bit = Encoding.Length - 1;
int Value = 0;
int XMask = 0;
int XBits = 0;
int[] XPos = new int[Encoding.Length];
for (int Index = 0; Index < Encoding.Length; Index++, Bit--)
{
char Chr = Encoding[Index];
if (Chr == '1')
{
Value |= 1 << Bit;
}
else if (Chr == 'x')
{
XMask |= 1 << Bit;
XPos[XBits++] = Bit;
}
}
XMask = ~XMask;
for (int Index = 0; Index < (1 << XBits); Index++)
{
Value &= XMask;
for (int X = 0; X < XBits; X++)
{
Value |= ((Index >> X) & 1) << XPos[X];
}
OpCodes[Value] = Func;
}
}
public static ShaderDecodeFunc GetDecoder(long OpCode)
{
return OpCodes[(ulong)OpCode >> (64 - EncodingBits)];
}
}
}

View file

@ -0,0 +1,50 @@
namespace Ryujinx.Graphics.Gal.Shader
{
public static class ShaderTest
{
public static void Test()
{
System.Console.WriteLine("Starting test code...");
System.Collections.Generic.List<int> CodeList = new System.Collections.Generic.List<int>();
using (System.IO.FileStream FS = new System.IO.FileStream("D:\\puyo_vsh.bin", System.IO.FileMode.Open))
{
System.IO.BinaryReader Reader = new System.IO.BinaryReader(FS);
while (FS.Position + 8 <= FS.Length)
{
CodeList.Add(Reader.ReadInt32());
}
}
int[] Code = CodeList.ToArray();
ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Code, 0);
ShaderIrNode[] Nodes = Block.GetNodes();
foreach (ShaderIrNode Node in Nodes)
{
System.Console.Write(Node.Inst);
if (Node is ShaderIrNodeLdr LdrNode)
{
System.Console.Write($" r{LdrNode.GprIndex}");
}
else if (Node is ShaderIrNodeStr StrNode)
{
System.Console.Write($" r{StrNode.GprIndex}");
}
else if (Node is ShaderIrNodeLdb LdbNode)
{
System.Console.Write($" c{LdbNode.Cbuf}[0x{LdbNode.Offs.ToString("x")}]");
}
System.Console.WriteLine(string.Empty);
}
System.Console.WriteLine("Test code finished!");
}
}
}