[GPU] Add more shader instructions, add support for rgb565 textures
This commit is contained in:
parent
e9cfdef098
commit
feb2680a6c
22 changed files with 817 additions and 238 deletions
|
@ -4,6 +4,7 @@ namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
A8B8G8R8 = 0x8,
|
A8B8G8R8 = 0x8,
|
||||||
A1B5G5R5 = 0x14,
|
A1B5G5R5 = 0x14,
|
||||||
|
B5G6R5 = 0x15,
|
||||||
BC1 = 0x24,
|
BC1 = 0x24,
|
||||||
BC2 = 0x25,
|
BC2 = 0x25,
|
||||||
BC3 = 0x26
|
BC3 = 0x26
|
||||||
|
|
|
@ -55,6 +55,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
throw new ArgumentException(nameof(Type));
|
throw new ArgumentException(nameof(Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static (PixelFormat, PixelType) GetTextureFormat(GalTextureFormat Format)
|
||||||
|
{
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalTextureFormat.A8B8G8R8: return (PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||||
|
case GalTextureFormat.A1B5G5R5: return (PixelFormat.Rgba, PixelType.UnsignedShort5551);
|
||||||
|
case GalTextureFormat.B5G6R5: return (PixelFormat.Rgb, PixelType.UnsignedShort565);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException(Format.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
public static PixelInternalFormat GetCompressedTextureFormat(GalTextureFormat Format)
|
public static PixelInternalFormat GetCompressedTextureFormat(GalTextureFormat Format)
|
||||||
{
|
{
|
||||||
switch (Format)
|
switch (Format)
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Textures = new int[80];
|
Textures = new int[80];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set(int Index, GalTexture Tex)
|
public void Set(int Index, GalTexture Texture)
|
||||||
{
|
{
|
||||||
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||||||
|
|
||||||
|
@ -19,29 +19,38 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||||
|
|
||||||
int W = Tex.Width;
|
const int Border = 0;
|
||||||
int H = Tex.Height;
|
|
||||||
|
|
||||||
byte[] Data = Tex.Data;
|
if (IsCompressedTextureFormat(Texture.Format))
|
||||||
|
|
||||||
int Length = Data.Length;
|
|
||||||
|
|
||||||
if (IsCompressedTextureFormat(Tex.Format))
|
|
||||||
{
|
{
|
||||||
PixelInternalFormat Pif = OGLEnumConverter.GetCompressedTextureFormat(Tex.Format);
|
PixelInternalFormat InternalFmt = OGLEnumConverter.GetCompressedTextureFormat(Texture.Format);
|
||||||
|
|
||||||
GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Length, Data);
|
GL.CompressedTexImage2D(
|
||||||
|
TextureTarget.Texture2D,
|
||||||
|
0,
|
||||||
|
InternalFmt,
|
||||||
|
Texture.Width,
|
||||||
|
Texture.Height,
|
||||||
|
Border,
|
||||||
|
Texture.Data.Length,
|
||||||
|
Texture.Data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//TODO: Get those from Texture format.
|
const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
|
||||||
const PixelInternalFormat Pif = PixelInternalFormat.Rgba;
|
|
||||||
|
|
||||||
const PixelFormat Pf = PixelFormat.Rgba;
|
(PixelFormat, PixelType) Format = OGLEnumConverter.GetTextureFormat(Texture.Format);
|
||||||
|
|
||||||
const PixelType Pt = PixelType.UnsignedByte;
|
GL.TexImage2D(
|
||||||
|
TextureTarget.Texture2D,
|
||||||
GL.TexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Pf, Pt, Data);
|
0,
|
||||||
|
InternalFmt,
|
||||||
|
Texture.Width,
|
||||||
|
Texture.Height,
|
||||||
|
Border,
|
||||||
|
Format.Item1,
|
||||||
|
Format.Item2,
|
||||||
|
Texture.Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public void Render()
|
public void Render()
|
||||||
{
|
{
|
||||||
FbRenderer.Render();
|
//FbRenderer.Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetWindowSize(int Width, int Height)
|
public void SetWindowSize(int Width, int Height)
|
||||||
|
|
|
@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
private const int AttrStartIndex = 8;
|
private const int AttrStartIndex = 8;
|
||||||
private const int TexStartIndex = 8;
|
private const int TexStartIndex = 8;
|
||||||
|
|
||||||
|
public const string PositionOutAttrName = "position";
|
||||||
|
|
||||||
private const string InAttrName = "in_attr";
|
private const string InAttrName = "in_attr";
|
||||||
private const string OutAttrName = "out_attr";
|
private const string OutAttrName = "out_attr";
|
||||||
private const string UniformName = "c";
|
private const string UniformName = "c";
|
||||||
|
@ -62,10 +64,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
m_Gprs = new Dictionary<int, ShaderDeclInfo>();
|
m_Gprs = new Dictionary<int, ShaderDeclInfo>();
|
||||||
m_Preds = new Dictionary<int, ShaderDeclInfo>();
|
m_Preds = new Dictionary<int, ShaderDeclInfo>();
|
||||||
|
|
||||||
//FIXME: Only valid for vertex shaders.
|
|
||||||
if (ShaderType == GalShaderType.Fragment)
|
if (ShaderType == GalShaderType.Fragment)
|
||||||
{
|
{
|
||||||
m_Gprs.Add(0, new ShaderDeclInfo(FragmentOutputName, 0, 0, 4));
|
m_Gprs.Add(0, new ShaderDeclInfo(FragmentOutputName, 0, 0, 4));
|
||||||
|
|
||||||
|
m_InAttributes.Add(7, new ShaderDeclInfo(PositionOutAttrName, -1, 0, 4));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -104,10 +107,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Traverse(Op, Op.OperandB);
|
Traverse(Op, Op.OperandB);
|
||||||
Traverse(Op, Op.OperandC);
|
Traverse(Op, Op.OperandC);
|
||||||
|
|
||||||
if (Op.Inst == ShaderIrInst.Texr ||
|
if (Op.Inst == ShaderIrInst.Texq ||
|
||||||
Op.Inst == ShaderIrInst.Texg ||
|
Op.Inst == ShaderIrInst.Texs ||
|
||||||
Op.Inst == ShaderIrInst.Texb ||
|
Op.Inst == ShaderIrInst.Txlf)
|
||||||
Op.Inst == ShaderIrInst.Texa)
|
|
||||||
{
|
{
|
||||||
int Handle = ((ShaderIrOperImm)Op.OperandC).Value;
|
int Handle = ((ShaderIrOperImm)Op.OperandC).Value;
|
||||||
|
|
||||||
|
|
|
@ -31,40 +31,51 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
|
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
|
||||||
{
|
{
|
||||||
{ ShaderIrInst.And, GetAndExpr },
|
{ ShaderIrInst.And, GetAndExpr },
|
||||||
{ ShaderIrInst.Asr, GetAsrExpr },
|
{ ShaderIrInst.Asr, GetAsrExpr },
|
||||||
{ ShaderIrInst.Band, GetBandExpr },
|
{ ShaderIrInst.Band, GetBandExpr },
|
||||||
{ ShaderIrInst.Bnot, GetBnotExpr },
|
{ ShaderIrInst.Bnot, GetBnotExpr },
|
||||||
{ ShaderIrInst.Clt, GetCltExpr },
|
{ ShaderIrInst.Ceil, GetCeilExpr },
|
||||||
{ ShaderIrInst.Ceq, GetCeqExpr },
|
{ ShaderIrInst.Ceq, GetCeqExpr },
|
||||||
{ ShaderIrInst.Cle, GetCleExpr },
|
{ ShaderIrInst.Cge, GetCgeExpr },
|
||||||
{ ShaderIrInst.Cgt, GetCgtExpr },
|
{ ShaderIrInst.Cgt, GetCgtExpr },
|
||||||
{ ShaderIrInst.Cne, GetCneExpr },
|
{ ShaderIrInst.Clamp, GetClampExpr },
|
||||||
{ ShaderIrInst.Cge, GetCgeExpr },
|
{ ShaderIrInst.Cle, GetCleExpr },
|
||||||
{ ShaderIrInst.Exit, GetExitExpr },
|
{ ShaderIrInst.Clt, GetCltExpr },
|
||||||
{ ShaderIrInst.Fabs, GetFabsExpr },
|
{ ShaderIrInst.Cne, GetCneExpr },
|
||||||
{ ShaderIrInst.Fadd, GetFaddExpr },
|
{ ShaderIrInst.Exit, GetExitExpr },
|
||||||
{ ShaderIrInst.Fcos, GetFcosExpr },
|
{ ShaderIrInst.Fabs, GetFabsExpr },
|
||||||
{ ShaderIrInst.Fex2, GetFex2Expr },
|
{ ShaderIrInst.Fadd, GetFaddExpr },
|
||||||
{ ShaderIrInst.Ffma, GetFfmaExpr },
|
{ ShaderIrInst.Fceq, GetCeqExpr },
|
||||||
{ ShaderIrInst.Flg2, GetFlg2Expr },
|
{ ShaderIrInst.Fcge, GetCgeExpr },
|
||||||
{ ShaderIrInst.Fmul, GetFmulExpr },
|
{ ShaderIrInst.Fcgt, GetCgtExpr },
|
||||||
{ ShaderIrInst.Fneg, GetFnegExpr },
|
{ ShaderIrInst.Fcle, GetCleExpr },
|
||||||
{ ShaderIrInst.Frcp, GetFrcpExpr },
|
{ ShaderIrInst.Fclt, GetCltExpr },
|
||||||
{ ShaderIrInst.Frsq, GetFrsqExpr },
|
{ ShaderIrInst.Fcne, GetCneExpr },
|
||||||
{ ShaderIrInst.Fsin, GetFsinExpr },
|
{ ShaderIrInst.Fcos, GetFcosExpr },
|
||||||
{ ShaderIrInst.Ipa, GetIpaExpr },
|
{ ShaderIrInst.Fex2, GetFex2Expr },
|
||||||
{ ShaderIrInst.Kil, GetKilExpr },
|
{ ShaderIrInst.Ffma, GetFfmaExpr },
|
||||||
{ ShaderIrInst.Lsr, GetLsrExpr },
|
{ ShaderIrInst.Flg2, GetFlg2Expr },
|
||||||
{ ShaderIrInst.Not, GetNotExpr },
|
{ ShaderIrInst.Floor, GetFloorExpr },
|
||||||
{ ShaderIrInst.Or, GetOrExpr },
|
{ ShaderIrInst.Fmul, GetFmulExpr },
|
||||||
{ ShaderIrInst.Stof, GetStofExpr },
|
{ ShaderIrInst.Fneg, GetFnegExpr },
|
||||||
{ ShaderIrInst.Utof, GetUtofExpr },
|
{ ShaderIrInst.Frcp, GetFrcpExpr },
|
||||||
{ ShaderIrInst.Texr, GetTexrExpr },
|
{ ShaderIrInst.Frsq, GetFrsqExpr },
|
||||||
{ ShaderIrInst.Texg, GetTexgExpr },
|
{ ShaderIrInst.Fsin, GetFsinExpr },
|
||||||
{ ShaderIrInst.Texb, GetTexbExpr },
|
{ ShaderIrInst.Ftos, GetFtosExpr },
|
||||||
{ ShaderIrInst.Texa, GetTexaExpr },
|
{ ShaderIrInst.Ftou, GetFtouExpr },
|
||||||
{ ShaderIrInst.Xor, GetXorExpr },
|
{ ShaderIrInst.Ipa, GetIpaExpr },
|
||||||
|
{ ShaderIrInst.Kil, GetKilExpr },
|
||||||
|
{ ShaderIrInst.Lsr, GetLsrExpr },
|
||||||
|
{ ShaderIrInst.Not, GetNotExpr },
|
||||||
|
{ ShaderIrInst.Or, GetOrExpr },
|
||||||
|
{ ShaderIrInst.Stof, GetStofExpr },
|
||||||
|
{ ShaderIrInst.Texq, GetTexqExpr },
|
||||||
|
{ ShaderIrInst.Texs, GetTexsExpr },
|
||||||
|
{ ShaderIrInst.Trunc, GetTruncExpr },
|
||||||
|
{ ShaderIrInst.Txlf, GetTxlfExpr },
|
||||||
|
{ ShaderIrInst.Utof, GetUtofExpr },
|
||||||
|
{ ShaderIrInst.Xor, GetXorExpr }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,11 +128,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private void PrintDeclInAttributes()
|
private void PrintDeclInAttributes()
|
||||||
{
|
{
|
||||||
|
if (Decl.ShaderType == GalShaderType.Fragment)
|
||||||
|
{
|
||||||
|
SB.AppendLine("in vec4 " + GlslDecl.PositionOutAttrName + ";");
|
||||||
|
}
|
||||||
|
|
||||||
PrintDeclAttributes(Decl.InAttributes.Values, "in");
|
PrintDeclAttributes(Decl.InAttributes.Values, "in");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclOutAttributes()
|
private void PrintDeclOutAttributes()
|
||||||
{
|
{
|
||||||
|
if (Decl.ShaderType == GalShaderType.Vertex)
|
||||||
|
{
|
||||||
|
SB.AppendLine("out vec4 " + GlslDecl.PositionOutAttrName + ";");
|
||||||
|
}
|
||||||
|
|
||||||
PrintDeclAttributes(Decl.OutAttributes.Values, "out");
|
PrintDeclAttributes(Decl.OutAttributes.Values, "out");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +154,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
if (DeclInfo.Index >= 0)
|
if (DeclInfo.Index >= 0)
|
||||||
{
|
{
|
||||||
SB.AppendLine($"layout (location = {DeclInfo.Index}) {InOut} {GetDecl(DeclInfo)};");
|
SB.AppendLine("layout (location = " + DeclInfo.Index + ") " + InOut + " " + GetDecl(DeclInfo) + ";");
|
||||||
|
|
||||||
Count++;
|
Count++;
|
||||||
}
|
}
|
||||||
|
@ -222,7 +243,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (Node is ShaderIrCond Cond)
|
if (Node is ShaderIrCond Cond)
|
||||||
{
|
{
|
||||||
string SubScopeName = "if (" + GetSrcExpr(Cond.Pred, true) + ")";
|
string IfExpr = GetSrcExpr(Cond.Pred, true);
|
||||||
|
|
||||||
|
if (Cond.Not)
|
||||||
|
{
|
||||||
|
IfExpr = "!(" + IfExpr + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
string SubScopeName = "if (" + IfExpr + ")";
|
||||||
|
|
||||||
PrintBlockScope(SubScopeName, IdentationLevel + 1, Cond.Child);
|
PrintBlockScope(SubScopeName, IdentationLevel + 1, Cond.Child);
|
||||||
}
|
}
|
||||||
|
@ -236,6 +264,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
else if (Node is ShaderIrOp Op)
|
else if (Node is ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
|
if (Op.Inst == ShaderIrInst.Exit)
|
||||||
|
{
|
||||||
|
//Do everything that needs to be done before
|
||||||
|
//the shader ends here.
|
||||||
|
if (Decl.ShaderType == GalShaderType.Vertex)
|
||||||
|
{
|
||||||
|
SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + " = gl_Position;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
|
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -321,10 +359,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ShaderIrInst.Ipa:
|
case ShaderIrInst.Ipa:
|
||||||
case ShaderIrInst.Texr:
|
case ShaderIrInst.Texq:
|
||||||
case ShaderIrInst.Texg:
|
case ShaderIrInst.Texs:
|
||||||
case ShaderIrInst.Texb:
|
case ShaderIrInst.Txlf:
|
||||||
case ShaderIrInst.Texa:
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,11 +386,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetName(ShaderIrOperAbuf Abuf)
|
private string GetName(ShaderIrOperAbuf Abuf)
|
||||||
{
|
{
|
||||||
if (Abuf.Offs == GlslDecl.GlPositionWAttr && Decl.ShaderType == GalShaderType.Fragment)
|
|
||||||
{
|
|
||||||
return "(1f / gl_FragCoord.w)";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Abuf.Offs == GlslDecl.VertexIdAttr)
|
if (Abuf.Offs == GlslDecl.VertexIdAttr)
|
||||||
{
|
{
|
||||||
return "gl_VertexID";
|
return "gl_VertexID";
|
||||||
|
@ -437,6 +469,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetBnotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "!");
|
private string GetBnotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "!");
|
||||||
|
|
||||||
|
private string GetCeilExpr(ShaderIrOp Op) => GetUnaryCall(Op, "ceil");
|
||||||
|
|
||||||
|
private string GetClampExpr(ShaderIrOp Op) => GetTernaryCall(Op, "clamp");
|
||||||
|
|
||||||
private string GetCltExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<");
|
private string GetCltExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<");
|
||||||
private string GetCeqExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "==");
|
private string GetCeqExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "==");
|
||||||
private string GetCleExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<=");
|
private string GetCleExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<=");
|
||||||
|
@ -458,6 +494,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetFlg2Expr(ShaderIrOp Op) => GetUnaryCall(Op, "log2");
|
private string GetFlg2Expr(ShaderIrOp Op) => GetUnaryCall(Op, "log2");
|
||||||
|
|
||||||
|
private string GetFloorExpr(ShaderIrOp Op) => GetUnaryCall(Op, "floor");
|
||||||
|
|
||||||
private string GetFmulExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "*");
|
private string GetFmulExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "*");
|
||||||
|
|
||||||
private string GetFnegExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "-");
|
private string GetFnegExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "-");
|
||||||
|
@ -468,6 +506,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetFsinExpr(ShaderIrOp Op) => GetUnaryCall(Op, "sin");
|
private string GetFsinExpr(ShaderIrOp Op) => GetUnaryCall(Op, "sin");
|
||||||
|
|
||||||
|
private string GetFtosExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return "int(" + GetOperExpr(Op, Op.OperandA) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFtouExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return "int(uint(" + GetOperExpr(Op, Op.OperandA) + "))";
|
||||||
|
}
|
||||||
|
|
||||||
private string GetIpaExpr(ShaderIrOp Op) => GetSrcExpr(Op.OperandA);
|
private string GetIpaExpr(ShaderIrOp Op) => GetSrcExpr(Op.OperandA);
|
||||||
|
|
||||||
private string GetKilExpr(ShaderIrOp Op) => "discard";
|
private string GetKilExpr(ShaderIrOp Op) => "discard";
|
||||||
|
@ -487,6 +535,54 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return "float(" + GetOperExpr(Op, Op.OperandA) + ")";
|
return "float(" + GetOperExpr(Op, Op.OperandA) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetTexqExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
ShaderIrMetaTexq Meta = (ShaderIrMetaTexq)Op.MetaData;
|
||||||
|
|
||||||
|
string Ch = "xyzw".Substring(Meta.Elem, 1);
|
||||||
|
|
||||||
|
if (Meta.Info == ShaderTexqInfo.Dimension)
|
||||||
|
{
|
||||||
|
string Sampler = GetTexSamplerName(Op);
|
||||||
|
|
||||||
|
string Lod = GetOperExpr(Op, Op.OperandA); //???
|
||||||
|
|
||||||
|
return "textureSize(" + Sampler + ", " + Lod + ")." + Ch;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException(Meta.Info.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetTexsExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
|
||||||
|
|
||||||
|
string Sampler = GetTexSamplerName(Op);
|
||||||
|
|
||||||
|
string Coords = GetTexSamplerCoords(Op);
|
||||||
|
|
||||||
|
string Ch = "rgba".Substring(Meta.Elem, 1);
|
||||||
|
|
||||||
|
return "texture(" + Sampler + ", " + Coords + ")." + Ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetTxlfExpr(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
|
||||||
|
|
||||||
|
string Sampler = GetTexSamplerName(Op);
|
||||||
|
|
||||||
|
string Coords = GetITexSamplerCoords(Op);
|
||||||
|
|
||||||
|
string Ch = "rgba".Substring(Meta.Elem, 1);
|
||||||
|
|
||||||
|
return "texelFetch(" + Sampler + ", " + Coords + ", 0)." + Ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetTruncExpr(ShaderIrOp Op) => GetUnaryCall(Op, "trunc");
|
||||||
|
|
||||||
private string GetUtofExpr(ShaderIrOp Op)
|
private string GetUtofExpr(ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
return "float(uint(" + GetOperExpr(Op, Op.OperandA) + "))";
|
return "float(uint(" + GetOperExpr(Op, Op.OperandA) + "))";
|
||||||
|
@ -499,6 +595,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ")";
|
return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetTernaryCall(ShaderIrOp Op, string FuncName)
|
||||||
|
{
|
||||||
|
return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ", " +
|
||||||
|
GetOperExpr(Op, Op.OperandB) + ", " +
|
||||||
|
GetOperExpr(Op, Op.OperandC) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
private string GetUnaryExpr(ShaderIrOp Op, string Opr)
|
private string GetUnaryExpr(ShaderIrOp Op, string Opr)
|
||||||
{
|
{
|
||||||
return Opr + GetOperExpr(Op, Op.OperandA);
|
return Opr + GetOperExpr(Op, Op.OperandA);
|
||||||
|
@ -517,16 +620,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
GetOperExpr(Op, Op.OperandC);
|
GetOperExpr(Op, Op.OperandC);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetTexrExpr(ShaderIrOp Op) => GetTexExpr(Op, 'r');
|
|
||||||
private string GetTexgExpr(ShaderIrOp Op) => GetTexExpr(Op, 'g');
|
|
||||||
private string GetTexbExpr(ShaderIrOp Op) => GetTexExpr(Op, 'b');
|
|
||||||
private string GetTexaExpr(ShaderIrOp Op) => GetTexExpr(Op, 'a');
|
|
||||||
|
|
||||||
private string GetTexExpr(ShaderIrOp Op, char Ch)
|
|
||||||
{
|
|
||||||
return $"texture({GetTexSamplerName(Op)}, {GetTexSamplerCoords(Op)}).{Ch}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetTexSamplerName(ShaderIrOp Op)
|
private string GetTexSamplerName(ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
ShaderIrOperImm Node = (ShaderIrOperImm)Op.OperandC;
|
ShaderIrOperImm Node = (ShaderIrOperImm)Op.OperandC;
|
||||||
|
@ -547,6 +640,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
GetOperExpr(Op, Op.OperandB) + ")";
|
GetOperExpr(Op, Op.OperandB) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetITexSamplerCoords(ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
return "ivec2(" + GetOperExpr(Op, Op.OperandA) + ", " +
|
||||||
|
GetOperExpr(Op, Op.OperandB) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper)
|
private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper)
|
||||||
{
|
{
|
||||||
return GetExprWithCast(Op, Oper, GetSrcExpr(Oper));
|
return GetExprWithCast(Op, Oper, GetSrcExpr(Oper));
|
||||||
|
@ -571,13 +670,31 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
//For integer immediates being used as float,
|
switch (Src)
|
||||||
//it's better (for readability) to just return the float value.
|
|
||||||
if (Src is ShaderIrOperImm Imm && DstType == OperType.F32)
|
|
||||||
{
|
{
|
||||||
float Value = BitConverter.Int32BitsToSingle(Imm.Value);
|
case ShaderIrOperGpr Gpr:
|
||||||
|
{
|
||||||
|
//When the Gpr is ZR, just return the 0 value directly,
|
||||||
|
//since the float encoding for 0 is 0.
|
||||||
|
if (Gpr.IsConst)
|
||||||
|
{
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return Value.ToString(CultureInfo.InvariantCulture) + "f";
|
case ShaderIrOperImm Imm:
|
||||||
|
{
|
||||||
|
//For integer immediates being used as float,
|
||||||
|
//it's better (for readability) to just return the float value.
|
||||||
|
if (DstType == OperType.F32)
|
||||||
|
{
|
||||||
|
float Value = BitConverter.Int32BitsToSingle(Imm.Value);
|
||||||
|
|
||||||
|
return Value.ToString(CultureInfo.InvariantCulture) + "f";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (DstType)
|
switch (DstType)
|
||||||
|
@ -592,12 +709,20 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private static OperType GetDstNodeType(ShaderIrNode Node)
|
private static OperType GetDstNodeType(ShaderIrNode Node)
|
||||||
{
|
{
|
||||||
|
//Special case instructions with the result type different
|
||||||
|
//from the input types (like integer <-> float conversion) here.
|
||||||
if (Node is ShaderIrOp Op)
|
if (Node is ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
switch (Op.Inst)
|
switch (Op.Inst)
|
||||||
{
|
{
|
||||||
case ShaderIrInst.Stof: return OperType.F32;
|
case ShaderIrInst.Stof:
|
||||||
case ShaderIrInst.Utof: return OperType.F32;
|
case ShaderIrInst.Txlf:
|
||||||
|
case ShaderIrInst.Utof:
|
||||||
|
return OperType.F32;
|
||||||
|
|
||||||
|
case ShaderIrInst.Ftos:
|
||||||
|
case ShaderIrInst.Ftou:
|
||||||
|
return OperType.I32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Isetp_C(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitIsetp(Block, OpCode, ShaderOper.CR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Isetp_I(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitIsetp(Block, OpCode, ShaderOper.Imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Isetp_R(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitIsetp(Block, OpCode, ShaderOper.RR);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Lop32i(ShaderIrBlock Block, long OpCode)
|
public static void Lop32i(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
int SubOp = (int)(OpCode >> 53) & 3;
|
int SubOp = (int)(OpCode >> 53) & 3;
|
||||||
|
@ -258,6 +273,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitFsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitFsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
|
{
|
||||||
|
EmitSetp(Block, OpCode, true, Oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitIsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
|
{
|
||||||
|
EmitSetp(Block, OpCode, false, Oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitSetp(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
bool Aa = ((OpCode >> 7) & 1) != 0;
|
bool Aa = ((OpCode >> 7) & 1) != 0;
|
||||||
bool Np = ((OpCode >> 42) & 1) != 0;
|
bool Np = ((OpCode >> 42) & 1) != 0;
|
||||||
|
@ -269,17 +294,28 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
switch (Oper)
|
switch (Oper)
|
||||||
{
|
{
|
||||||
case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
|
case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
|
||||||
|
case ShaderOper.Imm: OperB = GetOperImm19_20 (OpCode); break;
|
||||||
case ShaderOper.Immf: OperB = GetOperImmf19_20(OpCode); break;
|
case ShaderOper.Immf: OperB = GetOperImmf19_20(OpCode); break;
|
||||||
case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
|
case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrInst CmpInst = GetCmp(OpCode);
|
ShaderIrInst CmpInst;
|
||||||
|
|
||||||
ShaderIrOp Op = new ShaderIrOp(CmpInst,
|
if (IsFloat)
|
||||||
GetAluAbsNeg(OperA, Aa, Na),
|
{
|
||||||
GetAluAbs (OperB, Ab));
|
OperA = GetAluAbsNeg(OperA, Aa, Na);
|
||||||
|
OperB = GetAluAbs (OperB, Ab);
|
||||||
|
|
||||||
|
CmpInst = GetCmpF(OpCode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CmpInst = GetCmp(OpCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);
|
||||||
|
|
||||||
ShaderIrOperPred P0Node = GetOperPred3 (OpCode);
|
ShaderIrOperPred P0Node = GetOperPred3 (OpCode);
|
||||||
ShaderIrOperPred P1Node = GetOperPred0 (OpCode);
|
ShaderIrOperPred P1Node = GetOperPred0 (OpCode);
|
||||||
|
|
|
@ -60,7 +60,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return new ShaderIrOperGpr((int)(OpCode >> 28) & 0xff);
|
return new ShaderIrOperGpr((int)(OpCode >> 28) & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrNode GetOperImm19_20(long OpCode)
|
public static ShaderIrOperImm GetOperImm13_36(long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperImm((int)(OpCode >> 36) & 0x1fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrOperImm GetOperImm32_20(long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperImm((int)(OpCode >> 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrOperImm GetOperImm19_20(long OpCode)
|
||||||
{
|
{
|
||||||
int Value = (int)(OpCode >> 20) & 0x7ffff;
|
int Value = (int)(OpCode >> 20) & 0x7ffff;
|
||||||
|
|
||||||
|
@ -74,7 +84,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return new ShaderIrOperImm((int)Value);
|
return new ShaderIrOperImm((int)Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrNode GetOperImmf19_20(long OpCode)
|
public static ShaderIrOperImmf GetOperImmf19_20(long OpCode)
|
||||||
{
|
{
|
||||||
uint Imm = (uint)(OpCode >> 20) & 0x7ffff;
|
uint Imm = (uint)(OpCode >> 20) & 0x7ffff;
|
||||||
|
|
||||||
|
@ -92,16 +102,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return new ShaderIrOperImmf(Value);
|
return new ShaderIrOperImmf(Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrOperImm GetOperImm13_36(long OpCode)
|
|
||||||
{
|
|
||||||
return new ShaderIrOperImm((int)(OpCode >> 36) & 0x1fff);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ShaderIrOperImm GetOperImm32_20(long OpCode)
|
|
||||||
{
|
|
||||||
return new ShaderIrOperImm((int)(OpCode >> 20));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ShaderIrOperPred GetOperPred3(long OpCode)
|
public static ShaderIrOperPred GetOperPred3(long OpCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperPred((int)(OpCode >> 3) & 7);
|
return new ShaderIrOperPred((int)(OpCode >> 3) & 7);
|
||||||
|
@ -130,23 +130,38 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrInst GetCmp(long OpCode)
|
public static ShaderIrInst GetCmp(long OpCode)
|
||||||
|
{
|
||||||
|
switch ((int)(OpCode >> 49) & 7)
|
||||||
|
{
|
||||||
|
case 1: return ShaderIrInst.Clt;
|
||||||
|
case 2: return ShaderIrInst.Ceq;
|
||||||
|
case 3: return ShaderIrInst.Cle;
|
||||||
|
case 4: return ShaderIrInst.Cgt;
|
||||||
|
case 5: return ShaderIrInst.Cne;
|
||||||
|
case 6: return ShaderIrInst.Cge;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(nameof(OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrInst GetCmpF(long OpCode)
|
||||||
{
|
{
|
||||||
switch ((int)(OpCode >> 48) & 0xf)
|
switch ((int)(OpCode >> 48) & 0xf)
|
||||||
{
|
{
|
||||||
case 0x1: return ShaderIrInst.Clt;
|
case 0x1: return ShaderIrInst.Fclt;
|
||||||
case 0x2: return ShaderIrInst.Ceq;
|
case 0x2: return ShaderIrInst.Fceq;
|
||||||
case 0x3: return ShaderIrInst.Cle;
|
case 0x3: return ShaderIrInst.Fcle;
|
||||||
case 0x4: return ShaderIrInst.Cgt;
|
case 0x4: return ShaderIrInst.Fcgt;
|
||||||
case 0x5: return ShaderIrInst.Cne;
|
case 0x5: return ShaderIrInst.Fcne;
|
||||||
case 0x6: return ShaderIrInst.Cge;
|
case 0x6: return ShaderIrInst.Fcge;
|
||||||
case 0x7: return ShaderIrInst.Cnum;
|
case 0x7: return ShaderIrInst.Fcnum;
|
||||||
case 0x8: return ShaderIrInst.Cnan;
|
case 0x8: return ShaderIrInst.Fcnan;
|
||||||
case 0x9: return ShaderIrInst.Cltu;
|
case 0x9: return ShaderIrInst.Fcltu;
|
||||||
case 0xa: return ShaderIrInst.Cequ;
|
case 0xa: return ShaderIrInst.Fcequ;
|
||||||
case 0xb: return ShaderIrInst.Cleu;
|
case 0xb: return ShaderIrInst.Fcleu;
|
||||||
case 0xc: return ShaderIrInst.Cgtu;
|
case 0xc: return ShaderIrInst.Fcgtu;
|
||||||
case 0xd: return ShaderIrInst.Cneu;
|
case 0xd: return ShaderIrInst.Fcneu;
|
||||||
case 0xe: return ShaderIrInst.Cgeu;
|
case 0xe: return ShaderIrInst.Fcgeu;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException(nameof(OpCode));
|
throw new ArgumentException(nameof(OpCode));
|
||||||
|
@ -170,7 +185,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (Pred.Index != ShaderIrOperPred.UnusedIndex)
|
if (Pred.Index != ShaderIrOperPred.UnusedIndex)
|
||||||
{
|
{
|
||||||
Node = new ShaderIrCond(Pred, Node);
|
bool Inv = ((OpCode >> 19) & 1) != 0;
|
||||||
|
|
||||||
|
Node = new ShaderIrCond(Pred, Node, Inv);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Node;
|
return Node;
|
||||||
|
|
|
@ -36,24 +36,56 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Texq(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
ShaderIrNode OperD = GetOperGpr0(OpCode);
|
||||||
|
ShaderIrNode OperA = GetOperGpr8(OpCode);
|
||||||
|
|
||||||
|
ShaderTexqInfo Info = (ShaderTexqInfo)((OpCode >> 22) & 0x1f);
|
||||||
|
|
||||||
|
ShaderIrMetaTexq Meta0 = new ShaderIrMetaTexq(Info, 0);
|
||||||
|
ShaderIrMetaTexq Meta1 = new ShaderIrMetaTexq(Info, 1);
|
||||||
|
|
||||||
|
ShaderIrNode OperC = GetOperImm13_36(OpCode);
|
||||||
|
|
||||||
|
ShaderIrOp Op0 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta0);
|
||||||
|
ShaderIrOp Op1 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta1);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(OperD, Op0), OpCode));
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(OperA, Op1), OpCode)); //Is this right?
|
||||||
|
}
|
||||||
|
|
||||||
public static void Texs(ShaderIrBlock Block, long OpCode)
|
public static void Texs(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitTex(Block, OpCode, ShaderIrInst.Texs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Tlds(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitTex(Block, OpCode, ShaderIrInst.Txlf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitTex(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst)
|
||||||
{
|
{
|
||||||
//TODO: Support other formats.
|
//TODO: Support other formats.
|
||||||
ShaderIrNode OperA = GetOperGpr8 (OpCode);
|
ShaderIrNode OperA = GetOperGpr8 (OpCode);
|
||||||
ShaderIrNode OperB = GetOperGpr20 (OpCode);
|
ShaderIrNode OperB = GetOperGpr20 (OpCode);
|
||||||
ShaderIrNode OperC = GetOperGpr28 (OpCode);
|
ShaderIrNode OperC = GetOperImm13_36(OpCode);
|
||||||
ShaderIrNode OperD = GetOperImm13_36(OpCode);
|
|
||||||
|
|
||||||
for (int Ch = 0; Ch < 4; Ch++)
|
for (int Ch = 0; Ch < 4; Ch++)
|
||||||
{
|
{
|
||||||
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Texr + Ch, OperA, OperB, OperD);
|
ShaderIrOperGpr Dst = (Ch >> 1) != 0
|
||||||
|
? GetOperGpr28(OpCode)
|
||||||
|
: GetOperGpr0 (OpCode);
|
||||||
|
|
||||||
ShaderIrOperGpr Dst = GetOperGpr0(OpCode);
|
Dst.Index += Ch & 1;
|
||||||
|
|
||||||
Dst.Index += Ch;
|
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);
|
||||||
|
|
||||||
Block.AddNode(new ShaderIrAsg(Dst, Op));
|
ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta);
|
||||||
}
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,6 +25,36 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
F64 = 3
|
F64 = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void F2f_C(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitF2f(Block, OpCode, ShaderOper.CR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void F2f_I(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitF2f(Block, OpCode, ShaderOper.Immf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void F2f_R(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitF2f(Block, OpCode, ShaderOper.RR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void F2i_C(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitF2i(Block, OpCode, ShaderOper.CR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void F2i_I(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitF2i(Block, OpCode, ShaderOper.Immf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void F2i_R(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitF2i(Block, OpCode, ShaderOper.RR);
|
||||||
|
}
|
||||||
|
|
||||||
public static void I2f_C(ShaderIrBlock Block, long OpCode)
|
public static void I2f_C(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
EmitI2f(Block, OpCode, ShaderOper.CR);
|
EmitI2f(Block, OpCode, ShaderOper.CR);
|
||||||
|
@ -40,6 +70,131 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
EmitI2f(Block, OpCode, ShaderOper.RR);
|
EmitI2f(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Mov_C(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
ShaderIrOperCbuf Cbuf = GetOperCbuf34(OpCode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Cbuf), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Mov_I(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
ShaderIrOperImm Imm = GetOperImm19_20(OpCode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Mov_R(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
ShaderIrOperGpr Gpr = GetOperGpr20(OpCode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Gpr), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Mov32i(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
ShaderIrOperImm Imm = GetOperImm32_20(OpCode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitF2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
|
{
|
||||||
|
bool Na = ((OpCode >> 45) & 1) != 0;
|
||||||
|
bool Aa = ((OpCode >> 49) & 1) != 0;
|
||||||
|
|
||||||
|
ShaderIrNode OperA;
|
||||||
|
|
||||||
|
switch (Oper)
|
||||||
|
{
|
||||||
|
case ShaderOper.CR: OperA = GetOperCbuf34 (OpCode); break;
|
||||||
|
case ShaderOper.Immf: OperA = GetOperImmf19_20(OpCode); break;
|
||||||
|
case ShaderOper.RR: OperA = GetOperGpr20 (OpCode); break;
|
||||||
|
|
||||||
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
|
}
|
||||||
|
|
||||||
|
OperA = GetAluAbsNeg(OperA, Aa, Na);
|
||||||
|
|
||||||
|
ShaderIrInst RoundInst = GetRoundInst(OpCode);
|
||||||
|
|
||||||
|
if (RoundInst != ShaderIrInst.Invalid)
|
||||||
|
{
|
||||||
|
OperA = new ShaderIrOp(RoundInst, OperA);
|
||||||
|
}
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitF2i(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
|
{
|
||||||
|
IntType Type = GetIntType(OpCode);
|
||||||
|
|
||||||
|
if (Type == IntType.U64 ||
|
||||||
|
Type == IntType.S64)
|
||||||
|
{
|
||||||
|
//TODO: 64-bits support.
|
||||||
|
//Note: GLSL doesn't support 64-bits integers.
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Na = ((OpCode >> 45) & 1) != 0;
|
||||||
|
bool Aa = ((OpCode >> 49) & 1) != 0;
|
||||||
|
|
||||||
|
ShaderIrNode OperA;
|
||||||
|
|
||||||
|
switch (Oper)
|
||||||
|
{
|
||||||
|
case ShaderOper.CR: OperA = GetOperCbuf34 (OpCode); break;
|
||||||
|
case ShaderOper.Immf: OperA = GetOperImmf19_20(OpCode); break;
|
||||||
|
case ShaderOper.RR: OperA = GetOperGpr20 (OpCode); break;
|
||||||
|
|
||||||
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
|
}
|
||||||
|
|
||||||
|
OperA = GetAluAbsNeg(OperA, Aa, Na);
|
||||||
|
|
||||||
|
ShaderIrInst RoundInst = GetRoundInst(OpCode);
|
||||||
|
|
||||||
|
if (RoundInst != ShaderIrInst.Invalid)
|
||||||
|
{
|
||||||
|
OperA = new ShaderIrOp(RoundInst, OperA);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Signed = Type >= IntType.S8;
|
||||||
|
|
||||||
|
int Size = 8 << ((int)Type & 3);
|
||||||
|
|
||||||
|
if (Size < 32)
|
||||||
|
{
|
||||||
|
uint Mask = uint.MaxValue >> (32 - Size);
|
||||||
|
|
||||||
|
float CMin = 0;
|
||||||
|
float CMax = Mask;
|
||||||
|
|
||||||
|
if (Signed)
|
||||||
|
{
|
||||||
|
uint HalfMask = Mask >> 1;
|
||||||
|
|
||||||
|
CMin -= HalfMask + 1;
|
||||||
|
CMax = HalfMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIrOperImmf IMin = new ShaderIrOperImmf(CMin);
|
||||||
|
ShaderIrOperImmf IMax = new ShaderIrOperImmf(CMax);
|
||||||
|
|
||||||
|
OperA = new ShaderIrOp(ShaderIrInst.Clamp, OperA, IMin, IMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIrInst Inst = Signed
|
||||||
|
? ShaderIrInst.Ftos
|
||||||
|
: ShaderIrInst.Ftou;
|
||||||
|
|
||||||
|
ShaderIrNode Op = new ShaderIrOp(Inst, OperA);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitI2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitI2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
IntType Type = GetIntType(OpCode);
|
IntType Type = GetIntType(OpCode);
|
||||||
|
@ -76,18 +231,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
int Size = 8 << ((int)Type & 3);
|
int Size = 8 << ((int)Type & 3);
|
||||||
|
|
||||||
ulong Mask = ulong.MaxValue >> (64 - Size);
|
|
||||||
|
|
||||||
int Mask32 = (int)Mask;
|
|
||||||
|
|
||||||
if (Shift != 0)
|
if (Shift != 0)
|
||||||
{
|
{
|
||||||
OperA = new ShaderIrOp(ShaderIrInst.Asr, OperA, new ShaderIrOperImm(Shift));
|
OperA = new ShaderIrOp(ShaderIrInst.Asr, OperA, new ShaderIrOperImm(Shift));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Mask != uint.MaxValue)
|
if (Size < 32)
|
||||||
{
|
{
|
||||||
OperA = new ShaderIrOp(ShaderIrInst.And, OperA, new ShaderIrOperImm(Mask32));
|
uint Mask = uint.MaxValue >> (32 - Size);
|
||||||
|
|
||||||
|
OperA = new ShaderIrOp(ShaderIrInst.And, OperA, new ShaderIrOperImm((int)Mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrInst Inst = Signed
|
ShaderIrInst Inst = Signed
|
||||||
|
@ -99,13 +252,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Mov32i(ShaderIrBlock Block, long OpCode)
|
|
||||||
{
|
|
||||||
ShaderIrOperImm Imm = GetOperImm32_20(OpCode);
|
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IntType GetIntType(long OpCode)
|
private static IntType GetIntType(long OpCode)
|
||||||
{
|
{
|
||||||
bool Signed = ((OpCode >> 13) & 1) != 0;
|
bool Signed = ((OpCode >> 13) & 1) != 0;
|
||||||
|
@ -124,5 +270,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
return (FloatType)((OpCode >> 8) & 3);
|
return (FloatType)((OpCode >> 8) & 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ShaderIrInst GetRoundInst(long OpCode)
|
||||||
|
{
|
||||||
|
switch ((OpCode >> 39) & 3)
|
||||||
|
{
|
||||||
|
case 1: return ShaderIrInst.Floor;
|
||||||
|
case 2: return ShaderIrInst.Ceil;
|
||||||
|
case 3: return ShaderIrInst.Trunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ShaderIrInst.Invalid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,6 +8,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
while (Offset + 2 <= Code.Length)
|
while (Offset + 2 <= Code.Length)
|
||||||
{
|
{
|
||||||
|
//Ignore scheduling instructions, which are
|
||||||
|
//written every 32 bytes.
|
||||||
|
if ((Offset & 7) == 0)
|
||||||
|
{
|
||||||
|
Offset += 2;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
uint Word0 = (uint)Code[Offset++];
|
uint Word0 = (uint)Code[Offset++];
|
||||||
uint Word1 = (uint)Code[Offset++];
|
uint Word1 = (uint)Code[Offset++];
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
public ShaderIrNode Pred { get; set; }
|
public ShaderIrNode Pred { get; set; }
|
||||||
public ShaderIrNode Child { get; set; }
|
public ShaderIrNode Child { get; set; }
|
||||||
|
|
||||||
public ShaderIrCond(ShaderIrNode Pred, ShaderIrNode Child)
|
public bool Not { get; private set; }
|
||||||
|
|
||||||
|
public ShaderIrCond(ShaderIrNode Pred, ShaderIrNode Child, bool Not)
|
||||||
{
|
{
|
||||||
this.Pred = Pred;
|
this.Pred = Pred;
|
||||||
this.Child = Child;
|
this.Child = Child;
|
||||||
|
this.Not = Not;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,53 +2,66 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
enum ShaderIrInst
|
enum ShaderIrInst
|
||||||
{
|
{
|
||||||
|
Invalid,
|
||||||
|
|
||||||
B_Start,
|
B_Start,
|
||||||
Band,
|
Band,
|
||||||
Bnot,
|
Bnot,
|
||||||
Bor,
|
Bor,
|
||||||
Bxor,
|
Bxor,
|
||||||
Clt,
|
|
||||||
Ceq,
|
|
||||||
Cle,
|
|
||||||
Cgt,
|
|
||||||
Cne,
|
|
||||||
Cge,
|
|
||||||
Cnum,
|
|
||||||
Cnan,
|
|
||||||
Cltu,
|
|
||||||
Cequ,
|
|
||||||
Cleu,
|
|
||||||
Cgtu,
|
|
||||||
Cneu,
|
|
||||||
Cgeu,
|
|
||||||
B_End,
|
B_End,
|
||||||
|
|
||||||
F_Start,
|
F_Start,
|
||||||
|
Ceil,
|
||||||
|
Clamp,
|
||||||
Fabs,
|
Fabs,
|
||||||
Fadd,
|
Fadd,
|
||||||
|
Fceq,
|
||||||
|
Fcequ,
|
||||||
|
Fcge,
|
||||||
|
Fcgeu,
|
||||||
|
Fcgt,
|
||||||
|
Fcgtu,
|
||||||
|
Fcle,
|
||||||
|
Fcleu,
|
||||||
|
Fclt,
|
||||||
|
Fcltu,
|
||||||
|
Fcnan,
|
||||||
|
Fcne,
|
||||||
|
Fcneu,
|
||||||
|
Fcnum,
|
||||||
Fcos,
|
Fcos,
|
||||||
Fex2,
|
Fex2,
|
||||||
Ffma,
|
Ffma,
|
||||||
Flg2,
|
Flg2,
|
||||||
|
Floor,
|
||||||
Fmul,
|
Fmul,
|
||||||
Fneg,
|
Fneg,
|
||||||
Frcp,
|
Frcp,
|
||||||
Frsq,
|
Frsq,
|
||||||
Fsin,
|
Fsin,
|
||||||
|
Ftos,
|
||||||
|
Ftou,
|
||||||
Ipa,
|
Ipa,
|
||||||
Texr,
|
Texs,
|
||||||
Texg,
|
Trunc,
|
||||||
Texb,
|
|
||||||
Texa,
|
|
||||||
F_End,
|
F_End,
|
||||||
|
|
||||||
I_Start,
|
I_Start,
|
||||||
And,
|
And,
|
||||||
Asr,
|
Asr,
|
||||||
|
Ceq,
|
||||||
|
Cge,
|
||||||
|
Cgt,
|
||||||
|
Cle,
|
||||||
|
Clt,
|
||||||
|
Cne,
|
||||||
Lsr,
|
Lsr,
|
||||||
Not,
|
Not,
|
||||||
Or,
|
Or,
|
||||||
Stof,
|
Stof,
|
||||||
|
Texq,
|
||||||
|
Txlf,
|
||||||
Utof,
|
Utof,
|
||||||
Xor,
|
Xor,
|
||||||
I_End,
|
I_End,
|
||||||
|
|
4
Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs
Normal file
4
Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
class ShaderIrMeta { }
|
||||||
|
}
|
12
Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs
Normal file
12
Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
class ShaderIrMetaTex : ShaderIrMeta
|
||||||
|
{
|
||||||
|
public int Elem { get; private set; }
|
||||||
|
|
||||||
|
public ShaderIrMetaTex(int Elem)
|
||||||
|
{
|
||||||
|
this.Elem = Elem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs
Normal file
15
Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
class ShaderIrMetaTexq : ShaderIrMeta
|
||||||
|
{
|
||||||
|
public ShaderTexqInfo Info { get; private set; }
|
||||||
|
|
||||||
|
public int Elem { get; private set; }
|
||||||
|
|
||||||
|
public ShaderIrMetaTexq(ShaderTexqInfo Info, int Elem)
|
||||||
|
{
|
||||||
|
this.Info = Info;
|
||||||
|
this.Elem = Elem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,17 +6,20 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
public ShaderIrNode OperandA { get; set; }
|
public ShaderIrNode OperandA { get; set; }
|
||||||
public ShaderIrNode OperandB { get; set; }
|
public ShaderIrNode OperandB { get; set; }
|
||||||
public ShaderIrNode OperandC { get; set; }
|
public ShaderIrNode OperandC { get; set; }
|
||||||
|
public ShaderIrMeta MetaData { get; set; }
|
||||||
|
|
||||||
public ShaderIrOp(
|
public ShaderIrOp(
|
||||||
ShaderIrInst Inst,
|
ShaderIrInst Inst,
|
||||||
ShaderIrNode OperandA = null,
|
ShaderIrNode OperandA = null,
|
||||||
ShaderIrNode OperandB = null,
|
ShaderIrNode OperandB = null,
|
||||||
ShaderIrNode OperandC = null)
|
ShaderIrNode OperandC = null,
|
||||||
|
ShaderIrMeta MetaData = null)
|
||||||
{
|
{
|
||||||
this.Inst = Inst;
|
this.Inst = Inst;
|
||||||
this.OperandA = OperandA;
|
this.OperandA = OperandA;
|
||||||
this.OperandB = OperandB;
|
this.OperandB = OperandB;
|
||||||
this.OperandC = OperandC;
|
this.OperandC = OperandC;
|
||||||
|
this.MetaData = MetaData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,6 +14,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
#region Instructions
|
#region Instructions
|
||||||
Set("111000110000xx", ShaderDecode.Exit);
|
Set("111000110000xx", ShaderDecode.Exit);
|
||||||
|
Set("0100110010101x", ShaderDecode.F2f_C);
|
||||||
|
Set("0011100x10101x", ShaderDecode.F2f_I);
|
||||||
|
Set("0101110010101x", ShaderDecode.F2f_R);
|
||||||
|
Set("0100110010110x", ShaderDecode.F2i_C);
|
||||||
|
Set("0011100x10110x", ShaderDecode.F2i_I);
|
||||||
|
Set("0101110010110x", ShaderDecode.F2i_R);
|
||||||
Set("0100110001011x", ShaderDecode.Fadd_C);
|
Set("0100110001011x", ShaderDecode.Fadd_C);
|
||||||
Set("0011100x01011x", ShaderDecode.Fadd_I);
|
Set("0011100x01011x", ShaderDecode.Fadd_I);
|
||||||
Set("0101110001011x", ShaderDecode.Fadd_R);
|
Set("0101110001011x", ShaderDecode.Fadd_R);
|
||||||
|
@ -31,16 +37,24 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Set("0011100x10111x", ShaderDecode.I2f_I);
|
Set("0011100x10111x", ShaderDecode.I2f_I);
|
||||||
Set("0101110010111x", ShaderDecode.I2f_R);
|
Set("0101110010111x", ShaderDecode.I2f_R);
|
||||||
Set("11100000xxxxxx", ShaderDecode.Ipa);
|
Set("11100000xxxxxx", ShaderDecode.Ipa);
|
||||||
|
Set("010010110110xx", ShaderDecode.Isetp_C);
|
||||||
|
Set("0011011x0110xx", ShaderDecode.Isetp_I);
|
||||||
|
Set("010110110110xx", ShaderDecode.Isetp_R);
|
||||||
Set("111000110011xx", ShaderDecode.Kil);
|
Set("111000110011xx", ShaderDecode.Kil);
|
||||||
Set("1110111111011x", ShaderDecode.Ld_A);
|
Set("1110111111011x", ShaderDecode.Ld_A);
|
||||||
Set("000001xxxxxxxx", ShaderDecode.Lop32i);
|
Set("000001xxxxxxxx", ShaderDecode.Lop32i);
|
||||||
|
Set("0100110010011x", ShaderDecode.Mov_C);
|
||||||
|
Set("0011100x10011x", ShaderDecode.Mov_I);
|
||||||
|
Set("0101110010011x", ShaderDecode.Mov_R);
|
||||||
Set("000000010000xx", ShaderDecode.Mov32i);
|
Set("000000010000xx", ShaderDecode.Mov32i);
|
||||||
Set("0101000010000x", ShaderDecode.Mufu);
|
Set("0101000010000x", ShaderDecode.Mufu);
|
||||||
Set("0100110000101x", ShaderDecode.Shr_C);
|
Set("0100110000101x", ShaderDecode.Shr_C);
|
||||||
Set("0011100x00101x", ShaderDecode.Shr_I);
|
Set("0011100x00101x", ShaderDecode.Shr_I);
|
||||||
Set("0101110000101x", ShaderDecode.Shr_R);
|
Set("0101110000101x", ShaderDecode.Shr_R);
|
||||||
Set("1110111111110x", ShaderDecode.St_A);
|
Set("1110111111110x", ShaderDecode.St_A);
|
||||||
|
Set("1101111101001x", ShaderDecode.Texq);
|
||||||
Set("1101100xxxxxxx", ShaderDecode.Texs);
|
Set("1101100xxxxxxx", ShaderDecode.Texs);
|
||||||
|
Set("1101101xxxxxxx", ShaderDecode.Tlds);
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
enum ShaderOper
|
enum ShaderOper
|
||||||
{
|
{
|
||||||
CR,
|
CR,
|
||||||
RC,
|
|
||||||
RR,
|
|
||||||
Imm,
|
Imm,
|
||||||
Immf
|
Immf,
|
||||||
|
RC,
|
||||||
|
RR
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,13 +7,22 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
private struct UseSite
|
private struct UseSite
|
||||||
{
|
{
|
||||||
public object Parent;
|
public ShaderIrNode Parent { get; private set; }
|
||||||
|
public ShaderIrCond Cond { get; private set; }
|
||||||
|
|
||||||
public int OperIndex;
|
public int UseIndex { get; private set; }
|
||||||
|
|
||||||
public UseSite(object Parent, int OperIndex)
|
public int OperIndex { get; private set; }
|
||||||
|
|
||||||
|
public UseSite(
|
||||||
|
ShaderIrNode Parent,
|
||||||
|
ShaderIrCond Cond,
|
||||||
|
int UseIndex,
|
||||||
|
int OperIndex)
|
||||||
{
|
{
|
||||||
this.Parent = Parent;
|
this.Parent = Parent;
|
||||||
|
this.Cond = Cond;
|
||||||
|
this.UseIndex = UseIndex;
|
||||||
this.OperIndex = OperIndex;
|
this.OperIndex = OperIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +33,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public int AsgIndex { get; private set; }
|
public int AsgIndex { get; private set; }
|
||||||
|
|
||||||
private bool Propagate;
|
public int LastSiteIndex { get; private set; }
|
||||||
|
|
||||||
|
public ShaderIrCond Cond { get; private set; }
|
||||||
|
|
||||||
private List<UseSite> Sites;
|
private List<UseSite> Sites;
|
||||||
|
|
||||||
|
@ -35,6 +46,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public void AddUseSite(UseSite Site)
|
public void AddUseSite(UseSite Site)
|
||||||
{
|
{
|
||||||
|
if (LastSiteIndex < Site.UseIndex)
|
||||||
|
{
|
||||||
|
LastSiteIndex = Site.UseIndex;
|
||||||
|
}
|
||||||
|
|
||||||
Sites.Add(Site);
|
Sites.Add(Site);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,14 +58,27 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
//This happens when a untiliazied register is used,
|
//This happens when a untiliazied register is used,
|
||||||
//this usually indicates a decoding error, but may also
|
//this usually indicates a decoding error, but may also
|
||||||
//be cased by bogus programs (?). In any case, we just
|
//be caused by bogus programs (?). In any case, we just
|
||||||
//keep the unitialized access and avoid trying to propagate
|
//keep the unitialized access and avoid trying to propagate
|
||||||
//the expression (since we can't propagate what doesn't yet exist).
|
//the expression (since we can't propagate what doesn't yet exist).
|
||||||
if (Asg == null || !Propagate)
|
if (Asg == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Cond != null)
|
||||||
|
{
|
||||||
|
//If the assignment is conditional, we can only propagate
|
||||||
|
//to the use sites that shares the same condition of the assignment.
|
||||||
|
foreach (UseSite Site in Sites)
|
||||||
|
{
|
||||||
|
if (!IsSameCondition(Cond, Site.Cond))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Sites.Count > 0)
|
if (Sites.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (UseSite Site in Sites)
|
foreach (UseSite Site in Sites)
|
||||||
|
@ -89,11 +118,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetNewAsg(ShaderIrAsg Asg, int AsgIndex, bool Propagate)
|
public void SetNewAsg(ShaderIrAsg Asg, int AsgIndex, ShaderIrCond Cond)
|
||||||
{
|
{
|
||||||
this.Asg = Asg;
|
this.Asg = Asg;
|
||||||
this.AsgIndex = AsgIndex;
|
this.AsgIndex = AsgIndex;
|
||||||
this.Propagate = Propagate;
|
this.Cond = Cond;
|
||||||
|
|
||||||
|
LastSiteIndex = 0;
|
||||||
|
|
||||||
Sites.Clear();
|
Sites.Clear();
|
||||||
}
|
}
|
||||||
|
@ -137,38 +168,52 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return GetUse(GetPredKey(PredIndex));
|
return GetUse(GetPredKey(PredIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FindRegUses(List<(int, UseSite)> UseList, object Parent, ShaderIrNode Node, int OperIndex = 0)
|
void RemoveUse(RegUse Use)
|
||||||
{
|
{
|
||||||
if (Node is ShaderIrAsg Asg)
|
if (!Nodes.Remove((ShaderIrNode)Use.Cond ?? Use.Asg))
|
||||||
{
|
{
|
||||||
FindRegUses(UseList, Asg, Asg.Src);
|
throw new InvalidOperationException();
|
||||||
}
|
|
||||||
else if (Node is ShaderIrCond Cond)
|
|
||||||
{
|
|
||||||
FindRegUses(UseList, Cond, Cond.Pred, 0);
|
|
||||||
FindRegUses(UseList, Cond, Cond.Child, 1);
|
|
||||||
}
|
|
||||||
else if (Node is ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
FindRegUses(UseList, Op, Op.OperandA, 0);
|
|
||||||
FindRegUses(UseList, Op, Op.OperandB, 1);
|
|
||||||
FindRegUses(UseList, Op, Op.OperandC, 2);
|
|
||||||
}
|
|
||||||
else if (Node is ShaderIrOperGpr Gpr && Gpr.Index != ShaderIrOperGpr.ZRIndex)
|
|
||||||
{
|
|
||||||
UseList.Add((GetGprKey(Gpr.Index), new UseSite(Parent, OperIndex)));
|
|
||||||
}
|
|
||||||
else if (Node is ShaderIrOperPred Pred)
|
|
||||||
{
|
|
||||||
UseList.Add((GetPredKey(Pred.Index), new UseSite(Parent, OperIndex)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TryAddRegUseSite(ShaderIrNode Node)
|
void FindRegUses(
|
||||||
|
List<(int, UseSite)> UseList,
|
||||||
|
ShaderIrNode Parent,
|
||||||
|
ShaderIrNode Node,
|
||||||
|
ShaderIrCond CondNode,
|
||||||
|
int UseIndex,
|
||||||
|
int OperIndex = 0)
|
||||||
|
{
|
||||||
|
if (Node is ShaderIrAsg Asg)
|
||||||
|
{
|
||||||
|
FindRegUses(UseList, Asg, Asg.Src, CondNode, UseIndex);
|
||||||
|
}
|
||||||
|
else if (Node is ShaderIrCond Cond)
|
||||||
|
{
|
||||||
|
FindRegUses(UseList, Cond, Cond.Pred, CondNode, UseIndex, 0);
|
||||||
|
FindRegUses(UseList, Cond, Cond.Child, CondNode, UseIndex, 1);
|
||||||
|
}
|
||||||
|
else if (Node is ShaderIrOp Op)
|
||||||
|
{
|
||||||
|
FindRegUses(UseList, Op, Op.OperandA, CondNode, UseIndex, 0);
|
||||||
|
FindRegUses(UseList, Op, Op.OperandB, CondNode, UseIndex, 1);
|
||||||
|
FindRegUses(UseList, Op, Op.OperandC, CondNode, UseIndex, 2);
|
||||||
|
}
|
||||||
|
else if (Node is ShaderIrOperGpr Gpr && !Gpr.IsConst)
|
||||||
|
{
|
||||||
|
UseList.Add((GetGprKey(Gpr.Index), new UseSite(Parent, CondNode, UseIndex, OperIndex)));
|
||||||
|
}
|
||||||
|
else if (Node is ShaderIrOperPred Pred)
|
||||||
|
{
|
||||||
|
UseList.Add((GetPredKey(Pred.Index), new UseSite(Parent, CondNode, UseIndex, OperIndex)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TryAddRegUseSite(ShaderIrNode Node, ShaderIrCond CondNode, int UseIndex)
|
||||||
{
|
{
|
||||||
List<(int, UseSite)> UseList = new List<(int, UseSite)>();
|
List<(int, UseSite)> UseList = new List<(int, UseSite)>();
|
||||||
|
|
||||||
FindRegUses(UseList, null, Node);
|
FindRegUses(UseList, null, Node, CondNode, UseIndex);
|
||||||
|
|
||||||
foreach ((int Key, UseSite Site) in UseList)
|
foreach ((int Key, UseSite Site) in UseList)
|
||||||
{
|
{
|
||||||
|
@ -190,10 +235,22 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
List<(int, UseSite)> UseList = new List<(int, UseSite)>();
|
List<(int, UseSite)> UseList = new List<(int, UseSite)>();
|
||||||
|
|
||||||
FindRegUses(UseList, Use.Asg, Use.Asg.Src);
|
if (Use.Cond != null)
|
||||||
|
{
|
||||||
|
FindRegUses(UseList, null, Use.Cond, null, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FindRegUses(UseList, Use.Asg, Use.Asg.Src, null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ((int Key, UseSite Site) in UseList)
|
foreach ((int Key, UseSite Site) in UseList)
|
||||||
{
|
{
|
||||||
|
//TODO: Build an assignment list inside RegUse,
|
||||||
|
//and check if there is an assignment inside the
|
||||||
|
//range of Use.AsgIndex and Use.LastSiteIndex,
|
||||||
|
//and if that's the case, then we should return false.
|
||||||
|
//The current method is too conservative.
|
||||||
if (GetUse(Key).AsgIndex >= Use.AsgIndex)
|
if (GetUse(Key).AsgIndex >= Use.AsgIndex)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -203,13 +260,18 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return Use.TryPropagate();
|
return Use.TryPropagate();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int Index = 0, AsgIndex = 0; Index < Nodes.Count; Index++, AsgIndex++)
|
for (int Index = 0, IterCount = 0; Index < Nodes.Count; Index++, IterCount++)
|
||||||
{
|
{
|
||||||
ShaderIrNode Node = Nodes[Index];
|
ShaderIrNode Node = Nodes[Index];
|
||||||
|
|
||||||
bool IsConditional = Node is ShaderIrCond;
|
ShaderIrCond CondNode = null;
|
||||||
|
|
||||||
TryAddRegUseSite(Node);
|
if (Node is ShaderIrCond)
|
||||||
|
{
|
||||||
|
CondNode = (ShaderIrCond)Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
TryAddRegUseSite(Node, CondNode, IterCount);;
|
||||||
|
|
||||||
while (Node is ShaderIrCond Cond)
|
while (Node is ShaderIrCond Cond)
|
||||||
{
|
{
|
||||||
|
@ -223,7 +285,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
RegUse Use = null;
|
RegUse Use = null;
|
||||||
|
|
||||||
if (Asg.Dst is ShaderIrOperGpr Gpr && Gpr.Index != ShaderIrOperGpr.ZRIndex)
|
if (Asg.Dst is ShaderIrOperGpr Gpr && !Gpr.IsConst)
|
||||||
{
|
{
|
||||||
Use = GetGprUse(Gpr.Index);
|
Use = GetGprUse(Gpr.Index);
|
||||||
}
|
}
|
||||||
|
@ -232,16 +294,22 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Use = GetPredUse(Pred.Index);
|
Use = GetPredUse(Pred.Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsConditional && TryPropagate(Use))
|
bool CanRemoveAsg = CondNode == null;
|
||||||
{
|
|
||||||
Nodes.Remove(Use.Asg);
|
|
||||||
|
|
||||||
|
CanRemoveAsg |= IsSameCondition(CondNode, Use?.Cond);
|
||||||
|
|
||||||
|
if (CanRemoveAsg && TryPropagate(Use))
|
||||||
|
{
|
||||||
|
RemoveUse(Use);
|
||||||
|
|
||||||
|
//Note: Only decrement if the removal was successful.
|
||||||
|
//RemoveUse throws when this is not the case so we should be good.
|
||||||
Index--;
|
Index--;
|
||||||
}
|
}
|
||||||
|
|
||||||
//All nodes inside conditional nodes can't be propagated,
|
//All nodes inside conditional nodes can't be propagated,
|
||||||
//as we don't even know if they will be executed to begin with.
|
//as we don't even know if they will be executed to begin with.
|
||||||
Use?.SetNewAsg(Asg, AsgIndex, !IsConditional);
|
Use?.SetNewAsg(Asg, IterCount, CondNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (RegUse Use in Uses.Values)
|
foreach (RegUse Use in Uses.Values)
|
||||||
|
@ -258,9 +326,41 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (TryPropagate(Use))
|
if (TryPropagate(Use))
|
||||||
{
|
{
|
||||||
Nodes.Remove(Use.Asg);
|
RemoveUse(Use);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsSameCondition(ShaderIrCond CondA, ShaderIrCond CondB)
|
||||||
|
{
|
||||||
|
if (CondA == null || CondB == null)
|
||||||
|
{
|
||||||
|
return CondA == CondB;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CondA.Not != CondB.Not)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CondA.Pred is ShaderIrOperPred PredA)
|
||||||
|
{
|
||||||
|
if (!(CondB.Pred is ShaderIrOperPred PredB))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PredA.Index != PredB.Index)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (CondA.Pred != CondB.Pred)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
13
Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs
Normal file
13
Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
enum ShaderTexqInfo
|
||||||
|
{
|
||||||
|
Dimension = 1,
|
||||||
|
TextureType = 2,
|
||||||
|
SamplePos = 5,
|
||||||
|
Filter = 16,
|
||||||
|
Lod = 18,
|
||||||
|
Wrap = 20,
|
||||||
|
BorderColor = 22
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
case GalTextureFormat.A8B8G8R8: return Read4Bpp (Memory, Texture);
|
case GalTextureFormat.A8B8G8R8: return Read4Bpp (Memory, Texture);
|
||||||
case GalTextureFormat.A1B5G5R5: return Read2Bpp (Memory, Texture);
|
case GalTextureFormat.A1B5G5R5: return Read2Bpp (Memory, Texture);
|
||||||
|
case GalTextureFormat.B5G6R5: return Read2Bpp (Memory, Texture);
|
||||||
case GalTextureFormat.BC1: return Read8Bpt4x4 (Memory, Texture);
|
case GalTextureFormat.BC1: return Read8Bpt4x4 (Memory, Texture);
|
||||||
case GalTextureFormat.BC2: return Read16Bpt4x4(Memory, Texture);
|
case GalTextureFormat.BC2: return Read16Bpt4x4(Memory, Texture);
|
||||||
case GalTextureFormat.BC3: return Read16Bpt4x4(Memory, Texture);
|
case GalTextureFormat.BC3: return Read16Bpt4x4(Memory, Texture);
|
||||||
|
@ -20,35 +21,6 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
throw new NotImplementedException(Texture.Format.ToString());
|
throw new NotImplementedException(Texture.Format.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe static byte[] Read4Bpp(AMemory Memory, Texture Texture)
|
|
||||||
{
|
|
||||||
int Width = Texture.Width;
|
|
||||||
int Height = Texture.Height;
|
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height * 4];
|
|
||||||
|
|
||||||
ISwizzle Swizzle = GetSwizzle(Texture, 4);
|
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
|
||||||
{
|
|
||||||
long OutOffs = 0;
|
|
||||||
|
|
||||||
for (int Y = 0; Y < Height; Y++)
|
|
||||||
for (int X = 0; X < Width; X++)
|
|
||||||
{
|
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
|
||||||
|
|
||||||
int Pixel = Memory.ReadInt32Unchecked(Texture.Position + Offset);
|
|
||||||
|
|
||||||
*(int*)(BuffPtr + OutOffs) = Pixel;
|
|
||||||
|
|
||||||
OutOffs += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Output;
|
|
||||||
}
|
|
||||||
|
|
||||||
private unsafe static byte[] Read2Bpp(AMemory Memory, Texture Texture)
|
private unsafe static byte[] Read2Bpp(AMemory Memory, Texture Texture)
|
||||||
{
|
{
|
||||||
int Width = Texture.Width;
|
int Width = Texture.Width;
|
||||||
|
@ -56,7 +28,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height * 2];
|
byte[] Output = new byte[Width * Height * 2];
|
||||||
|
|
||||||
ISwizzle Swizzle = GetSwizzle(Texture, 2);
|
ISwizzle Swizzle = GetSwizzle(Texture, Width, 2);
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
fixed (byte* BuffPtr = Output)
|
||||||
{
|
{
|
||||||
|
@ -78,6 +50,35 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
return Output;
|
return Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private unsafe static byte[] Read4Bpp(AMemory Memory, Texture Texture)
|
||||||
|
{
|
||||||
|
int Width = Texture.Width;
|
||||||
|
int Height = Texture.Height;
|
||||||
|
|
||||||
|
byte[] Output = new byte[Width * Height * 4];
|
||||||
|
|
||||||
|
ISwizzle Swizzle = GetSwizzle(Texture, Width, 4);
|
||||||
|
|
||||||
|
fixed (byte* BuffPtr = Output)
|
||||||
|
{
|
||||||
|
long OutOffs = 0;
|
||||||
|
|
||||||
|
for (int Y = 0; Y < Height; Y++)
|
||||||
|
for (int X = 0; X < Width; X++)
|
||||||
|
{
|
||||||
|
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||||
|
|
||||||
|
int Pixel = Memory.ReadInt32Unchecked(Texture.Position + Offset);
|
||||||
|
|
||||||
|
*(int*)(BuffPtr + OutOffs) = Pixel;
|
||||||
|
|
||||||
|
OutOffs += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Output;
|
||||||
|
}
|
||||||
|
|
||||||
private unsafe static byte[] Read8Bpt4x4(AMemory Memory, Texture Texture)
|
private unsafe static byte[] Read8Bpt4x4(AMemory Memory, Texture Texture)
|
||||||
{
|
{
|
||||||
int Width = (Texture.Width + 3) / 4;
|
int Width = (Texture.Width + 3) / 4;
|
||||||
|
@ -85,7 +86,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height * 8];
|
byte[] Output = new byte[Width * Height * 8];
|
||||||
|
|
||||||
ISwizzle Swizzle = GetSwizzle(Texture, 8);
|
ISwizzle Swizzle = GetSwizzle(Texture, Width, 8);
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
fixed (byte* BuffPtr = Output)
|
||||||
{
|
{
|
||||||
|
@ -114,7 +115,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
byte[] Output = new byte[Width * Height * 16];
|
byte[] Output = new byte[Width * Height * 16];
|
||||||
|
|
||||||
ISwizzle Swizzle = GetSwizzle(Texture, 16);
|
ISwizzle Swizzle = GetSwizzle(Texture, Width, 16);
|
||||||
|
|
||||||
fixed (byte* BuffPtr = Output)
|
fixed (byte* BuffPtr = Output)
|
||||||
{
|
{
|
||||||
|
@ -138,7 +139,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
return Output;
|
return Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ISwizzle GetSwizzle(Texture Texture, int Bpp)
|
private static ISwizzle GetSwizzle(Texture Texture, int Width, int Bpp)
|
||||||
{
|
{
|
||||||
switch (Texture.Swizzle)
|
switch (Texture.Swizzle)
|
||||||
{
|
{
|
||||||
|
@ -148,7 +149,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
case TextureSwizzle.BlockLinear:
|
case TextureSwizzle.BlockLinear:
|
||||||
case TextureSwizzle.BlockLinearColorKey:
|
case TextureSwizzle.BlockLinearColorKey:
|
||||||
return new BlockLinearSwizzle(Texture.Width, Bpp, Texture.BlockHeight);
|
return new BlockLinearSwizzle(Width, Bpp, Texture.BlockHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(Texture.Swizzle.ToString());
|
throw new NotImplementedException(Texture.Swizzle.ToString());
|
||||||
|
|
Reference in a new issue