aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-04-10 16:50:32 -0300
committergdkchan <gab.dark.100@gmail.com>2018-04-10 16:50:32 -0300
commitfeb2680a6ce1512c08980ee55c1c8215b8b5c3e4 (patch)
treeb41d2c8558ece834b2c1c5c9afba0afe226e0553
parente9cfdef0982824b673c60b362524408a263946df (diff)
[GPU] Add more shader instructions, add support for rgb565 textures
-rw-r--r--Ryujinx.Graphics/Gal/GalTextureFormat.cs1
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs12
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs47
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs2
-rw-r--r--Ryujinx.Graphics/Gal/Shader/GlslDecl.cs12
-rw-r--r--Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs249
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs44
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs71
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs50
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs184
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs9
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs5
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs49
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs4
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs12
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs15
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs5
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs14
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderOper.cs6
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderOptExprProp.cs162
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs13
-rw-r--r--Ryujinx.Graphics/Gpu/TextureReader.cs33
22 files changed, 789 insertions, 210 deletions
diff --git a/Ryujinx.Graphics/Gal/GalTextureFormat.cs b/Ryujinx.Graphics/Gal/GalTextureFormat.cs
index 5b642961..8c2c718a 100644
--- a/Ryujinx.Graphics/Gal/GalTextureFormat.cs
+++ b/Ryujinx.Graphics/Gal/GalTextureFormat.cs
@@ -4,6 +4,7 @@ namespace Ryujinx.Graphics.Gal
{
A8B8G8R8 = 0x8,
A1B5G5R5 = 0x14,
+ B5G6R5 = 0x15,
BC1 = 0x24,
BC2 = 0x25,
BC3 = 0x26
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
index 6518de5f..03c3ef52 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
@@ -55,6 +55,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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)
{
switch (Format)
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
index 559e0eda..681e6d67 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
@@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Textures = new int[80];
}
- public void Set(int Index, GalTexture Tex)
+ public void Set(int Index, GalTexture Texture)
{
GL.ActiveTexture(TextureUnit.Texture0 + Index);
@@ -19,29 +19,38 @@ namespace Ryujinx.Graphics.Gal.OpenGL
GL.BindTexture(TextureTarget.Texture2D, Handle);
- int W = Tex.Width;
- int H = Tex.Height;
+ const int Border = 0;
- byte[] Data = Tex.Data;
-
- int Length = Data.Length;
-
- if (IsCompressedTextureFormat(Tex.Format))
+ if (IsCompressedTextureFormat(Texture.Format))
{
- PixelInternalFormat Pif = OGLEnumConverter.GetCompressedTextureFormat(Tex.Format);
-
- GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Length, Data);
+ PixelInternalFormat InternalFmt = OGLEnumConverter.GetCompressedTextureFormat(Texture.Format);
+
+ GL.CompressedTexImage2D(
+ TextureTarget.Texture2D,
+ 0,
+ InternalFmt,
+ Texture.Width,
+ Texture.Height,
+ Border,
+ Texture.Data.Length,
+ Texture.Data);
}
else
{
- //TODO: Get those from Texture format.
- const PixelInternalFormat Pif = PixelInternalFormat.Rgba;
-
- const PixelFormat Pf = PixelFormat.Rgba;
-
- const PixelType Pt = PixelType.UnsignedByte;
-
- GL.TexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Pf, Pt, Data);
+ const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
+
+ (PixelFormat, PixelType) Format = OGLEnumConverter.GetTextureFormat(Texture.Format);
+
+ GL.TexImage2D(
+ TextureTarget.Texture2D,
+ 0,
+ InternalFmt,
+ Texture.Width,
+ Texture.Height,
+ Border,
+ Format.Item1,
+ Format.Item2,
+ Texture.Data);
}
}
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
index 0b7bf92a..8d8e6425 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
@@ -63,7 +63,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public void Render()
{
- FbRenderer.Render();
+ //FbRenderer.Render();
}
public void SetWindowSize(int Width, int Height)
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
index 898b90b5..cd901747 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
@@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.Gal.Shader
private const int AttrStartIndex = 8;
private const int TexStartIndex = 8;
+ public const string PositionOutAttrName = "position";
+
private const string InAttrName = "in_attr";
private const string OutAttrName = "out_attr";
private const string UniformName = "c";
@@ -62,10 +64,11 @@ namespace Ryujinx.Graphics.Gal.Shader
m_Gprs = new Dictionary<int, ShaderDeclInfo>();
m_Preds = new Dictionary<int, ShaderDeclInfo>();
- //FIXME: Only valid for vertex shaders.
if (ShaderType == GalShaderType.Fragment)
{
m_Gprs.Add(0, new ShaderDeclInfo(FragmentOutputName, 0, 0, 4));
+
+ m_InAttributes.Add(7, new ShaderDeclInfo(PositionOutAttrName, -1, 0, 4));
}
else
{
@@ -104,10 +107,9 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
+ if (Op.Inst == ShaderIrInst.Texq ||
+ Op.Inst == ShaderIrInst.Texs ||
+ Op.Inst == ShaderIrInst.Txlf)
{
int Handle = ((ShaderIrOperImm)Op.OperandC).Value;
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
index eda70cef..e155e475 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
@@ -31,40 +31,51 @@ namespace Ryujinx.Graphics.Gal.Shader
{
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
{
- { ShaderIrInst.And, GetAndExpr },
- { ShaderIrInst.Asr, GetAsrExpr },
- { ShaderIrInst.Band, GetBandExpr },
- { ShaderIrInst.Bnot, GetBnotExpr },
- { ShaderIrInst.Clt, GetCltExpr },
- { ShaderIrInst.Ceq, GetCeqExpr },
- { ShaderIrInst.Cle, GetCleExpr },
- { ShaderIrInst.Cgt, GetCgtExpr },
- { ShaderIrInst.Cne, GetCneExpr },
- { ShaderIrInst.Cge, GetCgeExpr },
- { ShaderIrInst.Exit, GetExitExpr },
- { ShaderIrInst.Fabs, GetFabsExpr },
- { ShaderIrInst.Fadd, GetFaddExpr },
- { ShaderIrInst.Fcos, GetFcosExpr },
- { ShaderIrInst.Fex2, GetFex2Expr },
- { ShaderIrInst.Ffma, GetFfmaExpr },
- { ShaderIrInst.Flg2, GetFlg2Expr },
- { ShaderIrInst.Fmul, GetFmulExpr },
- { ShaderIrInst.Fneg, GetFnegExpr },
- { ShaderIrInst.Frcp, GetFrcpExpr },
- { ShaderIrInst.Frsq, GetFrsqExpr },
- { ShaderIrInst.Fsin, GetFsinExpr },
- { ShaderIrInst.Ipa, GetIpaExpr },
- { ShaderIrInst.Kil, GetKilExpr },
- { ShaderIrInst.Lsr, GetLsrExpr },
- { ShaderIrInst.Not, GetNotExpr },
- { ShaderIrInst.Or, GetOrExpr },
- { ShaderIrInst.Stof, GetStofExpr },
- { ShaderIrInst.Utof, GetUtofExpr },
- { ShaderIrInst.Texr, GetTexrExpr },
- { ShaderIrInst.Texg, GetTexgExpr },
- { ShaderIrInst.Texb, GetTexbExpr },
- { ShaderIrInst.Texa, GetTexaExpr },
- { ShaderIrInst.Xor, GetXorExpr },
+ { ShaderIrInst.And, GetAndExpr },
+ { ShaderIrInst.Asr, GetAsrExpr },
+ { ShaderIrInst.Band, GetBandExpr },
+ { ShaderIrInst.Bnot, GetBnotExpr },
+ { ShaderIrInst.Ceil, GetCeilExpr },
+ { ShaderIrInst.Ceq, GetCeqExpr },
+ { ShaderIrInst.Cge, GetCgeExpr },
+ { ShaderIrInst.Cgt, GetCgtExpr },
+ { ShaderIrInst.Clamp, GetClampExpr },
+ { ShaderIrInst.Cle, GetCleExpr },
+ { ShaderIrInst.Clt, GetCltExpr },
+ { ShaderIrInst.Cne, GetCneExpr },
+ { ShaderIrInst.Exit, GetExitExpr },
+ { ShaderIrInst.Fabs, GetFabsExpr },
+ { ShaderIrInst.Fadd, GetFaddExpr },
+ { ShaderIrInst.Fceq, GetCeqExpr },
+ { ShaderIrInst.Fcge, GetCgeExpr },
+ { ShaderIrInst.Fcgt, GetCgtExpr },
+ { ShaderIrInst.Fcle, GetCleExpr },
+ { ShaderIrInst.Fclt, GetCltExpr },
+ { ShaderIrInst.Fcne, GetCneExpr },
+ { ShaderIrInst.Fcos, GetFcosExpr },
+ { ShaderIrInst.Fex2, GetFex2Expr },
+ { ShaderIrInst.Ffma, GetFfmaExpr },
+ { ShaderIrInst.Flg2, GetFlg2Expr },
+ { ShaderIrInst.Floor, GetFloorExpr },
+ { ShaderIrInst.Fmul, GetFmulExpr },
+ { ShaderIrInst.Fneg, GetFnegExpr },
+ { ShaderIrInst.Frcp, GetFrcpExpr },
+ { ShaderIrInst.Frsq, GetFrsqExpr },
+ { ShaderIrInst.Fsin, GetFsinExpr },
+ { ShaderIrInst.Ftos, GetFtosExpr },
+ { ShaderIrInst.Ftou, GetFtouExpr },
+ { 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()
{
+ if (Decl.ShaderType == GalShaderType.Fragment)
+ {
+ SB.AppendLine("in vec4 " + GlslDecl.PositionOutAttrName + ";");
+ }
+
PrintDeclAttributes(Decl.InAttributes.Values, "in");
}
private void PrintDeclOutAttributes()
{
+ if (Decl.ShaderType == GalShaderType.Vertex)
+ {
+ SB.AppendLine("out vec4 " + GlslDecl.PositionOutAttrName + ";");
+ }
+
PrintDeclAttributes(Decl.OutAttributes.Values, "out");
}
@@ -133,7 +154,7 @@ namespace Ryujinx.Graphics.Gal.Shader
{
if (DeclInfo.Index >= 0)
{
- SB.AppendLine($"layout (location = {DeclInfo.Index}) {InOut} {GetDecl(DeclInfo)};");
+ SB.AppendLine("layout (location = " + DeclInfo.Index + ") " + InOut + " " + GetDecl(DeclInfo) + ";");
Count++;
}
@@ -222,7 +243,14 @@ namespace Ryujinx.Graphics.Gal.Shader
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);
}
@@ -236,6 +264,16 @@ namespace Ryujinx.Graphics.Gal.Shader
}
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) + ";");
}
else
@@ -321,10 +359,9 @@ namespace Ryujinx.Graphics.Gal.Shader
return true;
case ShaderIrInst.Ipa:
- case ShaderIrInst.Texr:
- case ShaderIrInst.Texg:
- case ShaderIrInst.Texb:
- case ShaderIrInst.Texa:
+ case ShaderIrInst.Texq:
+ case ShaderIrInst.Texs:
+ case ShaderIrInst.Txlf:
return false;
}
@@ -349,11 +386,6 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetName(ShaderIrOperAbuf Abuf)
{
- if (Abuf.Offs == GlslDecl.GlPositionWAttr && Decl.ShaderType == GalShaderType.Fragment)
- {
- return "(1f / gl_FragCoord.w)";
- }
-
if (Abuf.Offs == GlslDecl.VertexIdAttr)
{
return "gl_VertexID";
@@ -437,6 +469,10 @@ namespace Ryujinx.Graphics.Gal.Shader
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 GetCeqExpr(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 GetFloorExpr(ShaderIrOp Op) => GetUnaryCall(Op, "floor");
+
private string GetFmulExpr(ShaderIrOp Op) => GetBinaryExpr(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 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 GetKilExpr(ShaderIrOp Op) => "discard";
@@ -487,6 +535,54 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
return "float(uint(" + GetOperExpr(Op, Op.OperandA) + "))";
@@ -499,6 +595,13 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
return Opr + GetOperExpr(Op, Op.OperandA);
@@ -517,16 +620,6 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
ShaderIrOperImm Node = (ShaderIrOperImm)Op.OperandC;
@@ -547,6 +640,12 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
return GetExprWithCast(Op, Oper, GetSrcExpr(Oper));
@@ -571,13 +670,31 @@ namespace Ryujinx.Graphics.Gal.Shader
throw new InvalidOperationException();
}
- //For integer immediates being used as float,
- //it's better (for readability) to just return the float value.
- if (Src is ShaderIrOperImm Imm && DstType == OperType.F32)
+ switch (Src)
{
- 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)
@@ -592,12 +709,20 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
switch (Op.Inst)
{
- case ShaderIrInst.Stof: return OperType.F32;
- case ShaderIrInst.Utof: return OperType.F32;
+ case ShaderIrInst.Stof:
+ case ShaderIrInst.Txlf:
+ case ShaderIrInst.Utof:
+ return OperType.F32;
+
+ case ShaderIrInst.Ftos:
+ case ShaderIrInst.Ftou:
+ return OperType.I32;
}
}
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
index 5c2f493e..b796ab28 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
@@ -81,6 +81,21 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
int SubOp = (int)(OpCode >> 53) & 3;
@@ -259,6 +274,16 @@ namespace Ryujinx.Graphics.Gal.Shader
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 Np = ((OpCode >> 42) & 1) != 0;
bool Na = ((OpCode >> 43) & 1) != 0;
@@ -269,17 +294,28 @@ namespace Ryujinx.Graphics.Gal.Shader
switch (Oper)
{
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.RR: OperB = GetOperGpr20 (OpCode); break;
default: throw new ArgumentException(nameof(Oper));
}
- ShaderIrInst CmpInst = GetCmp(OpCode);
+ ShaderIrInst CmpInst;
+
+ if (IsFloat)
+ {
+ OperA = GetAluAbsNeg(OperA, Aa, Na);
+ OperB = GetAluAbs (OperB, Ab);
+
+ CmpInst = GetCmpF(OpCode);
+ }
+ else
+ {
+ CmpInst = GetCmp(OpCode);
+ }
- ShaderIrOp Op = new ShaderIrOp(CmpInst,
- GetAluAbsNeg(OperA, Aa, Na),
- GetAluAbs (OperB, Ab));
+ ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);
ShaderIrOperPred P0Node = GetOperPred3 (OpCode);
ShaderIrOperPred P1Node = GetOperPred0 (OpCode);
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
index 7989570d..de932dce 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
@@ -60,7 +60,17 @@ namespace Ryujinx.Graphics.Gal.Shader
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;
@@ -74,7 +84,7 @@ namespace Ryujinx.Graphics.Gal.Shader
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;
@@ -92,16 +102,6 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
return new ShaderIrOperPred((int)(OpCode >> 3) & 7);
@@ -131,22 +131,37 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
- case 0x1: return ShaderIrInst.Clt;
- case 0x2: return ShaderIrInst.Ceq;
- case 0x3: return ShaderIrInst.Cle;
- case 0x4: return ShaderIrInst.Cgt;
- case 0x5: return ShaderIrInst.Cne;
- case 0x6: return ShaderIrInst.Cge;
- case 0x7: return ShaderIrInst.Cnum;
- case 0x8: return ShaderIrInst.Cnan;
- case 0x9: return ShaderIrInst.Cltu;
- case 0xa: return ShaderIrInst.Cequ;
- case 0xb: return ShaderIrInst.Cleu;
- case 0xc: return ShaderIrInst.Cgtu;
- case 0xd: return ShaderIrInst.Cneu;
- case 0xe: return ShaderIrInst.Cgeu;
+ case 0x1: return ShaderIrInst.Fclt;
+ case 0x2: return ShaderIrInst.Fceq;
+ case 0x3: return ShaderIrInst.Fcle;
+ case 0x4: return ShaderIrInst.Fcgt;
+ case 0x5: return ShaderIrInst.Fcne;
+ case 0x6: return ShaderIrInst.Fcge;
+ case 0x7: return ShaderIrInst.Fcnum;
+ case 0x8: return ShaderIrInst.Fcnan;
+ case 0x9: return ShaderIrInst.Fcltu;
+ case 0xa: return ShaderIrInst.Fcequ;
+ case 0xb: return ShaderIrInst.Fcleu;
+ case 0xc: return ShaderIrInst.Fcgtu;
+ case 0xd: return ShaderIrInst.Fcneu;
+ case 0xe: return ShaderIrInst.Fcgeu;
}
throw new ArgumentException(nameof(OpCode));
@@ -170,7 +185,9 @@ namespace Ryujinx.Graphics.Gal.Shader
if (Pred.Index != ShaderIrOperPred.UnusedIndex)
{
- Node = new ShaderIrCond(Pred, Node);
+ bool Inv = ((OpCode >> 19) & 1) != 0;
+
+ Node = new ShaderIrCond(Pred, Node, Inv);
}
return Node;
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
index fd18ce07..6553cfcf 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
@@ -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)
{
+ 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.
- ShaderIrNode OperA = GetOperGpr8 (OpCode);
- ShaderIrNode OperB = GetOperGpr20 (OpCode);
- ShaderIrNode OperC = GetOperGpr28 (OpCode);
- ShaderIrNode OperD = GetOperImm13_36(OpCode);
+ ShaderIrNode OperA = GetOperGpr8 (OpCode);
+ ShaderIrNode OperB = GetOperGpr20 (OpCode);
+ ShaderIrNode OperC = GetOperImm13_36(OpCode);
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));
+ }
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
index 50c740bf..6d30cfed 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
@@ -25,6 +25,36 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
EmitI2f(Block, OpCode, ShaderOper.CR);
@@ -40,6 +70,131 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
IntType Type = GetIntType(OpCode);
@@ -76,18 +231,16 @@ namespace Ryujinx.Graphics.Gal.Shader
int Size = 8 << ((int)Type & 3);
- ulong Mask = ulong.MaxValue >> (64 - Size);
-
- int Mask32 = (int)Mask;
-
if (Shift != 0)
{
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
@@ -99,13 +252,6 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
bool Signed = ((OpCode >> 13) & 1) != 0;
@@ -124,5 +270,17 @@ namespace Ryujinx.Graphics.Gal.Shader
{
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;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
index 779bbf92..7bebea62 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
@@ -8,6 +8,15 @@ namespace Ryujinx.Graphics.Gal.Shader
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 Word1 = (uint)Code[Offset++];
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs
index d8c87b49..8fb01660 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs
@@ -5,10 +5,13 @@ namespace Ryujinx.Graphics.Gal.Shader
public ShaderIrNode Pred { 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.Child = Child;
+ this.Not = Not;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
index b6f4e80b..1b72f647 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
@@ -2,53 +2,66 @@ namespace Ryujinx.Graphics.Gal.Shader
{
enum ShaderIrInst
{
+ Invalid,
+
B_Start,
Band,
Bnot,
Bor,
Bxor,
- Clt,
- Ceq,
- Cle,
- Cgt,
- Cne,
- Cge,
- Cnum,
- Cnan,
- Cltu,
- Cequ,
- Cleu,
- Cgtu,
- Cneu,
- Cgeu,
B_End,
F_Start,
+ Ceil,
+ Clamp,
Fabs,
Fadd,
+ Fceq,
+ Fcequ,
+ Fcge,
+ Fcgeu,
+ Fcgt,
+ Fcgtu,
+ Fcle,
+ Fcleu,
+ Fclt,
+ Fcltu,
+ Fcnan,
+ Fcne,
+ Fcneu,
+ Fcnum,
Fcos,
Fex2,
Ffma,
Flg2,
+ Floor,
Fmul,
Fneg,
Frcp,
Frsq,
Fsin,
+ Ftos,
+ Ftou,
Ipa,
- Texr,
- Texg,
- Texb,
- Texa,
+ Texs,
+ Trunc,
F_End,
I_Start,
And,
Asr,
+ Ceq,
+ Cge,
+ Cgt,
+ Cle,
+ Clt,
+ Cne,
Lsr,
Not,
Or,
Stof,
+ Texq,
+ Txlf,
Utof,
Xor,
I_End,
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs
new file mode 100644
index 00000000..afb7503b
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs
@@ -0,0 +1,4 @@
+namespace Ryujinx.Graphics.Gal.Shader
+{
+ class ShaderIrMeta { }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs
new file mode 100644
index 00000000..82f3bb77
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs
new file mode 100644
index 00000000..92871137
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs
index cd210757..12a6123c 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs
@@ -6,17 +6,20 @@ namespace Ryujinx.Graphics.Gal.Shader
public ShaderIrNode OperandA { get; set; }
public ShaderIrNode OperandB { get; set; }
public ShaderIrNode OperandC { get; set; }
+ public ShaderIrMeta MetaData { get; set; }
public ShaderIrOp(
ShaderIrInst Inst,
ShaderIrNode OperandA = null,
ShaderIrNode OperandB = null,
- ShaderIrNode OperandC = null)
+ ShaderIrNode OperandC = null,
+ ShaderIrMeta MetaData = null)
{
this.Inst = Inst;
this.OperandA = OperandA;
this.OperandB = OperandB;
this.OperandC = OperandC;
+ this.MetaData = MetaData;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
index 48c3b2ee..a234f7f7 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
@@ -14,6 +14,12 @@ namespace Ryujinx.Graphics.Gal.Shader
#region Instructions
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("0011100x01011x", ShaderDecode.Fadd_I);
Set("0101110001011x", ShaderDecode.Fadd_R);
@@ -31,16 +37,24 @@ namespace Ryujinx.Graphics.Gal.Shader
Set("0011100x10111x", ShaderDecode.I2f_I);
Set("0101110010111x", ShaderDecode.I2f_R);
Set("11100000xxxxxx", ShaderDecode.Ipa);
+ Set("010010110110xx", ShaderDecode.Isetp_C);
+ Set("0011011x0110xx", ShaderDecode.Isetp_I);
+ Set("010110110110xx", ShaderDecode.Isetp_R);
Set("111000110011xx", ShaderDecode.Kil);
Set("1110111111011x", ShaderDecode.Ld_A);
Set("000001xxxxxxxx", ShaderDecode.Lop32i);
+ Set("0100110010011x", ShaderDecode.Mov_C);
+ Set("0011100x10011x", ShaderDecode.Mov_I);
+ Set("0101110010011x", ShaderDecode.Mov_R);
Set("000000010000xx", ShaderDecode.Mov32i);
Set("0101000010000x", ShaderDecode.Mufu);
Set("0100110000101x", ShaderDecode.Shr_C);
Set("0011100x00101x", ShaderDecode.Shr_I);
Set("0101110000101x", ShaderDecode.Shr_R);
Set("1110111111110x", ShaderDecode.St_A);
+ Set("1101111101001x", ShaderDecode.Texq);
Set("1101100xxxxxxx", ShaderDecode.Texs);
+ Set("1101101xxxxxxx", ShaderDecode.Tlds);
#endregion
}
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs
index 7989deed..aa485482 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs
@@ -3,9 +3,9 @@ namespace Ryujinx.Graphics.Gal.Shader
enum ShaderOper
{
CR,
- RC,
- RR,
Imm,
- Immf
+ Immf,
+ RC,
+ RR
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOptExprProp.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOptExprProp.cs
index 69457aeb..9ce7cbe3 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderOptExprProp.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderOptExprProp.cs
@@ -7,13 +7,22 @@ namespace Ryujinx.Graphics.Gal.Shader
{
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.Cond = Cond;
+ this.UseIndex = UseIndex;
this.OperIndex = OperIndex;
}
}
@@ -24,7 +33,9 @@ namespace Ryujinx.Graphics.Gal.Shader
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;
@@ -35,6 +46,11 @@ namespace Ryujinx.Graphics.Gal.Shader
public void AddUseSite(UseSite Site)
{
+ if (LastSiteIndex < Site.UseIndex)
+ {
+ LastSiteIndex = Site.UseIndex;
+ }
+
Sites.Add(Site);
}
@@ -42,14 +58,27 @@ namespace Ryujinx.Graphics.Gal.Shader
{
//This happens when a untiliazied register is used,
//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
//the expression (since we can't propagate what doesn't yet exist).
- if (Asg == null || !Propagate)
+ if (Asg == null)
{
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)
{
foreach (UseSite Site in Sites)
@@ -89,11 +118,13 @@ namespace Ryujinx.Graphics.Gal.Shader
return true;
}
- public void SetNewAsg(ShaderIrAsg Asg, int AsgIndex, bool Propagate)
+ public void SetNewAsg(ShaderIrAsg Asg, int AsgIndex, ShaderIrCond Cond)
{
- this.Asg = Asg;
- this.AsgIndex = AsgIndex;
- this.Propagate = Propagate;
+ this.Asg = Asg;
+ this.AsgIndex = AsgIndex;
+ this.Cond = Cond;
+
+ LastSiteIndex = 0;
Sites.Clear();
}
@@ -137,38 +168,52 @@ namespace Ryujinx.Graphics.Gal.Shader
return GetUse(GetPredKey(PredIndex));
}
- void FindRegUses(List<(int, UseSite)> UseList, object Parent, ShaderIrNode Node, int OperIndex = 0)
+ void RemoveUse(RegUse Use)
+ {
+ if (!Nodes.Remove((ShaderIrNode)Use.Cond ?? Use.Asg))
+ {
+ throw new InvalidOperationException();
+ }
+ }
+
+ 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);
+ FindRegUses(UseList, Asg, Asg.Src, CondNode, UseIndex);
}
else if (Node is ShaderIrCond Cond)
{
- FindRegUses(UseList, Cond, Cond.Pred, 0);
- FindRegUses(UseList, Cond, Cond.Child, 1);
+ 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, 0);
- FindRegUses(UseList, Op, Op.OperandB, 1);
- FindRegUses(UseList, Op, Op.OperandC, 2);
+ 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.Index != ShaderIrOperGpr.ZRIndex)
+ else if (Node is ShaderIrOperGpr Gpr && !Gpr.IsConst)
{
- UseList.Add((GetGprKey(Gpr.Index), new UseSite(Parent, OperIndex)));
+ 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, OperIndex)));
+ UseList.Add((GetPredKey(Pred.Index), new UseSite(Parent, CondNode, UseIndex, OperIndex)));
}
}
- void TryAddRegUseSite(ShaderIrNode Node)
+ void TryAddRegUseSite(ShaderIrNode Node, ShaderIrCond CondNode, int UseIndex)
{
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)
{
@@ -190,10 +235,22 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
+ //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)
{
return false;
@@ -203,13 +260,18 @@ namespace Ryujinx.Graphics.Gal.Shader
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];
- 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)
{
@@ -223,7 +285,7 @@ namespace Ryujinx.Graphics.Gal.Shader
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);
}
@@ -232,16 +294,22 @@ namespace Ryujinx.Graphics.Gal.Shader
Use = GetPredUse(Pred.Index);
}
- if (!IsConditional && TryPropagate(Use))
+ bool CanRemoveAsg = CondNode == null;
+
+ CanRemoveAsg |= IsSameCondition(CondNode, Use?.Cond);
+
+ if (CanRemoveAsg && TryPropagate(Use))
{
- Nodes.Remove(Use.Asg);
+ RemoveUse(Use);
+ //Note: Only decrement if the removal was successful.
+ //RemoveUse throws when this is not the case so we should be good.
Index--;
}
//All nodes inside conditional nodes can't be propagated,
//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)
@@ -258,9 +326,41 @@ namespace Ryujinx.Graphics.Gal.Shader
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;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs b/Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs
new file mode 100644
index 00000000..9158662c
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs
@@ -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
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gpu/TextureReader.cs b/Ryujinx.Graphics/Gpu/TextureReader.cs
index 60285aed..715578b5 100644
--- a/Ryujinx.Graphics/Gpu/TextureReader.cs
+++ b/Ryujinx.Graphics/Gpu/TextureReader.cs
@@ -12,6 +12,7 @@ namespace Ryujinx.Graphics.Gpu
{
case GalTextureFormat.A8B8G8R8: return Read4Bpp (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.BC2: return Read16Bpt4x4(Memory, Texture);
case GalTextureFormat.BC3: return Read16Bpt4x4(Memory, Texture);
@@ -20,14 +21,14 @@ namespace Ryujinx.Graphics.Gpu
throw new NotImplementedException(Texture.Format.ToString());
}
- private unsafe static byte[] Read4Bpp(AMemory Memory, Texture Texture)
+ private unsafe static byte[] Read2Bpp(AMemory Memory, Texture Texture)
{
int Width = Texture.Width;
int Height = Texture.Height;
- byte[] Output = new byte[Width * Height * 4];
+ byte[] Output = new byte[Width * Height * 2];
- ISwizzle Swizzle = GetSwizzle(Texture, 4);
+ ISwizzle Swizzle = GetSwizzle(Texture, Width, 2);
fixed (byte* BuffPtr = Output)
{
@@ -38,25 +39,25 @@ namespace Ryujinx.Graphics.Gpu
{
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
- int Pixel = Memory.ReadInt32Unchecked(Texture.Position + Offset);
+ short Pixel = Memory.ReadInt16Unchecked(Texture.Position + Offset);
- *(int*)(BuffPtr + OutOffs) = Pixel;
+ *(short*)(BuffPtr + OutOffs) = Pixel;
- OutOffs += 4;
+ OutOffs += 2;
}
}
return Output;
}
- private unsafe static byte[] Read2Bpp(AMemory Memory, Texture Texture)
+ private unsafe static byte[] Read4Bpp(AMemory Memory, Texture Texture)
{
int Width = Texture.Width;
int Height = Texture.Height;
- byte[] Output = new byte[Width * Height * 2];
+ byte[] Output = new byte[Width * Height * 4];
- ISwizzle Swizzle = GetSwizzle(Texture, 2);
+ ISwizzle Swizzle = GetSwizzle(Texture, Width, 4);
fixed (byte* BuffPtr = Output)
{
@@ -67,11 +68,11 @@ namespace Ryujinx.Graphics.Gpu
{
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
- short Pixel = Memory.ReadInt16Unchecked(Texture.Position + Offset);
+ int Pixel = Memory.ReadInt32Unchecked(Texture.Position + Offset);
- *(short*)(BuffPtr + OutOffs) = Pixel;
+ *(int*)(BuffPtr + OutOffs) = Pixel;
- OutOffs += 2;
+ OutOffs += 4;
}
}
@@ -85,7 +86,7 @@ namespace Ryujinx.Graphics.Gpu
byte[] Output = new byte[Width * Height * 8];
- ISwizzle Swizzle = GetSwizzle(Texture, 8);
+ ISwizzle Swizzle = GetSwizzle(Texture, Width, 8);
fixed (byte* BuffPtr = Output)
{
@@ -114,7 +115,7 @@ namespace Ryujinx.Graphics.Gpu
byte[] Output = new byte[Width * Height * 16];
- ISwizzle Swizzle = GetSwizzle(Texture, 16);
+ ISwizzle Swizzle = GetSwizzle(Texture, Width, 16);
fixed (byte* BuffPtr = Output)
{
@@ -138,7 +139,7 @@ namespace Ryujinx.Graphics.Gpu
return Output;
}
- private static ISwizzle GetSwizzle(Texture Texture, int Bpp)
+ private static ISwizzle GetSwizzle(Texture Texture, int Width, int Bpp)
{
switch (Texture.Swizzle)
{
@@ -148,7 +149,7 @@ namespace Ryujinx.Graphics.Gpu
case TextureSwizzle.BlockLinear:
case TextureSwizzle.BlockLinearColorKey:
- return new BlockLinearSwizzle(Texture.Width, Bpp, Texture.BlockHeight);
+ return new BlockLinearSwizzle(Width, Bpp, Texture.BlockHeight);
}
throw new NotImplementedException(Texture.Swizzle.ToString());