More work on GPU refactoring
This commit is contained in:
parent
d237bca9a8
commit
32d76fb4f8
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 int Index { get; private set; }
|
||||
public int Cbuf { 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.Index = Index;
|
||||
this.Cbuf = Cbuf;
|
||||
this.Size = Size;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
@ -15,29 +16,28 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" };
|
||||
|
||||
private SortedDictionary<int, GlslDeclInfo> InputAttributes;
|
||||
private SortedDictionary<int, GlslDeclInfo> OutputAttributes;
|
||||
private Dictionary<int, GlslDeclInfo> Textures;
|
||||
|
||||
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 TexStartIndex = 8;
|
||||
|
||||
private const string InputAttrPrefix = "in_attr";
|
||||
private const string OutputAttrPrefix = "out_attr";
|
||||
private const string InputAttrName = "in_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 PredName = "pred";
|
||||
private const string TextureName = "tex";
|
||||
|
||||
private const string GprName = "gpr";
|
||||
private const string PredName = "pred";
|
||||
private const string SampName = "samp";
|
||||
|
||||
private int GprsCount;
|
||||
private int PredsCount;
|
||||
private int SampsCount;
|
||||
|
||||
private StringBuilder BodySB;
|
||||
private StringBuilder SB;
|
||||
|
||||
public GlslDecompiler()
|
||||
{
|
||||
|
@ -51,6 +51,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{ ShaderIrInst.Cgt, GetCgtExpr },
|
||||
{ ShaderIrInst.Cne, GetCneExpr },
|
||||
{ ShaderIrInst.Cge, GetCgeExpr },
|
||||
{ ShaderIrInst.Exit, GetExitExpr },
|
||||
{ ShaderIrInst.Fabs, GetFabsExpr },
|
||||
{ ShaderIrInst.Fadd, GetFaddExpr },
|
||||
{ ShaderIrInst.Fcos, GetFcosExpr },
|
||||
|
@ -73,50 +74,47 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public GlslProgram Decompile(int[] Code, GalShaderType Type)
|
||||
{
|
||||
InputAttributes = new SortedDictionary<int, GlslDeclInfo>();
|
||||
OutputAttributes = new SortedDictionary<int, GlslDeclInfo>();
|
||||
Uniforms = new Dictionary<(int, 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.
|
||||
if (Type == GalShaderType.Fragment)
|
||||
{
|
||||
OutputAttributes.Add(7, new GlslDeclInfo("FragColor", -1, 4));
|
||||
Gprs.Add(0, new GlslDeclInfo("FragColor", 0, 0, 4));
|
||||
}
|
||||
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);
|
||||
|
||||
ShaderIrNode[] Nodes = Block.GetNodes();
|
||||
|
||||
PrintBlockScope("void main()", 1, Nodes);
|
||||
|
||||
StringBuilder SB = new StringBuilder();
|
||||
foreach (ShaderIrNode Node in Nodes)
|
||||
{
|
||||
Traverse(null, Node);
|
||||
}
|
||||
|
||||
SB.AppendLine("#version 430");
|
||||
|
||||
PrintDeclUBOs(SB);
|
||||
PrintDeclInAttributes(SB);
|
||||
PrintDeclOutAttributes(SB);
|
||||
PrintDeclTextures();
|
||||
PrintDeclUniforms();
|
||||
PrintDeclInAttributes();
|
||||
PrintDeclOutAttributes();
|
||||
PrintDeclGprs();
|
||||
PrintDeclPreds();
|
||||
|
||||
if (Type == GalShaderType.Fragment)
|
||||
{
|
||||
SB.AppendLine($"out vec4 {OutputAttributes[7].Name};");
|
||||
SB.AppendLine();
|
||||
}
|
||||
|
||||
PrintDeclSamplers(SB);
|
||||
PrintDeclGprs(SB);
|
||||
PrintDeclPreds(SB);
|
||||
|
||||
SB.Append(BodySB.ToString());
|
||||
|
||||
BodySB.Clear();
|
||||
PrintBlockScope("void main()", 1, Nodes);
|
||||
|
||||
GlslProgram Program = new GlslProgram();
|
||||
|
||||
|
@ -124,33 +122,158 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
Program.Attributes = InputAttributes.Values.ToArray();
|
||||
|
||||
SB.Clear();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
foreach (KeyValuePair<int, GlslDeclInfo> KV in InputAttributes)
|
||||
foreach (GlslDeclInfo DeclInfo in Decls.OrderBy(DeclKeySelector))
|
||||
{
|
||||
int Index = KV.Key - AttrStartIndex;
|
||||
|
||||
if (Index >= 0)
|
||||
if (DeclInfo.Index >= 0)
|
||||
{
|
||||
string Type = ElemTypes[KV.Value.Size];
|
||||
|
||||
SB.AppendLine($"layout (location = {Index}) in {Type} {KV.Value.Name};");
|
||||
SB.AppendLine($"layout (location = {DeclInfo.Index}) {InOut} {GetDecl(DeclInfo)};");
|
||||
|
||||
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)
|
||||
private void PrintDeclPreds()
|
||||
{
|
||||
PrintDecls(Preds.Values, "bool");
|
||||
}
|
||||
|
||||
private void PrintDecls(ICollection<GlslDeclInfo> Decls, string CustomType = null)
|
||||
{
|
||||
foreach (GlslDeclInfo DeclInfo in Decls.OrderBy(DeclKeySelector))
|
||||
{
|
||||
int Index = KV.Key - AttrStartIndex;
|
||||
string Name;
|
||||
|
||||
if (Index >= 0)
|
||||
if (CustomType != null)
|
||||
{
|
||||
string Type = ElemTypes[KV.Value.Size];
|
||||
|
||||
SB.AppendLine($"layout (location = {Index}) out {Type} {KV.Value.Name};");
|
||||
|
||||
PrintNl = true;
|
||||
Name = $"{CustomType} {DeclInfo.Name};";
|
||||
}
|
||||
else
|
||||
{
|
||||
Name = $"{GetDecl(DeclInfo)};";
|
||||
}
|
||||
|
||||
SB.AppendLine(Name);
|
||||
}
|
||||
|
||||
if (PrintNl)
|
||||
if (Decls.Count > 0)
|
||||
{
|
||||
SB.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintDeclSamplers(StringBuilder SB)
|
||||
private int DeclKeySelector(GlslDeclInfo DeclInfo)
|
||||
{
|
||||
if (SampsCount > 0)
|
||||
{
|
||||
SB.AppendLine($"uniform sampler2D {SampName}[{SampsCount}];");
|
||||
SB.AppendLine();
|
||||
}
|
||||
return DeclInfo.Cbuf << 24 | DeclInfo.Index;
|
||||
}
|
||||
|
||||
private void PrintDeclGprs(StringBuilder SB)
|
||||
private string GetDecl(GlslDeclInfo DeclInfo)
|
||||
{
|
||||
if (GprsCount > 0)
|
||||
{
|
||||
SB.AppendLine($"float {GprName}[{GprsCount}];");
|
||||
SB.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintDeclPreds(StringBuilder SB)
|
||||
{
|
||||
if (PredsCount > 0)
|
||||
{
|
||||
SB.AppendLine($"bool {PredName}[{PredsCount}];");
|
||||
SB.AppendLine();
|
||||
}
|
||||
return $"{ElemTypes[DeclInfo.Size - 1]} {DeclInfo.Name}";
|
||||
}
|
||||
|
||||
private void PrintBlockScope(string ScopeName, int IdentationLevel, params ShaderIrNode[] Nodes)
|
||||
|
@ -227,7 +343,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
ScopeName += " ";
|
||||
}
|
||||
|
||||
BodySB.AppendLine(Identation + ScopeName + "{");
|
||||
SB.AppendLine(Identation + ScopeName + "{");
|
||||
|
||||
string LastLine = Identation + "}";
|
||||
|
||||
|
@ -250,14 +366,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
if (IsValidOutOper(Asg.Dst))
|
||||
{
|
||||
BodySB.AppendLine(Identation +
|
||||
$"{GetOutOperName(Asg.Dst)} = " +
|
||||
SB.AppendLine(Identation +
|
||||
$"{GetOutOperName(Asg.Dst)} = " +
|
||||
$"{GetInOperName (Asg.Src, true)};");
|
||||
}
|
||||
}
|
||||
else if (Node is ShaderIrOp Op)
|
||||
{
|
||||
BodySB.AppendLine($"{Identation}{GetInOperName(Op, true)};");
|
||||
SB.AppendLine($"{Identation}{GetInOperName(Op, true)};");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -265,16 +381,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
BodySB.AppendLine(LastLine);
|
||||
SB.AppendLine(LastLine);
|
||||
}
|
||||
|
||||
private bool IsValidOutOper(ShaderIrNode Node)
|
||||
{
|
||||
if (Node is ShaderIrOperGpr Gpr && Gpr.Index == ShaderIrOperGpr.ZRIndex)
|
||||
if (Node is ShaderIrOperGpr Gpr && Gpr.IsConst)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (Node is ShaderIrOperPred Pred && Pred.Index == ShaderIrOperPred.UnusedIndex)
|
||||
else if (Node is ShaderIrOperPred Pred && Pred.IsConst)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -307,6 +423,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
case ShaderIrOperAbuf Abuf: return GetName(Abuf);
|
||||
case ShaderIrOperCbuf Cbuf: return GetName(Cbuf);
|
||||
case ShaderIrOperGpr Gpr: return GetName(Gpr);
|
||||
case ShaderIrOperImm Imm: return GetName(Imm);
|
||||
case ShaderIrOperPred Pred: return GetName(Pred);
|
||||
|
||||
case ShaderIrOp Op:
|
||||
|
@ -327,7 +444,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
|
||||
return Expr;
|
||||
|
||||
|
||||
default: throw new ArgumentException(nameof(Node));
|
||||
}
|
||||
}
|
||||
|
@ -347,84 +464,77 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Inst == ShaderIrInst.Texr ||
|
||||
Inst == ShaderIrInst.Texg ||
|
||||
Inst == ShaderIrInst.Texb ||
|
||||
Inst == ShaderIrInst.Texa;
|
||||
}
|
||||
|
||||
private string GetOutAbufName(ShaderIrOperAbuf Abuf)
|
||||
{
|
||||
int Index = Abuf.Offs >> 4;
|
||||
|
||||
int Elem = (Abuf.Offs >> 2) & 3;
|
||||
|
||||
if (!OutputAttributes.TryGetValue(Index, out GlslDeclInfo Attr))
|
||||
{
|
||||
int GlslIndex = Index - AttrStartIndex;
|
||||
|
||||
Attr = new GlslDeclInfo(OutputAttrPrefix + GlslIndex, GlslIndex, Elem);
|
||||
|
||||
OutputAttributes.Add(Index, Attr);
|
||||
}
|
||||
|
||||
Attr.Enlarge(Elem);
|
||||
|
||||
return $"{Attr.Name}.{GetAttrSwizzle(Elem)}";
|
||||
}
|
||||
|
||||
private string GetName(ShaderIrOperAbuf Abuf, bool Swizzle = true)
|
||||
{
|
||||
int Index = Abuf.Offs >> 4;
|
||||
|
||||
int Elem = (Abuf.Offs >> 2) & 3;
|
||||
|
||||
if (!InputAttributes.TryGetValue(Index, out GlslDeclInfo Attr))
|
||||
{
|
||||
int GlslIndex = Index - AttrStartIndex;
|
||||
|
||||
Attr = new GlslDeclInfo(InputAttrPrefix + GlslIndex, GlslIndex, Elem);
|
||||
|
||||
InputAttributes.Add(Index, Attr);
|
||||
}
|
||||
|
||||
Attr.Enlarge(Elem);
|
||||
|
||||
return Swizzle ? $"{Attr.Name}.{GetAttrSwizzle(Elem)}" : Attr.Name;
|
||||
Inst == ShaderIrInst.Texa;
|
||||
}
|
||||
|
||||
private string GetName(ShaderIrOperCbuf Cbuf)
|
||||
{
|
||||
UsedCbufs.Add(Cbuf.Index);
|
||||
if (!Uniforms.TryGetValue((Cbuf.Index, Cbuf.Offs), out GlslDeclInfo DeclInfo))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return $"{CbufBuffPrefix}{Cbuf.Index}.{CbufDataName}[{Cbuf.Offs}]";
|
||||
return DeclInfo.Name;
|
||||
}
|
||||
|
||||
private string GetOutAbufName(ShaderIrOperAbuf Abuf)
|
||||
{
|
||||
return GetName(OutputAttributes, Abuf, Swizzle: true);
|
||||
}
|
||||
|
||||
private string GetName(ShaderIrOperAbuf Abuf, bool Swizzle = true)
|
||||
{
|
||||
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;
|
||||
|
||||
if (!Decls.TryGetValue(Index, out GlslDeclInfo DeclInfo))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Swizzle &= DeclInfo.Size > 1;
|
||||
|
||||
return Swizzle ? $"{DeclInfo.Name}.{GetAttrSwizzle(Elem)}" : DeclInfo.Name;
|
||||
}
|
||||
|
||||
private string GetName(ShaderIrOperGpr Gpr)
|
||||
{
|
||||
if (GprsCount < Gpr.Index + 1)
|
||||
{
|
||||
GprsCount = Gpr.Index + 1;
|
||||
}
|
||||
return Gpr.IsConst ? "0" : GetNameWithSwizzle(Gprs, Gpr.Index);
|
||||
}
|
||||
|
||||
return GetRegName(Gpr.Index);
|
||||
private string GetName(ShaderIrOperImm Imm)
|
||||
{
|
||||
return Imm.Imm.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
private string GetName(ShaderIrOperPred Pred)
|
||||
{
|
||||
if (PredsCount < Pred.Index + 1)
|
||||
return Pred.IsConst ? "true" : GetNameWithSwizzle(Preds, Pred.Index);
|
||||
}
|
||||
|
||||
private string GetNameWithSwizzle(Dictionary<int, GlslDeclInfo> Decls, int Index)
|
||||
{
|
||||
int VecIndex = Index >> 2;
|
||||
|
||||
if (Decls.TryGetValue(VecIndex, out GlslDeclInfo DeclInfo))
|
||||
{
|
||||
PredsCount = Pred.Index + 1;
|
||||
if (DeclInfo.Size > 1 && Index < VecIndex + DeclInfo.Size)
|
||||
{
|
||||
return $"{DeclInfo.Name}.{GetAttrSwizzle(Index & 3)}";
|
||||
}
|
||||
}
|
||||
|
||||
return GetPredName(Pred.Index);
|
||||
}
|
||||
if (!Decls.TryGetValue(Index, out DeclInfo))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetRegName(int GprIndex)
|
||||
{
|
||||
return GprIndex == ShaderIrOperGpr.ZRIndex ? "0" : $"{GprName}[{GprIndex}]";
|
||||
}
|
||||
|
||||
private string GetPredName(int PredIndex)
|
||||
{
|
||||
return PredIndex == ShaderIrOperPred.UnusedIndex ? "true" : $"{PredName}[{PredIndex}]";
|
||||
return DeclInfo.Name;
|
||||
}
|
||||
|
||||
private string GetBandExpr(ShaderIrOp Op)
|
||||
|
@ -474,6 +584,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
$"{GetInOperName(Op.OperandB)}";
|
||||
}
|
||||
|
||||
private string GetExitExpr(ShaderIrOp Op)
|
||||
{
|
||||
return "return";
|
||||
}
|
||||
|
||||
private string GetFabsExpr(ShaderIrOp Op)
|
||||
{
|
||||
return $"abs({GetInOperName(Op.OperandA)})";
|
||||
|
@ -557,14 +672,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
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)
|
||||
|
|
|
@ -4,6 +4,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
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)
|
||||
{
|
||||
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Kil), OpCode));
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
public static ShaderIrOperGpr GetOperGpr39(long OpCode)
|
||||
{
|
||||
return new ShaderIrOperGpr((int)(OpCode >> 39) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
public static ShaderIrOperGpr GetOperGpr0(long OpCode)
|
||||
{
|
||||
|
@ -62,8 +62,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public static ShaderIrNode GetOperImmf19_20(long OpCode)
|
||||
{
|
||||
//TODO
|
||||
return new ShaderIrNode();
|
||||
//TODO: This should be a float immediate.
|
||||
return new ShaderIrOperImm((int)(OpCode >> 36) & 0x1fff);
|
||||
}
|
||||
|
||||
public static ShaderIrOperImm GetOperImm13_36(long OpCode)
|
||||
|
@ -136,7 +136,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
public static ShaderIrNode GetPredNode(ShaderIrNode Node, long OpCode)
|
||||
{
|
||||
ShaderIrOperPred Pred = GetPredNode(OpCode);
|
||||
|
||||
|
||||
if (Pred.Index != ShaderIrOperPred.UnusedIndex)
|
||||
{
|
||||
Node = new ShaderIrCond(Pred, Node);
|
||||
|
|
|
@ -2,7 +2,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
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();
|
||||
|
||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
uint Word0 = (uint)Code[Offset++];
|
||||
uint Word1 = (uint)Code[Offset++];
|
||||
|
||||
long OpCode = Word0 | (long)Word1 << 32;
|
||||
long OpCode = Word0 | (long)Word1 << 32;
|
||||
|
||||
ShaderDecodeFunc Decode = ShaderOpCodeTable.GetDecoder(OpCode);
|
||||
|
||||
|
@ -21,19 +21,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
|
||||
Decode(Block, OpCode);
|
||||
|
||||
if (Block.GetLastNode() is ShaderIrOp Op && IsFlowChange(Op.Inst))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Type == GalShaderType.Fragment)
|
||||
{
|
||||
Block.AddNode(new ShaderIrAsg(new ShaderIrOperAbuf(0x70, 0), new ShaderIrOperGpr(0)));
|
||||
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;
|
||||
}
|
||||
|
||||
private static bool IsFlowChange(ShaderIrInst Inst)
|
||||
{
|
||||
return Inst == ShaderIrInst.Exit;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,14 +16,24 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Nodes.Add(Node);
|
||||
}
|
||||
|
||||
public void RunOptimizationPasses()
|
||||
public void RunOptimizationPasses(GalShaderType ShaderType)
|
||||
{
|
||||
ShaderOptExprProp.Optimize(Nodes);
|
||||
ShaderOptExprProp.Optimize(Nodes, ShaderType);
|
||||
}
|
||||
|
||||
public ShaderIrNode[] GetNodes()
|
||||
{
|
||||
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,
|
||||
Cneu,
|
||||
Cgeu,
|
||||
Exit,
|
||||
Fabs,
|
||||
Fadd,
|
||||
Fcos,
|
||||
|
|
|
@ -4,6 +4,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
public const int ZRIndex = 0xff;
|
||||
|
||||
public bool IsConst => Index == ZRIndex;
|
||||
|
||||
public int Index { get; set; }
|
||||
|
||||
public ShaderIrOperGpr(int Index)
|
||||
|
|
|
@ -5,6 +5,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
public const int UnusedIndex = 0x7;
|
||||
public const int NeverExecute = 0xf;
|
||||
|
||||
public bool IsConst => Index >= UnusedIndex;
|
||||
|
||||
public int Index { get; set; }
|
||||
|
||||
public ShaderIrOperPred(int Index)
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
OpCodes = new ShaderDecodeFunc[1 << EncodingBits];
|
||||
|
||||
#region Instructions
|
||||
Set("111000110000xx", ShaderDecode.Exit);
|
||||
Set("0101110001011x", ShaderDecode.Fadd_R);
|
||||
Set("0100110001011x", ShaderDecode.Fadd_C);
|
||||
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>();
|
||||
|
||||
|
@ -183,6 +183,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
//to a register took place. We traverse the expression tree to find
|
||||
//all registers being used, if any of those registers was assigned
|
||||
//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)>();
|
||||
|
||||
FindRegUses(UseList, Use.Asg, Use.Asg.Src);
|
||||
|
@ -227,7 +232,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Use = GetPredUse(Pred.Index);
|
||||
}
|
||||
|
||||
if (Use?.Asg != null && !IsConditional && TryPropagate(Use))
|
||||
if (!IsConditional && TryPropagate(Use))
|
||||
{
|
||||
Nodes.Remove(Use.Asg);
|
||||
|
||||
|
@ -241,6 +246,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
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))
|
||||
{
|
||||
Nodes.Remove(Use.Asg);
|
||||
|
|
|
@ -6,6 +6,41 @@ namespace Ryujinx.Graphics.Gpu
|
|||
{
|
||||
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 INvGpuEngine Engine;
|
||||
|
||||
|
@ -18,6 +53,10 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
private bool Carry;
|
||||
|
||||
private int OpCode;
|
||||
|
||||
private int PipeOp;
|
||||
|
||||
private long Pc;
|
||||
|
||||
public MacroInterpreter(NvGpuFifo PFifo, INvGpuEngine Engine)
|
||||
|
@ -34,11 +73,17 @@ namespace Ryujinx.Graphics.Gpu
|
|||
{
|
||||
Reset();
|
||||
|
||||
Pc = Position;
|
||||
|
||||
Gprs[1] = Param;
|
||||
|
||||
Pc = Position;
|
||||
|
||||
FetchOpCode(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()
|
||||
|
@ -56,46 +101,98 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
private bool Step(AMemory Memory)
|
||||
{
|
||||
long BaseAddr = Pc;
|
||||
long BaseAddr = Pc - 4;
|
||||
|
||||
int OpCode = Memory.ReadInt32(Pc);
|
||||
FetchOpCode(Memory);
|
||||
|
||||
Pc += 4;
|
||||
|
||||
int Op = OpCode & 7;
|
||||
|
||||
if (Op < 7)
|
||||
if ((OpCode & 7) < 7)
|
||||
{
|
||||
//Operation produces a value.
|
||||
int AsgOp = (OpCode >> 4) & 7;
|
||||
AssignmentOperation AsgOp = (AssignmentOperation)((OpCode >> 4) & 7);
|
||||
|
||||
int Result = GetInstResult(OpCode);
|
||||
int Result = GetAluResult();
|
||||
|
||||
switch (AsgOp)
|
||||
{
|
||||
//Fetch parameter and ignore result.
|
||||
case 0: SetDstGpr(OpCode, FetchParam()); break;
|
||||
case AssignmentOperation.IgnoreAndFetch:
|
||||
{
|
||||
SetDstGpr(FetchParam());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//Move result.
|
||||
case 1: SetDstGpr(OpCode, Result); break;
|
||||
case AssignmentOperation.Move:
|
||||
{
|
||||
SetDstGpr(Result);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//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.
|
||||
case 3: SetDstGpr(OpCode, FetchParam()); Send(Memory, Result); break;
|
||||
case AssignmentOperation.FetchAndSend:
|
||||
{
|
||||
SetDstGpr(FetchParam());
|
||||
|
||||
Send(Memory, Result);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//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.
|
||||
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.
|
||||
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.
|
||||
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
|
||||
|
@ -104,61 +201,59 @@ namespace Ryujinx.Graphics.Gpu
|
|||
bool OnNotZero = ((OpCode >> 4) & 1) != 0;
|
||||
|
||||
bool Taken = OnNotZero
|
||||
? GetGprA(OpCode) != 0
|
||||
: GetGprA(OpCode) == 0;
|
||||
? GetGprA() != 0
|
||||
: GetGprA() == 0;
|
||||
|
||||
if (Taken)
|
||||
{
|
||||
bool KeepExecuting = true;
|
||||
Pc = BaseAddr + (GetImm() << 2);
|
||||
|
||||
//When bit 5 is set, branches executes as if delay slots didn't exist.
|
||||
if ((OpCode & 0x20) == 0)
|
||||
bool NoDelays = (OpCode & 0x20) != 0;
|
||||
|
||||
if (NoDelays)
|
||||
{
|
||||
//Execute one more instruction due to delay slot.
|
||||
KeepExecuting = Step(Memory);
|
||||
FetchOpCode(Memory);
|
||||
}
|
||||
|
||||
Pc = BaseAddr + (GetImm(OpCode) << 2);
|
||||
|
||||
return KeepExecuting;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((OpCode & 0x80) != 0)
|
||||
{
|
||||
//Exit (with a delay slot).
|
||||
Step(Memory);
|
||||
bool Exit = (OpCode & 0x80) != 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return !Exit;
|
||||
}
|
||||
|
||||
private int GetInstResult(int OpCode)
|
||||
private void FetchOpCode(AMemory Memory)
|
||||
{
|
||||
int Low = OpCode & 7;
|
||||
OpCode = PipeOp;
|
||||
|
||||
switch (Low)
|
||||
PipeOp = Memory.ReadInt32(Pc);
|
||||
|
||||
Pc += 4;
|
||||
}
|
||||
|
||||
private int GetAluResult()
|
||||
{
|
||||
AluOperation Op = (AluOperation)(OpCode & 7);
|
||||
|
||||
switch (Op)
|
||||
{
|
||||
//Arithmetic or Logical operation.
|
||||
case 0:
|
||||
case AluOperation.AluReg:
|
||||
{
|
||||
int AluOp = (OpCode >> 17) & 0x1f;
|
||||
AluRegOperation AluOp = (AluRegOperation)((OpCode >> 17) & 0x1f);
|
||||
|
||||
return GetAluResult(AluOp, GetGprA(OpCode), GetGprB(OpCode));
|
||||
return GetAluResult(AluOp, GetGprA(), GetGprB());
|
||||
}
|
||||
|
||||
//Add Immediate.
|
||||
case 1:
|
||||
case AluOperation.AddImmediate:
|
||||
{
|
||||
return GetGprA(OpCode) + GetImm(OpCode);
|
||||
return GetGprA() + GetImm();
|
||||
}
|
||||
|
||||
//Bitfield.
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case AluOperation.BitfieldReplace:
|
||||
case AluOperation.BitfieldExtractLslImm:
|
||||
case AluOperation.BitfieldExtractLslReg:
|
||||
{
|
||||
int BfSrcBit = (OpCode >> 17) & 0x1f;
|
||||
int BfSize = (OpCode >> 22) & 0x1f;
|
||||
|
@ -166,13 +261,12 @@ namespace Ryujinx.Graphics.Gpu
|
|||
|
||||
int BfMask = (1 << BfSize) - 1;
|
||||
|
||||
int Dst = GetGprA(OpCode);
|
||||
int Src = GetGprB(OpCode);
|
||||
int Dst = GetGprA();
|
||||
int Src = GetGprB();
|
||||
|
||||
switch (Low)
|
||||
switch (Op)
|
||||
{
|
||||
//Bitfield move.
|
||||
case 2:
|
||||
case AluOperation.BitfieldReplace:
|
||||
{
|
||||
Src = (int)((uint)Src >> BfSrcBit) & BfMask;
|
||||
|
||||
|
@ -183,16 +277,14 @@ namespace Ryujinx.Graphics.Gpu
|
|||
return Dst;
|
||||
}
|
||||
|
||||
//Bitfield extract with left shift by immediate.
|
||||
case 3:
|
||||
case AluOperation.BitfieldExtractLslImm:
|
||||
{
|
||||
Src = (int)((uint)Src >> Dst) & BfMask;
|
||||
|
||||
return Src << BfDstBit;
|
||||
}
|
||||
|
||||
//Bitfield extract with left shift by register.
|
||||
case 4:
|
||||
case AluOperation.BitfieldExtractLslReg:
|
||||
{
|
||||
Src = (int)((uint)Src >> BfSrcBit) & BfMask;
|
||||
|
||||
|
@ -203,69 +295,66 @@ namespace Ryujinx.Graphics.Gpu
|
|||
break;
|
||||
}
|
||||
|
||||
case 5:
|
||||
case AluOperation.ReadImmediate:
|
||||
{
|
||||
return Read(GetGprA(OpCode) + GetImm(OpCode));
|
||||
return Read(GetGprA() + GetImm());
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
//Add.
|
||||
case 0: return A + B;
|
||||
|
||||
//Add with Carry.
|
||||
case 1:
|
||||
case AluRegOperation.Add:
|
||||
{
|
||||
ulong C = Carry ? 1UL : 0UL;
|
||||
|
||||
ulong Result = (ulong)A + (ulong)B + C;
|
||||
ulong Result = (ulong)A + (ulong)B;
|
||||
|
||||
Carry = Result > 0xffffffff;
|
||||
|
||||
return (int)Result;
|
||||
}
|
||||
|
||||
//Subtract.
|
||||
case 2: return A - B;
|
||||
|
||||
//Subtract with Borrow.
|
||||
case 3:
|
||||
case AluRegOperation.AddWithCarry:
|
||||
{
|
||||
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;
|
||||
|
||||
return (int)Result;
|
||||
}
|
||||
|
||||
//Exclusive Or.
|
||||
case 8: return A ^ B;
|
||||
case AluRegOperation.SubtractWithBorrow:
|
||||
{
|
||||
ulong Result = (ulong)A - (ulong)B - (Carry ? 0UL : 1UL);
|
||||
|
||||
//Or.
|
||||
case 9: return A | B;
|
||||
Carry = Result < 0x100000000;
|
||||
|
||||
//And.
|
||||
case 10: return A & B;
|
||||
return (int)Result;
|
||||
}
|
||||
|
||||
//And Not.
|
||||
case 11: return A & ~B;
|
||||
|
||||
//Not And.
|
||||
case 12: return ~(A & B);
|
||||
case AluRegOperation.BitwiseExclusiveOr: return A ^ B;
|
||||
case AluRegOperation.BitwiseOr: return A | B;
|
||||
case AluRegOperation.BitwiseAnd: return A & B;
|
||||
case AluRegOperation.BitwiseAndNot: return A & ~B;
|
||||
case AluRegOperation.BitwiseNotAnd: return ~(A & B);
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(AluOp));
|
||||
}
|
||||
|
||||
private int GetImm(int OpCode)
|
||||
private int GetImm()
|
||||
{
|
||||
//Note: The immediate is signed, the sign-extension is intended here.
|
||||
return OpCode >> 14;
|
||||
|
@ -277,17 +366,17 @@ namespace Ryujinx.Graphics.Gpu
|
|||
MethIncr = (Value >> 12) & 0x3f;
|
||||
}
|
||||
|
||||
private void SetDstGpr(int OpCode, int Value)
|
||||
private void SetDstGpr(int Value)
|
||||
{
|
||||
Gprs[(OpCode >> 8) & 7] = Value;
|
||||
}
|
||||
|
||||
private int GetGprA(int OpCode)
|
||||
private int GetGprA()
|
||||
{
|
||||
return GetGprValue((OpCode >> 11) & 7);
|
||||
}
|
||||
|
||||
private int GetGprB(int OpCode)
|
||||
private int GetGprB()
|
||||
{
|
||||
return GetGprValue((OpCode >> 14) & 7);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
|
@ -63,11 +65,52 @@ namespace Ryujinx.Graphics.Gpu
|
|||
int TexCbuf = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
|
||||
|
||||
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)
|
||||
{
|
||||
if (TryGetCpuAddr(NvGpuEngine3dReg.QueryAddr, out long Position))
|
||||
if (TryGetCpuAddr(NvGpuEngine3dReg.QueryAddress, out long Position))
|
||||
{
|
||||
int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence];
|
||||
int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl];
|
||||
|
|
|
@ -2,9 +2,14 @@ namespace Ryujinx.Graphics.Gpu
|
|||
{
|
||||
enum NvGpuEngine3dReg
|
||||
{
|
||||
QueryAddr = 0x6c0,
|
||||
ShaderAddress = 0x582,
|
||||
QueryAddress = 0x6c0,
|
||||
QuerySequence = 0x6c2,
|
||||
QueryControl = 0x6c3,
|
||||
ShaderControl = 0x800,
|
||||
ShaderOffset = 0x801,
|
||||
ShaderMaxGprs = 0x803,
|
||||
ShaderType = 0x804,
|
||||
CbSize = 0x8e0,
|
||||
CbAddress = 0x8e1,
|
||||
CbOffset = 0x8e3,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using ChocolArm64.Memory;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue