More work on GPU refactoring
This commit is contained in:
parent
0a0cc69a7b
commit
0dc4053599
15 changed files with 565 additions and 274 deletions
|
@ -5,12 +5,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
|
|
||||||
public int Index { get; private set; }
|
public int Index { get; private set; }
|
||||||
|
public int Cbuf { get; private set; }
|
||||||
public int Size { get; private set; }
|
public int Size { get; private set; }
|
||||||
|
|
||||||
public GlslDeclInfo(string Name, int Index, int Size)
|
public GlslDeclInfo(string Name, int Index, int Cbuf = 0, int Size = 1)
|
||||||
{
|
{
|
||||||
this.Name = Name;
|
this.Name = Name;
|
||||||
this.Index = Index;
|
this.Index = Index;
|
||||||
|
this.Cbuf = Cbuf;
|
||||||
this.Size = Size;
|
this.Size = Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
@ -15,29 +16,28 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" };
|
private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" };
|
||||||
|
|
||||||
private SortedDictionary<int, GlslDeclInfo> InputAttributes;
|
private Dictionary<int, GlslDeclInfo> Textures;
|
||||||
private SortedDictionary<int, GlslDeclInfo> OutputAttributes;
|
|
||||||
|
|
||||||
private HashSet<int> UsedCbufs;
|
private Dictionary<(int, int), GlslDeclInfo> Uniforms;
|
||||||
|
|
||||||
|
private Dictionary<int, GlslDeclInfo> InputAttributes;
|
||||||
|
private Dictionary<int, GlslDeclInfo> OutputAttributes;
|
||||||
|
|
||||||
|
private Dictionary<int, GlslDeclInfo> Gprs;
|
||||||
|
private Dictionary<int, GlslDeclInfo> Preds;
|
||||||
|
|
||||||
private const int AttrStartIndex = 8;
|
private const int AttrStartIndex = 8;
|
||||||
private const int TexStartIndex = 8;
|
private const int TexStartIndex = 8;
|
||||||
|
|
||||||
private const string InputAttrPrefix = "in_attr";
|
private const string InputAttrName = "in_attr";
|
||||||
private const string OutputAttrPrefix = "out_attr";
|
private const string OutputName = "out_attr";
|
||||||
|
private const string UniformName = "c";
|
||||||
private const string CbufBuffPrefix = "c";
|
|
||||||
private const string CbufDataName = "buf";
|
|
||||||
|
|
||||||
private const string GprName = "gpr";
|
private const string GprName = "gpr";
|
||||||
private const string PredName = "pred";
|
private const string PredName = "pred";
|
||||||
private const string SampName = "samp";
|
private const string TextureName = "tex";
|
||||||
|
|
||||||
private int GprsCount;
|
private StringBuilder SB;
|
||||||
private int PredsCount;
|
|
||||||
private int SampsCount;
|
|
||||||
|
|
||||||
private StringBuilder BodySB;
|
|
||||||
|
|
||||||
public GlslDecompiler()
|
public GlslDecompiler()
|
||||||
{
|
{
|
||||||
|
@ -51,6 +51,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{ ShaderIrInst.Cgt, GetCgtExpr },
|
{ ShaderIrInst.Cgt, GetCgtExpr },
|
||||||
{ ShaderIrInst.Cne, GetCneExpr },
|
{ ShaderIrInst.Cne, GetCneExpr },
|
||||||
{ ShaderIrInst.Cge, GetCgeExpr },
|
{ ShaderIrInst.Cge, GetCgeExpr },
|
||||||
|
{ ShaderIrInst.Exit, GetExitExpr },
|
||||||
{ ShaderIrInst.Fabs, GetFabsExpr },
|
{ ShaderIrInst.Fabs, GetFabsExpr },
|
||||||
{ ShaderIrInst.Fadd, GetFaddExpr },
|
{ ShaderIrInst.Fadd, GetFaddExpr },
|
||||||
{ ShaderIrInst.Fcos, GetFcosExpr },
|
{ ShaderIrInst.Fcos, GetFcosExpr },
|
||||||
|
@ -73,50 +74,47 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public GlslProgram Decompile(int[] Code, GalShaderType Type)
|
public GlslProgram Decompile(int[] Code, GalShaderType Type)
|
||||||
{
|
{
|
||||||
InputAttributes = new SortedDictionary<int, GlslDeclInfo>();
|
Uniforms = new Dictionary<(int, int), GlslDeclInfo>();
|
||||||
OutputAttributes = new SortedDictionary<int, GlslDeclInfo>();
|
|
||||||
|
|
||||||
UsedCbufs = new HashSet<int>();
|
Textures = new Dictionary<int, GlslDeclInfo>();
|
||||||
|
|
||||||
BodySB = new StringBuilder();
|
InputAttributes = new Dictionary<int, GlslDeclInfo>();
|
||||||
|
OutputAttributes = new Dictionary<int, GlslDeclInfo>();
|
||||||
|
|
||||||
|
Gprs = new Dictionary<int, GlslDeclInfo>();
|
||||||
|
Preds = new Dictionary<int, GlslDeclInfo>();
|
||||||
|
|
||||||
|
SB = new StringBuilder();
|
||||||
|
|
||||||
//FIXME: Only valid for vertex shaders.
|
//FIXME: Only valid for vertex shaders.
|
||||||
if (Type == GalShaderType.Fragment)
|
if (Type == GalShaderType.Fragment)
|
||||||
{
|
{
|
||||||
OutputAttributes.Add(7, new GlslDeclInfo("FragColor", -1, 4));
|
Gprs.Add(0, new GlslDeclInfo("FragColor", 0, 0, 4));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OutputAttributes.Add(7, new GlslDeclInfo("gl_Position", -1, 4));
|
OutputAttributes.Add(7, new GlslDeclInfo("gl_Position", -1, 0, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Code, 0, Type);
|
ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Code, 0, Type);
|
||||||
|
|
||||||
ShaderIrNode[] Nodes = Block.GetNodes();
|
ShaderIrNode[] Nodes = Block.GetNodes();
|
||||||
|
|
||||||
PrintBlockScope("void main()", 1, Nodes);
|
foreach (ShaderIrNode Node in Nodes)
|
||||||
|
{
|
||||||
StringBuilder SB = new StringBuilder();
|
Traverse(null, Node);
|
||||||
|
}
|
||||||
|
|
||||||
SB.AppendLine("#version 430");
|
SB.AppendLine("#version 430");
|
||||||
|
|
||||||
PrintDeclUBOs(SB);
|
PrintDeclTextures();
|
||||||
PrintDeclInAttributes(SB);
|
PrintDeclUniforms();
|
||||||
PrintDeclOutAttributes(SB);
|
PrintDeclInAttributes();
|
||||||
|
PrintDeclOutAttributes();
|
||||||
|
PrintDeclGprs();
|
||||||
|
PrintDeclPreds();
|
||||||
|
|
||||||
if (Type == GalShaderType.Fragment)
|
PrintBlockScope("void main()", 1, Nodes);
|
||||||
{
|
|
||||||
SB.AppendLine($"out vec4 {OutputAttributes[7].Name};");
|
|
||||||
SB.AppendLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintDeclSamplers(SB);
|
|
||||||
PrintDeclGprs(SB);
|
|
||||||
PrintDeclPreds(SB);
|
|
||||||
|
|
||||||
SB.Append(BodySB.ToString());
|
|
||||||
|
|
||||||
BodySB.Clear();
|
|
||||||
|
|
||||||
GlslProgram Program = new GlslProgram();
|
GlslProgram Program = new GlslProgram();
|
||||||
|
|
||||||
|
@ -124,33 +122,158 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
Program.Attributes = InputAttributes.Values.ToArray();
|
Program.Attributes = InputAttributes.Values.ToArray();
|
||||||
|
|
||||||
|
SB.Clear();
|
||||||
|
|
||||||
return Program;
|
return Program;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclUBOs(StringBuilder SB)
|
private void Traverse(ShaderIrNode Parent, ShaderIrNode Node)
|
||||||
{
|
{
|
||||||
foreach (int Cbuf in UsedCbufs)
|
switch (Node)
|
||||||
|
{
|
||||||
|
case ShaderIrAsg Asg:
|
||||||
|
{
|
||||||
|
Traverse(Asg, Asg.Dst);
|
||||||
|
Traverse(Asg, Asg.Src);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrCond Cond:
|
||||||
|
{
|
||||||
|
Traverse(Cond, Cond.Pred);
|
||||||
|
Traverse(Cond, Cond.Child);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrOp Op:
|
||||||
|
{
|
||||||
|
Traverse(Op, Op.OperandA);
|
||||||
|
Traverse(Op, Op.OperandB);
|
||||||
|
Traverse(Op, Op.OperandC);
|
||||||
|
|
||||||
|
if (Op.Inst == ShaderIrInst.Texr ||
|
||||||
|
Op.Inst == ShaderIrInst.Texg ||
|
||||||
|
Op.Inst == ShaderIrInst.Texb ||
|
||||||
|
Op.Inst == ShaderIrInst.Texa)
|
||||||
|
{
|
||||||
|
int Handle = ((ShaderIrOperImm)Op.OperandC).Imm;
|
||||||
|
|
||||||
|
int Index = Handle - TexStartIndex;
|
||||||
|
|
||||||
|
string Name = $"{TextureName}{Index}";
|
||||||
|
|
||||||
|
Textures.TryAdd(Handle, new GlslDeclInfo(Name, Index));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrOperCbuf Cbuf:
|
||||||
|
{
|
||||||
|
string Name = $"{UniformName}{Cbuf.Index}_{Cbuf.Offs}";
|
||||||
|
|
||||||
|
GlslDeclInfo DeclInfo = new GlslDeclInfo(Name, Cbuf.Offs, Cbuf.Index);
|
||||||
|
|
||||||
|
Uniforms.TryAdd((Cbuf.Index, Cbuf.Offs), DeclInfo);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrOperAbuf Abuf:
|
||||||
|
{
|
||||||
|
int Index = Abuf.Offs >> 4;
|
||||||
|
int Elem = (Abuf.Offs >> 2) & 3;
|
||||||
|
|
||||||
|
int GlslIndex = Index - AttrStartIndex;
|
||||||
|
|
||||||
|
GlslDeclInfo DeclInfo;
|
||||||
|
|
||||||
|
if (Parent is ShaderIrAsg Asg && Asg.Dst == Node)
|
||||||
|
{
|
||||||
|
if (!OutputAttributes.TryGetValue(Index, out DeclInfo))
|
||||||
|
{
|
||||||
|
DeclInfo = new GlslDeclInfo(OutputName + GlslIndex, GlslIndex);
|
||||||
|
|
||||||
|
OutputAttributes.Add(Index, DeclInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!InputAttributes.TryGetValue(Index, out DeclInfo))
|
||||||
|
{
|
||||||
|
DeclInfo = new GlslDeclInfo(InputAttrName + GlslIndex, GlslIndex);
|
||||||
|
|
||||||
|
InputAttributes.Add(Index, DeclInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeclInfo.Enlarge(Elem + 1);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrOperGpr Gpr:
|
||||||
|
{
|
||||||
|
if (!Gpr.IsConst && GetNameWithSwizzle(Gprs, Gpr.Index) == null)
|
||||||
|
{
|
||||||
|
string Name = $"{GprName}{Gpr.Index}";
|
||||||
|
|
||||||
|
Gprs.TryAdd(Gpr.Index, new GlslDeclInfo(Name, Gpr.Index));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrOperPred Pred:
|
||||||
|
{
|
||||||
|
if (!Pred.IsConst && GetNameWithSwizzle(Preds, Pred.Index) == null)
|
||||||
|
{
|
||||||
|
string Name = $"{PredName}{Pred.Index}";
|
||||||
|
|
||||||
|
Preds.TryAdd(Pred.Index, new GlslDeclInfo(Name, Pred.Index));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintDeclTextures()
|
||||||
|
{
|
||||||
|
PrintDecls(Textures.Values, "uniform sampler2D");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintDeclUniforms()
|
||||||
|
{
|
||||||
|
foreach (GlslDeclInfo DeclInfo in Uniforms.Values.OrderBy(DeclKeySelector))
|
||||||
|
{
|
||||||
|
SB.AppendLine($"uniform {GetDecl(DeclInfo)};");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Uniforms.Values.Count > 0)
|
||||||
{
|
{
|
||||||
SB.AppendLine($"uniform _{CbufBuffPrefix}{Cbuf} {{");
|
|
||||||
SB.AppendLine($"{IdentationStr}float {CbufDataName}[];");
|
|
||||||
SB.AppendLine($"}} {CbufBuffPrefix}{Cbuf};");
|
|
||||||
SB.AppendLine();
|
SB.AppendLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclInAttributes(StringBuilder SB)
|
private void PrintDeclInAttributes()
|
||||||
|
{
|
||||||
|
PrintDeclAttributes(InputAttributes.Values, "in");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintDeclOutAttributes()
|
||||||
|
{
|
||||||
|
PrintDeclAttributes(OutputAttributes.Values, "out");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintDeclAttributes(ICollection<GlslDeclInfo> Decls, string InOut)
|
||||||
{
|
{
|
||||||
bool PrintNl = false;
|
bool PrintNl = false;
|
||||||
|
|
||||||
foreach (KeyValuePair<int, GlslDeclInfo> KV in InputAttributes)
|
foreach (GlslDeclInfo DeclInfo in Decls.OrderBy(DeclKeySelector))
|
||||||
{
|
{
|
||||||
int Index = KV.Key - AttrStartIndex;
|
if (DeclInfo.Index >= 0)
|
||||||
|
|
||||||
if (Index >= 0)
|
|
||||||
{
|
{
|
||||||
string Type = ElemTypes[KV.Value.Size];
|
SB.AppendLine($"layout (location = {DeclInfo.Index}) {InOut} {GetDecl(DeclInfo)};");
|
||||||
|
|
||||||
SB.AppendLine($"layout (location = {Index}) in {Type} {KV.Value.Name};");
|
|
||||||
|
|
||||||
PrintNl = true;
|
PrintNl = true;
|
||||||
}
|
}
|
||||||
|
@ -162,55 +285,48 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclOutAttributes(StringBuilder SB)
|
private void PrintDeclGprs()
|
||||||
{
|
{
|
||||||
bool PrintNl = false;
|
PrintDecls(Gprs.Values);
|
||||||
|
|
||||||
foreach (KeyValuePair<int, GlslDeclInfo> KV in OutputAttributes)
|
|
||||||
{
|
|
||||||
int Index = KV.Key - AttrStartIndex;
|
|
||||||
|
|
||||||
if (Index >= 0)
|
|
||||||
{
|
|
||||||
string Type = ElemTypes[KV.Value.Size];
|
|
||||||
|
|
||||||
SB.AppendLine($"layout (location = {Index}) out {Type} {KV.Value.Name};");
|
|
||||||
|
|
||||||
PrintNl = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PrintNl)
|
private void PrintDeclPreds()
|
||||||
|
{
|
||||||
|
PrintDecls(Preds.Values, "bool");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintDecls(ICollection<GlslDeclInfo> Decls, string CustomType = null)
|
||||||
|
{
|
||||||
|
foreach (GlslDeclInfo DeclInfo in Decls.OrderBy(DeclKeySelector))
|
||||||
|
{
|
||||||
|
string Name;
|
||||||
|
|
||||||
|
if (CustomType != null)
|
||||||
|
{
|
||||||
|
Name = $"{CustomType} {DeclInfo.Name};";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Name = $"{GetDecl(DeclInfo)};";
|
||||||
|
}
|
||||||
|
|
||||||
|
SB.AppendLine(Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Decls.Count > 0)
|
||||||
{
|
{
|
||||||
SB.AppendLine();
|
SB.AppendLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclSamplers(StringBuilder SB)
|
private int DeclKeySelector(GlslDeclInfo DeclInfo)
|
||||||
{
|
{
|
||||||
if (SampsCount > 0)
|
return DeclInfo.Cbuf << 24 | DeclInfo.Index;
|
||||||
{
|
|
||||||
SB.AppendLine($"uniform sampler2D {SampName}[{SampsCount}];");
|
|
||||||
SB.AppendLine();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclGprs(StringBuilder SB)
|
private string GetDecl(GlslDeclInfo DeclInfo)
|
||||||
{
|
{
|
||||||
if (GprsCount > 0)
|
return $"{ElemTypes[DeclInfo.Size - 1]} {DeclInfo.Name}";
|
||||||
{
|
|
||||||
SB.AppendLine($"float {GprName}[{GprsCount}];");
|
|
||||||
SB.AppendLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PrintDeclPreds(StringBuilder SB)
|
|
||||||
{
|
|
||||||
if (PredsCount > 0)
|
|
||||||
{
|
|
||||||
SB.AppendLine($"bool {PredName}[{PredsCount}];");
|
|
||||||
SB.AppendLine();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintBlockScope(string ScopeName, int IdentationLevel, params ShaderIrNode[] Nodes)
|
private void PrintBlockScope(string ScopeName, int IdentationLevel, params ShaderIrNode[] Nodes)
|
||||||
|
@ -227,7 +343,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
ScopeName += " ";
|
ScopeName += " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
BodySB.AppendLine(Identation + ScopeName + "{");
|
SB.AppendLine(Identation + ScopeName + "{");
|
||||||
|
|
||||||
string LastLine = Identation + "}";
|
string LastLine = Identation + "}";
|
||||||
|
|
||||||
|
@ -250,14 +366,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
if (IsValidOutOper(Asg.Dst))
|
if (IsValidOutOper(Asg.Dst))
|
||||||
{
|
{
|
||||||
BodySB.AppendLine(Identation +
|
SB.AppendLine(Identation +
|
||||||
$"{GetOutOperName(Asg.Dst)} = " +
|
$"{GetOutOperName(Asg.Dst)} = " +
|
||||||
$"{GetInOperName (Asg.Src, true)};");
|
$"{GetInOperName (Asg.Src, true)};");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Node is ShaderIrOp Op)
|
else if (Node is ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
BodySB.AppendLine($"{Identation}{GetInOperName(Op, true)};");
|
SB.AppendLine($"{Identation}{GetInOperName(Op, true)};");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -265,16 +381,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BodySB.AppendLine(LastLine);
|
SB.AppendLine(LastLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsValidOutOper(ShaderIrNode Node)
|
private bool IsValidOutOper(ShaderIrNode Node)
|
||||||
{
|
{
|
||||||
if (Node is ShaderIrOperGpr Gpr && Gpr.Index == ShaderIrOperGpr.ZRIndex)
|
if (Node is ShaderIrOperGpr Gpr && Gpr.IsConst)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (Node is ShaderIrOperPred Pred && Pred.Index == ShaderIrOperPred.UnusedIndex)
|
else if (Node is ShaderIrOperPred Pred && Pred.IsConst)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -307,6 +423,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
case ShaderIrOperAbuf Abuf: return GetName(Abuf);
|
case ShaderIrOperAbuf Abuf: return GetName(Abuf);
|
||||||
case ShaderIrOperCbuf Cbuf: return GetName(Cbuf);
|
case ShaderIrOperCbuf Cbuf: return GetName(Cbuf);
|
||||||
case ShaderIrOperGpr Gpr: return GetName(Gpr);
|
case ShaderIrOperGpr Gpr: return GetName(Gpr);
|
||||||
|
case ShaderIrOperImm Imm: return GetName(Imm);
|
||||||
case ShaderIrOperPred Pred: return GetName(Pred);
|
case ShaderIrOperPred Pred: return GetName(Pred);
|
||||||
|
|
||||||
case ShaderIrOp Op:
|
case ShaderIrOp Op:
|
||||||
|
@ -350,81 +467,74 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Inst == ShaderIrInst.Texa;
|
Inst == ShaderIrInst.Texa;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetOutAbufName(ShaderIrOperAbuf Abuf)
|
private string GetName(ShaderIrOperCbuf Cbuf)
|
||||||
{
|
{
|
||||||
int Index = Abuf.Offs >> 4;
|
if (!Uniforms.TryGetValue((Cbuf.Index, Cbuf.Offs), out GlslDeclInfo DeclInfo))
|
||||||
|
|
||||||
int Elem = (Abuf.Offs >> 2) & 3;
|
|
||||||
|
|
||||||
if (!OutputAttributes.TryGetValue(Index, out GlslDeclInfo Attr))
|
|
||||||
{
|
{
|
||||||
int GlslIndex = Index - AttrStartIndex;
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
Attr = new GlslDeclInfo(OutputAttrPrefix + GlslIndex, GlslIndex, Elem);
|
|
||||||
|
|
||||||
OutputAttributes.Add(Index, Attr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Attr.Enlarge(Elem);
|
return DeclInfo.Name;
|
||||||
|
}
|
||||||
|
|
||||||
return $"{Attr.Name}.{GetAttrSwizzle(Elem)}";
|
private string GetOutAbufName(ShaderIrOperAbuf Abuf)
|
||||||
|
{
|
||||||
|
return GetName(OutputAttributes, Abuf, Swizzle: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetName(ShaderIrOperAbuf Abuf, bool Swizzle = true)
|
private string GetName(ShaderIrOperAbuf Abuf, bool Swizzle = true)
|
||||||
{
|
{
|
||||||
int Index = Abuf.Offs >> 4;
|
return GetName(InputAttributes, Abuf, Swizzle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetName(Dictionary<int, GlslDeclInfo> Decls, ShaderIrOperAbuf Abuf, bool Swizzle)
|
||||||
|
{
|
||||||
|
int Index = Abuf.Offs >> 4;
|
||||||
int Elem = (Abuf.Offs >> 2) & 3;
|
int Elem = (Abuf.Offs >> 2) & 3;
|
||||||
|
|
||||||
if (!InputAttributes.TryGetValue(Index, out GlslDeclInfo Attr))
|
if (!Decls.TryGetValue(Index, out GlslDeclInfo DeclInfo))
|
||||||
{
|
{
|
||||||
int GlslIndex = Index - AttrStartIndex;
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
Attr = new GlslDeclInfo(InputAttrPrefix + GlslIndex, GlslIndex, Elem);
|
|
||||||
|
|
||||||
InputAttributes.Add(Index, Attr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Attr.Enlarge(Elem);
|
Swizzle &= DeclInfo.Size > 1;
|
||||||
|
|
||||||
return Swizzle ? $"{Attr.Name}.{GetAttrSwizzle(Elem)}" : Attr.Name;
|
return Swizzle ? $"{DeclInfo.Name}.{GetAttrSwizzle(Elem)}" : DeclInfo.Name;
|
||||||
}
|
|
||||||
|
|
||||||
private string GetName(ShaderIrOperCbuf Cbuf)
|
|
||||||
{
|
|
||||||
UsedCbufs.Add(Cbuf.Index);
|
|
||||||
|
|
||||||
return $"{CbufBuffPrefix}{Cbuf.Index}.{CbufDataName}[{Cbuf.Offs}]";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetName(ShaderIrOperGpr Gpr)
|
private string GetName(ShaderIrOperGpr Gpr)
|
||||||
{
|
{
|
||||||
if (GprsCount < Gpr.Index + 1)
|
return Gpr.IsConst ? "0" : GetNameWithSwizzle(Gprs, Gpr.Index);
|
||||||
{
|
|
||||||
GprsCount = Gpr.Index + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetRegName(Gpr.Index);
|
private string GetName(ShaderIrOperImm Imm)
|
||||||
|
{
|
||||||
|
return Imm.Imm.ToString(CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetName(ShaderIrOperPred Pred)
|
private string GetName(ShaderIrOperPred Pred)
|
||||||
{
|
{
|
||||||
if (PredsCount < Pred.Index + 1)
|
return Pred.IsConst ? "true" : GetNameWithSwizzle(Preds, Pred.Index);
|
||||||
{
|
|
||||||
PredsCount = Pred.Index + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetPredName(Pred.Index);
|
private string GetNameWithSwizzle(Dictionary<int, GlslDeclInfo> Decls, int Index)
|
||||||
|
{
|
||||||
|
int VecIndex = Index >> 2;
|
||||||
|
|
||||||
|
if (Decls.TryGetValue(VecIndex, out GlslDeclInfo DeclInfo))
|
||||||
|
{
|
||||||
|
if (DeclInfo.Size > 1 && Index < VecIndex + DeclInfo.Size)
|
||||||
|
{
|
||||||
|
return $"{DeclInfo.Name}.{GetAttrSwizzle(Index & 3)}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetRegName(int GprIndex)
|
if (!Decls.TryGetValue(Index, out DeclInfo))
|
||||||
{
|
{
|
||||||
return GprIndex == ShaderIrOperGpr.ZRIndex ? "0" : $"{GprName}[{GprIndex}]";
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetPredName(int PredIndex)
|
return DeclInfo.Name;
|
||||||
{
|
|
||||||
return PredIndex == ShaderIrOperPred.UnusedIndex ? "true" : $"{PredName}[{PredIndex}]";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetBandExpr(ShaderIrOp Op)
|
private string GetBandExpr(ShaderIrOp Op)
|
||||||
|
@ -474,6 +584,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
$"{GetInOperName(Op.OperandB)}";
|
$"{GetInOperName(Op.OperandB)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetExitExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return "return";
|
||||||
|
}
|
||||||
|
|
||||||
private string GetFabsExpr(ShaderIrOp Op)
|
private string GetFabsExpr(ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
return $"abs({GetInOperName(Op.OperandA)})";
|
return $"abs({GetInOperName(Op.OperandA)})";
|
||||||
|
@ -557,14 +672,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
ShaderIrOperImm Node = (ShaderIrOperImm)Op.OperandC;
|
ShaderIrOperImm Node = (ShaderIrOperImm)Op.OperandC;
|
||||||
|
|
||||||
int Handle = Node.Imm - TexStartIndex;
|
int Handle = ((ShaderIrOperImm)Op.OperandC).Imm;
|
||||||
|
|
||||||
if (SampsCount < Handle + 1)
|
if (!Textures.TryGetValue(Handle, out GlslDeclInfo DeclInfo))
|
||||||
{
|
{
|
||||||
SampsCount = Handle + 1;
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"{SampName}[{Handle}]";
|
return DeclInfo.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetTexSamplerCoords(ShaderIrOp Op)
|
private string GetTexSamplerCoords(ShaderIrOp Op)
|
||||||
|
|
|
@ -4,6 +4,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
static partial class ShaderDecode
|
||||||
{
|
{
|
||||||
|
public static void Exit(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Exit), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
public static void Kil(ShaderIrBlock Block, long OpCode)
|
public static void Kil(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Kil), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Kil), OpCode));
|
||||||
|
|
|
@ -62,8 +62,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public static ShaderIrNode GetOperImmf19_20(long OpCode)
|
public static ShaderIrNode GetOperImmf19_20(long OpCode)
|
||||||
{
|
{
|
||||||
//TODO
|
//TODO: This should be a float immediate.
|
||||||
return new ShaderIrNode();
|
return new ShaderIrOperImm((int)(OpCode >> 36) & 0x1fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrOperImm GetOperImm13_36(long OpCode)
|
public static ShaderIrOperImm GetOperImm13_36(long OpCode)
|
||||||
|
|
|
@ -2,7 +2,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static class ShaderDecoder
|
static class ShaderDecoder
|
||||||
{
|
{
|
||||||
public static ShaderIrBlock DecodeBasicBlock(int[] Code, int Offset, GalShaderType Type)
|
public static ShaderIrBlock DecodeBasicBlock(int[] Code, int Offset, GalShaderType ShaderType)
|
||||||
{
|
{
|
||||||
ShaderIrBlock Block = new ShaderIrBlock();
|
ShaderIrBlock Block = new ShaderIrBlock();
|
||||||
|
|
||||||
|
@ -21,19 +21,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
|
|
||||||
Decode(Block, OpCode);
|
Decode(Block, OpCode);
|
||||||
}
|
|
||||||
|
|
||||||
if (Type == GalShaderType.Fragment)
|
if (Block.GetLastNode() is ShaderIrOp Op && IsFlowChange(Op.Inst))
|
||||||
{
|
{
|
||||||
Block.AddNode(new ShaderIrAsg(new ShaderIrOperAbuf(0x70, 0), new ShaderIrOperGpr(0)));
|
break;
|
||||||
Block.AddNode(new ShaderIrAsg(new ShaderIrOperAbuf(0x74, 0), new ShaderIrOperGpr(1)));
|
}
|
||||||
Block.AddNode(new ShaderIrAsg(new ShaderIrOperAbuf(0x78, 0), new ShaderIrOperGpr(2)));
|
|
||||||
Block.AddNode(new ShaderIrAsg(new ShaderIrOperAbuf(0x7c, 0), new ShaderIrOperGpr(3)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Block.RunOptimizationPasses();
|
Block.RunOptimizationPasses(ShaderType);
|
||||||
|
|
||||||
return Block;
|
return Block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsFlowChange(ShaderIrInst Inst)
|
||||||
|
{
|
||||||
|
return Inst == ShaderIrInst.Exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,14 +16,24 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Nodes.Add(Node);
|
Nodes.Add(Node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RunOptimizationPasses()
|
public void RunOptimizationPasses(GalShaderType ShaderType)
|
||||||
{
|
{
|
||||||
ShaderOptExprProp.Optimize(Nodes);
|
ShaderOptExprProp.Optimize(Nodes, ShaderType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderIrNode[] GetNodes()
|
public ShaderIrNode[] GetNodes()
|
||||||
{
|
{
|
||||||
return Nodes.ToArray();
|
return Nodes.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ShaderIrNode GetLastNode()
|
||||||
|
{
|
||||||
|
if (Nodes.Count > 0)
|
||||||
|
{
|
||||||
|
return Nodes[Nodes.Count - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,6 +20,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Cgtu,
|
Cgtu,
|
||||||
Cneu,
|
Cneu,
|
||||||
Cgeu,
|
Cgeu,
|
||||||
|
Exit,
|
||||||
Fabs,
|
Fabs,
|
||||||
Fadd,
|
Fadd,
|
||||||
Fcos,
|
Fcos,
|
||||||
|
|
|
@ -4,6 +4,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
public const int ZRIndex = 0xff;
|
public const int ZRIndex = 0xff;
|
||||||
|
|
||||||
|
public bool IsConst => Index == ZRIndex;
|
||||||
|
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
|
|
||||||
public ShaderIrOperGpr(int Index)
|
public ShaderIrOperGpr(int Index)
|
||||||
|
|
|
@ -5,6 +5,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
public const int UnusedIndex = 0x7;
|
public const int UnusedIndex = 0x7;
|
||||||
public const int NeverExecute = 0xf;
|
public const int NeverExecute = 0xf;
|
||||||
|
|
||||||
|
public bool IsConst => Index >= UnusedIndex;
|
||||||
|
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
|
|
||||||
public ShaderIrOperPred(int Index)
|
public ShaderIrOperPred(int Index)
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
OpCodes = new ShaderDecodeFunc[1 << EncodingBits];
|
OpCodes = new ShaderDecodeFunc[1 << EncodingBits];
|
||||||
|
|
||||||
#region Instructions
|
#region Instructions
|
||||||
|
Set("111000110000xx", ShaderDecode.Exit);
|
||||||
Set("0101110001011x", ShaderDecode.Fadd_R);
|
Set("0101110001011x", ShaderDecode.Fadd_R);
|
||||||
Set("0100110001011x", ShaderDecode.Fadd_C);
|
Set("0100110001011x", ShaderDecode.Fadd_C);
|
||||||
Set("0011100x01011x", ShaderDecode.Fadd_Imm);
|
Set("0011100x01011x", ShaderDecode.Fadd_Imm);
|
||||||
|
|
|
@ -99,7 +99,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Optimize(List<ShaderIrNode> Nodes)
|
public static void Optimize(List<ShaderIrNode> Nodes, GalShaderType ShaderType)
|
||||||
{
|
{
|
||||||
Dictionary<int, RegUse> Uses = new Dictionary<int, RegUse>();
|
Dictionary<int, RegUse> Uses = new Dictionary<int, RegUse>();
|
||||||
|
|
||||||
|
@ -183,6 +183,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
//to a register took place. We traverse the expression tree to find
|
//to a register took place. We traverse the expression tree to find
|
||||||
//all registers being used, if any of those registers was assigned
|
//all registers being used, if any of those registers was assigned
|
||||||
//after the assignment to be propagated, then we can't propagate.
|
//after the assignment to be propagated, then we can't propagate.
|
||||||
|
if (Use?.Asg == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
List<(int, UseSite)> UseList = new List<(int, UseSite)>();
|
List<(int, UseSite)> UseList = new List<(int, UseSite)>();
|
||||||
|
|
||||||
FindRegUses(UseList, Use.Asg, Use.Asg.Src);
|
FindRegUses(UseList, Use.Asg, Use.Asg.Src);
|
||||||
|
@ -227,7 +232,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Use = GetPredUse(Pred.Index);
|
Use = GetPredUse(Pred.Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Use?.Asg != null && !IsConditional && TryPropagate(Use))
|
if (!IsConditional && TryPropagate(Use))
|
||||||
{
|
{
|
||||||
Nodes.Remove(Use.Asg);
|
Nodes.Remove(Use.Asg);
|
||||||
|
|
||||||
|
@ -241,6 +246,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
foreach (RegUse Use in Uses.Values)
|
foreach (RegUse Use in Uses.Values)
|
||||||
{
|
{
|
||||||
|
//Gprs 0-3 are the color output on fragment shaders,
|
||||||
|
//so we can't remove the last assignments to those registers.
|
||||||
|
if (ShaderType == GalShaderType.Fragment)
|
||||||
|
{
|
||||||
|
if (Use.Asg?.Dst is ShaderIrOperGpr Gpr && Gpr.Index < 4)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (TryPropagate(Use))
|
if (TryPropagate(Use))
|
||||||
{
|
{
|
||||||
Nodes.Remove(Use.Asg);
|
Nodes.Remove(Use.Asg);
|
||||||
|
|
|
@ -6,6 +6,41 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
class MacroInterpreter
|
class MacroInterpreter
|
||||||
{
|
{
|
||||||
|
private enum AssignmentOperation
|
||||||
|
{
|
||||||
|
IgnoreAndFetch = 0,
|
||||||
|
Move = 1,
|
||||||
|
MoveAndSetMaddr = 2,
|
||||||
|
FetchAndSend = 3,
|
||||||
|
MoveAndSend = 4,
|
||||||
|
FetchAndSetMaddr = 5,
|
||||||
|
MoveAndSetMaddrThenFetchAndSend = 6,
|
||||||
|
MoveAndSetMaddrThenSendHigh = 7
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum AluOperation
|
||||||
|
{
|
||||||
|
AluReg = 0,
|
||||||
|
AddImmediate = 1,
|
||||||
|
BitfieldReplace = 2,
|
||||||
|
BitfieldExtractLslImm = 3,
|
||||||
|
BitfieldExtractLslReg = 4,
|
||||||
|
ReadImmediate = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum AluRegOperation
|
||||||
|
{
|
||||||
|
Add = 0,
|
||||||
|
AddWithCarry = 1,
|
||||||
|
Subtract = 2,
|
||||||
|
SubtractWithBorrow = 3,
|
||||||
|
BitwiseExclusiveOr = 8,
|
||||||
|
BitwiseOr = 9,
|
||||||
|
BitwiseAnd = 10,
|
||||||
|
BitwiseAndNot = 11,
|
||||||
|
BitwiseNotAnd = 12
|
||||||
|
}
|
||||||
|
|
||||||
private NvGpuFifo PFifo;
|
private NvGpuFifo PFifo;
|
||||||
private INvGpuEngine Engine;
|
private INvGpuEngine Engine;
|
||||||
|
|
||||||
|
@ -18,6 +53,10 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private bool Carry;
|
private bool Carry;
|
||||||
|
|
||||||
|
private int OpCode;
|
||||||
|
|
||||||
|
private int PipeOp;
|
||||||
|
|
||||||
private long Pc;
|
private long Pc;
|
||||||
|
|
||||||
public MacroInterpreter(NvGpuFifo PFifo, INvGpuEngine Engine)
|
public MacroInterpreter(NvGpuFifo PFifo, INvGpuEngine Engine)
|
||||||
|
@ -34,11 +73,17 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
Pc = Position;
|
|
||||||
|
|
||||||
Gprs[1] = Param;
|
Gprs[1] = Param;
|
||||||
|
|
||||||
|
Pc = Position;
|
||||||
|
|
||||||
|
FetchOpCode(Memory);
|
||||||
|
|
||||||
while (Step(Memory));
|
while (Step(Memory));
|
||||||
|
|
||||||
|
//Due to the delay slot, we still need to execute
|
||||||
|
//one more instruction before we actually exit.
|
||||||
|
Step(Memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Reset()
|
private void Reset()
|
||||||
|
@ -56,46 +101,98 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private bool Step(AMemory Memory)
|
private bool Step(AMemory Memory)
|
||||||
{
|
{
|
||||||
long BaseAddr = Pc;
|
long BaseAddr = Pc - 4;
|
||||||
|
|
||||||
int OpCode = Memory.ReadInt32(Pc);
|
FetchOpCode(Memory);
|
||||||
|
|
||||||
Pc += 4;
|
if ((OpCode & 7) < 7)
|
||||||
|
|
||||||
int Op = OpCode & 7;
|
|
||||||
|
|
||||||
if (Op < 7)
|
|
||||||
{
|
{
|
||||||
//Operation produces a value.
|
//Operation produces a value.
|
||||||
int AsgOp = (OpCode >> 4) & 7;
|
AssignmentOperation AsgOp = (AssignmentOperation)((OpCode >> 4) & 7);
|
||||||
|
|
||||||
int Result = GetInstResult(OpCode);
|
int Result = GetAluResult();
|
||||||
|
|
||||||
switch (AsgOp)
|
switch (AsgOp)
|
||||||
{
|
{
|
||||||
//Fetch parameter and ignore result.
|
//Fetch parameter and ignore result.
|
||||||
case 0: SetDstGpr(OpCode, FetchParam()); break;
|
case AssignmentOperation.IgnoreAndFetch:
|
||||||
|
{
|
||||||
|
SetDstGpr(FetchParam());
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//Move result.
|
//Move result.
|
||||||
case 1: SetDstGpr(OpCode, Result); break;
|
case AssignmentOperation.Move:
|
||||||
|
{
|
||||||
|
SetDstGpr(Result);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//Move result and use as Method Address.
|
//Move result and use as Method Address.
|
||||||
case 2: SetDstGpr(OpCode, Result); SetMethAddr(Result); break;
|
case AssignmentOperation.MoveAndSetMaddr:
|
||||||
|
{
|
||||||
|
SetDstGpr(Result);
|
||||||
|
|
||||||
|
SetMethAddr(Result);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//Fetch parameter and send result.
|
//Fetch parameter and send result.
|
||||||
case 3: SetDstGpr(OpCode, FetchParam()); Send(Memory, Result); break;
|
case AssignmentOperation.FetchAndSend:
|
||||||
|
{
|
||||||
|
SetDstGpr(FetchParam());
|
||||||
|
|
||||||
|
Send(Memory, Result);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//Move and send result.
|
//Move and send result.
|
||||||
case 4: SetDstGpr(OpCode, Result); Send(Memory, Result); break;
|
case AssignmentOperation.MoveAndSend:
|
||||||
|
{
|
||||||
|
SetDstGpr(Result);
|
||||||
|
|
||||||
|
Send(Memory, Result);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//Fetch parameter and use result as Method Address.
|
//Fetch parameter and use result as Method Address.
|
||||||
case 5: SetDstGpr(OpCode, FetchParam()); SetMethAddr(Result); break;
|
case AssignmentOperation.FetchAndSetMaddr:
|
||||||
|
{
|
||||||
|
SetDstGpr(FetchParam());
|
||||||
|
|
||||||
|
SetMethAddr(Result);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//Move result and use as Method Address, then fetch and send paramter.
|
//Move result and use as Method Address, then fetch and send paramter.
|
||||||
case 6: SetDstGpr(OpCode, Result); SetMethAddr(Result); Send(Memory, FetchParam()); break;
|
case AssignmentOperation.MoveAndSetMaddrThenFetchAndSend:
|
||||||
|
{
|
||||||
|
SetDstGpr(Result);
|
||||||
|
|
||||||
|
SetMethAddr(Result);
|
||||||
|
|
||||||
|
Send(Memory, FetchParam());
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//Move result and use as Method Address, then send bits 17:12 of result.
|
//Move result and use as Method Address, then send bits 17:12 of result.
|
||||||
case 7: SetDstGpr(OpCode, Result); SetMethAddr(Result); Send(Memory, (Result >> 12) & 0x3f); break;
|
case AssignmentOperation.MoveAndSetMaddrThenSendHigh:
|
||||||
|
{
|
||||||
|
SetDstGpr(Result);
|
||||||
|
|
||||||
|
SetMethAddr(Result);
|
||||||
|
|
||||||
|
Send(Memory, (Result >> 12) & 0x3f);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -104,61 +201,59 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
bool OnNotZero = ((OpCode >> 4) & 1) != 0;
|
bool OnNotZero = ((OpCode >> 4) & 1) != 0;
|
||||||
|
|
||||||
bool Taken = OnNotZero
|
bool Taken = OnNotZero
|
||||||
? GetGprA(OpCode) != 0
|
? GetGprA() != 0
|
||||||
: GetGprA(OpCode) == 0;
|
: GetGprA() == 0;
|
||||||
|
|
||||||
if (Taken)
|
if (Taken)
|
||||||
{
|
{
|
||||||
bool KeepExecuting = true;
|
Pc = BaseAddr + (GetImm() << 2);
|
||||||
|
|
||||||
//When bit 5 is set, branches executes as if delay slots didn't exist.
|
bool NoDelays = (OpCode & 0x20) != 0;
|
||||||
if ((OpCode & 0x20) == 0)
|
|
||||||
|
if (NoDelays)
|
||||||
{
|
{
|
||||||
//Execute one more instruction due to delay slot.
|
FetchOpCode(Memory);
|
||||||
KeepExecuting = Step(Memory);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pc = BaseAddr + (GetImm(OpCode) << 2);
|
|
||||||
|
|
||||||
return KeepExecuting;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((OpCode & 0x80) != 0)
|
|
||||||
{
|
|
||||||
//Exit (with a delay slot).
|
|
||||||
Step(Memory);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetInstResult(int OpCode)
|
|
||||||
{
|
|
||||||
int Low = OpCode & 7;
|
|
||||||
|
|
||||||
switch (Low)
|
|
||||||
{
|
|
||||||
//Arithmetic or Logical operation.
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
int AluOp = (OpCode >> 17) & 0x1f;
|
|
||||||
|
|
||||||
return GetAluResult(AluOp, GetGprA(OpCode), GetGprB(OpCode));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add Immediate.
|
bool Exit = (OpCode & 0x80) != 0;
|
||||||
case 1:
|
|
||||||
{
|
return !Exit;
|
||||||
return GetGprA(OpCode) + GetImm(OpCode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Bitfield.
|
private void FetchOpCode(AMemory Memory)
|
||||||
case 2:
|
{
|
||||||
case 3:
|
OpCode = PipeOp;
|
||||||
case 4:
|
|
||||||
|
PipeOp = Memory.ReadInt32(Pc);
|
||||||
|
|
||||||
|
Pc += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetAluResult()
|
||||||
|
{
|
||||||
|
AluOperation Op = (AluOperation)(OpCode & 7);
|
||||||
|
|
||||||
|
switch (Op)
|
||||||
|
{
|
||||||
|
case AluOperation.AluReg:
|
||||||
|
{
|
||||||
|
AluRegOperation AluOp = (AluRegOperation)((OpCode >> 17) & 0x1f);
|
||||||
|
|
||||||
|
return GetAluResult(AluOp, GetGprA(), GetGprB());
|
||||||
|
}
|
||||||
|
|
||||||
|
case AluOperation.AddImmediate:
|
||||||
|
{
|
||||||
|
return GetGprA() + GetImm();
|
||||||
|
}
|
||||||
|
|
||||||
|
case AluOperation.BitfieldReplace:
|
||||||
|
case AluOperation.BitfieldExtractLslImm:
|
||||||
|
case AluOperation.BitfieldExtractLslReg:
|
||||||
{
|
{
|
||||||
int BfSrcBit = (OpCode >> 17) & 0x1f;
|
int BfSrcBit = (OpCode >> 17) & 0x1f;
|
||||||
int BfSize = (OpCode >> 22) & 0x1f;
|
int BfSize = (OpCode >> 22) & 0x1f;
|
||||||
|
@ -166,13 +261,12 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
int BfMask = (1 << BfSize) - 1;
|
int BfMask = (1 << BfSize) - 1;
|
||||||
|
|
||||||
int Dst = GetGprA(OpCode);
|
int Dst = GetGprA();
|
||||||
int Src = GetGprB(OpCode);
|
int Src = GetGprB();
|
||||||
|
|
||||||
switch (Low)
|
switch (Op)
|
||||||
{
|
{
|
||||||
//Bitfield move.
|
case AluOperation.BitfieldReplace:
|
||||||
case 2:
|
|
||||||
{
|
{
|
||||||
Src = (int)((uint)Src >> BfSrcBit) & BfMask;
|
Src = (int)((uint)Src >> BfSrcBit) & BfMask;
|
||||||
|
|
||||||
|
@ -183,16 +277,14 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
return Dst;
|
return Dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Bitfield extract with left shift by immediate.
|
case AluOperation.BitfieldExtractLslImm:
|
||||||
case 3:
|
|
||||||
{
|
{
|
||||||
Src = (int)((uint)Src >> Dst) & BfMask;
|
Src = (int)((uint)Src >> Dst) & BfMask;
|
||||||
|
|
||||||
return Src << BfDstBit;
|
return Src << BfDstBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Bitfield extract with left shift by register.
|
case AluOperation.BitfieldExtractLslReg:
|
||||||
case 4:
|
|
||||||
{
|
{
|
||||||
Src = (int)((uint)Src >> BfSrcBit) & BfMask;
|
Src = (int)((uint)Src >> BfSrcBit) & BfMask;
|
||||||
|
|
||||||
|
@ -203,69 +295,66 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 5:
|
case AluOperation.ReadImmediate:
|
||||||
{
|
{
|
||||||
return Read(GetGprA(OpCode) + GetImm(OpCode));
|
return Read(GetGprA() + GetImm());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(OpCode));
|
throw new ArgumentException(nameof(OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetAluResult(int AluOp, int A, int B)
|
private int GetAluResult(AluRegOperation AluOp, int A, int B)
|
||||||
{
|
{
|
||||||
switch (AluOp)
|
switch (AluOp)
|
||||||
{
|
{
|
||||||
//Add.
|
case AluRegOperation.Add:
|
||||||
case 0: return A + B;
|
|
||||||
|
|
||||||
//Add with Carry.
|
|
||||||
case 1:
|
|
||||||
{
|
{
|
||||||
ulong C = Carry ? 1UL : 0UL;
|
ulong Result = (ulong)A + (ulong)B;
|
||||||
|
|
||||||
ulong Result = (ulong)A + (ulong)B + C;
|
|
||||||
|
|
||||||
Carry = Result > 0xffffffff;
|
Carry = Result > 0xffffffff;
|
||||||
|
|
||||||
return (int)Result;
|
return (int)Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Subtract.
|
case AluRegOperation.AddWithCarry:
|
||||||
case 2: return A - B;
|
|
||||||
|
|
||||||
//Subtract with Borrow.
|
|
||||||
case 3:
|
|
||||||
{
|
{
|
||||||
ulong C = Carry ? 0UL : 1UL;
|
ulong Result = (ulong)A + (ulong)B + (Carry ? 1UL : 0UL);
|
||||||
|
|
||||||
ulong Result = (ulong)A - (ulong)B - C;
|
Carry = Result > 0xffffffff;
|
||||||
|
|
||||||
|
return (int)Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AluRegOperation.Subtract:
|
||||||
|
{
|
||||||
|
ulong Result = (ulong)A - (ulong)B;
|
||||||
|
|
||||||
Carry = Result < 0x100000000;
|
Carry = Result < 0x100000000;
|
||||||
|
|
||||||
return (int)Result;
|
return (int)Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Exclusive Or.
|
case AluRegOperation.SubtractWithBorrow:
|
||||||
case 8: return A ^ B;
|
{
|
||||||
|
ulong Result = (ulong)A - (ulong)B - (Carry ? 0UL : 1UL);
|
||||||
|
|
||||||
//Or.
|
Carry = Result < 0x100000000;
|
||||||
case 9: return A | B;
|
|
||||||
|
|
||||||
//And.
|
return (int)Result;
|
||||||
case 10: return A & B;
|
}
|
||||||
|
|
||||||
//And Not.
|
case AluRegOperation.BitwiseExclusiveOr: return A ^ B;
|
||||||
case 11: return A & ~B;
|
case AluRegOperation.BitwiseOr: return A | B;
|
||||||
|
case AluRegOperation.BitwiseAnd: return A & B;
|
||||||
//Not And.
|
case AluRegOperation.BitwiseAndNot: return A & ~B;
|
||||||
case 12: return ~(A & B);
|
case AluRegOperation.BitwiseNotAnd: return ~(A & B);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(AluOp));
|
throw new ArgumentOutOfRangeException(nameof(AluOp));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetImm(int OpCode)
|
private int GetImm()
|
||||||
{
|
{
|
||||||
//Note: The immediate is signed, the sign-extension is intended here.
|
//Note: The immediate is signed, the sign-extension is intended here.
|
||||||
return OpCode >> 14;
|
return OpCode >> 14;
|
||||||
|
@ -277,17 +366,17 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
MethIncr = (Value >> 12) & 0x3f;
|
MethIncr = (Value >> 12) & 0x3f;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetDstGpr(int OpCode, int Value)
|
private void SetDstGpr(int Value)
|
||||||
{
|
{
|
||||||
Gprs[(OpCode >> 8) & 7] = Value;
|
Gprs[(OpCode >> 8) & 7] = Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetGprA(int OpCode)
|
private int GetGprA()
|
||||||
{
|
{
|
||||||
return GetGprValue((OpCode >> 11) & 7);
|
return GetGprValue((OpCode >> 11) & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetGprB(int OpCode)
|
private int GetGprB()
|
||||||
{
|
{
|
||||||
return GetGprValue((OpCode >> 14) & 7);
|
return GetGprValue((OpCode >> 14) & 7);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
|
using Ryujinx.Graphics.Gal;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu
|
namespace Ryujinx.Graphics.Gpu
|
||||||
|
@ -63,11 +65,52 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
int TexCbuf = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
|
int TexCbuf = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
|
||||||
|
|
||||||
int TexHandle = ReadCb(Memory, TexCbuf, 0x20);
|
int TexHandle = ReadCb(Memory, TexCbuf, 0x20);
|
||||||
|
|
||||||
|
long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
||||||
|
|
||||||
|
for (int Index = 0; Index < 6; Index++)
|
||||||
|
{
|
||||||
|
int Offset = ReadRegister(NvGpuEngine3dReg.ShaderOffset + Index * 0x10);
|
||||||
|
|
||||||
|
if (Offset == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
long Position = Gpu.GetCpuAddr(BasePosition + (uint)Offset);
|
||||||
|
|
||||||
|
if (Position == -1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Find a better way to calculate the size.
|
||||||
|
int Size = 0x20000;
|
||||||
|
|
||||||
|
byte[] Code = AMemoryHelper.ReadBytes(Memory, Position, (uint)Size);
|
||||||
|
|
||||||
|
Gpu.Renderer.CreateShader(Position, Code, GetTypeFromProgram(Index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GalShaderType GetTypeFromProgram(int Program)
|
||||||
|
{
|
||||||
|
switch (Program)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1: return GalShaderType.Vertex;
|
||||||
|
case 2: return GalShaderType.TessControl;
|
||||||
|
case 3: return GalShaderType.TessEvaluation;
|
||||||
|
case 4: return GalShaderType.Geometry;
|
||||||
|
case 5: return GalShaderType.Fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(Program));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void QueryControl(AMemory Memory, NsGpuPBEntry PBEntry)
|
private void QueryControl(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||||
{
|
{
|
||||||
if (TryGetCpuAddr(NvGpuEngine3dReg.QueryAddr, out long Position))
|
if (TryGetCpuAddr(NvGpuEngine3dReg.QueryAddress, out long Position))
|
||||||
{
|
{
|
||||||
int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence];
|
int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence];
|
||||||
int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl];
|
int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl];
|
||||||
|
|
|
@ -2,9 +2,14 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
enum NvGpuEngine3dReg
|
enum NvGpuEngine3dReg
|
||||||
{
|
{
|
||||||
QueryAddr = 0x6c0,
|
ShaderAddress = 0x582,
|
||||||
|
QueryAddress = 0x6c0,
|
||||||
QuerySequence = 0x6c2,
|
QuerySequence = 0x6c2,
|
||||||
QueryControl = 0x6c3,
|
QueryControl = 0x6c3,
|
||||||
|
ShaderControl = 0x800,
|
||||||
|
ShaderOffset = 0x801,
|
||||||
|
ShaderMaxGprs = 0x803,
|
||||||
|
ShaderType = 0x804,
|
||||||
CbSize = 0x8e0,
|
CbSize = 0x8e0,
|
||||||
CbAddress = 0x8e1,
|
CbAddress = 0x8e1,
|
||||||
CbOffset = 0x8e3,
|
CbOffset = 0x8e3,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu
|
namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue