aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-05-17 15:25:42 -0300
committergdkchan <gab.dark.100@gmail.com>2018-05-17 15:25:42 -0300
commitb19c4740823ed8fcebf62bf5741a7614a2ac0aa0 (patch)
tree8cdede3fdb90aa35ffe50c004559b80d4704bea3
parent9b9ead94cd2f25a85468ecf91b7898bf34e10825 (diff)
Added more shader instructions, including BFE, BRA (partial), FMNMX, ISCADD, SHL, LD_C, some shader related fixes, added support for texture component selection
-rw-r--r--Ryujinx.Core/Gpu/TextureFactory.cs15
-rw-r--r--Ryujinx.Core/OsHle/Kernel/SvcThread.cs7
-rw-r--r--Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs18
-rw-r--r--Ryujinx.Core/OsHle/Services/Prepo/IPrepoService.cs10
-rw-r--r--Ryujinx.Graphics/Gal/GalTexture.cs27
-rw-r--r--Ryujinx.Graphics/Gal/GalTextureSource.cs13
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs16
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs20
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs10
-rw-r--r--Ryujinx.Graphics/Gal/Shader/GlslDecl.cs28
-rw-r--r--Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs139
-rw-r--r--Ryujinx.Graphics/Gal/Shader/GlslProgram.cs2
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs285
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs18
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs65
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs37
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs38
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs20
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs28
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs12
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs9
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrLabel.cs4
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs7
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs20
-rw-r--r--Ryujinx.Graphics/Gal/ShaderDeclInfo.cs8
-rw-r--r--Ryujinx.sln6
-rw-r--r--Ryushader/Program.cs48
-rw-r--r--Ryushader/Ryushader.csproj12
28 files changed, 805 insertions, 117 deletions
diff --git a/Ryujinx.Core/Gpu/TextureFactory.cs b/Ryujinx.Core/Gpu/TextureFactory.cs
index 68b48a1f..5206c125 100644
--- a/Ryujinx.Core/Gpu/TextureFactory.cs
+++ b/Ryujinx.Core/Gpu/TextureFactory.cs
@@ -11,6 +11,11 @@ namespace Ryujinx.Core.Gpu
GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);
+ GalTextureSource XSource = (GalTextureSource)((Tic[0] >> 19) & 7);
+ GalTextureSource YSource = (GalTextureSource)((Tic[0] >> 22) & 7);
+ GalTextureSource ZSource = (GalTextureSource)((Tic[0] >> 25) & 7);
+ GalTextureSource WSource = (GalTextureSource)((Tic[0] >> 28) & 7);
+
long TextureAddress = (uint)Tic[1];
TextureAddress |= (long)((ushort)Tic[2]) << 32;
@@ -37,7 +42,15 @@ namespace Ryujinx.Core.Gpu
byte[] Data = TextureReader.Read(Vmm, Texture);
- return new GalTexture(Data, Width, Height, Format);
+ return new GalTexture(
+ Data,
+ Width,
+ Height,
+ Format,
+ XSource,
+ YSource,
+ ZSource,
+ WSource);
}
public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition)
diff --git a/Ryujinx.Core/OsHle/Kernel/SvcThread.cs b/Ryujinx.Core/OsHle/Kernel/SvcThread.cs
index b504f81a..8aa26dd3 100644
--- a/Ryujinx.Core/OsHle/Kernel/SvcThread.cs
+++ b/Ryujinx.Core/OsHle/Kernel/SvcThread.cs
@@ -141,6 +141,13 @@ namespace Ryujinx.Core.OsHle.Kernel
private void SvcSetThreadCoreMask(AThreadState ThreadState)
{
+ //FIXME: This is wrong, but the "correct" way to handle
+ //this svc causes deadlocks when more often.
+ //There is probably something wrong with it still.
+ ThreadState.X0 = 0;
+
+ return;
+
int Handle = (int)ThreadState.X0;
int IdealCore = (int)ThreadState.X1;
long CoreMask = (long)ThreadState.X2;
diff --git a/Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs b/Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs
index 7de5a4d9..0d1aa5e4 100644
--- a/Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs
+++ b/Ryujinx.Core/OsHle/Services/Nifm/IRequest.cs
@@ -18,11 +18,12 @@ namespace Ryujinx.Core.OsHle.Services.Nifm
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
- { 0, GetRequestState },
- { 1, GetResult },
- { 2, GetSystemEventReadableHandles },
- { 3, Cancel },
- { 4, Submit },
+ { 0, GetRequestState },
+ { 1, GetResult },
+ { 2, GetSystemEventReadableHandles },
+ { 3, Cancel },
+ { 4, Submit },
+ { 11, SetConnectionConfirmationOption }
};
Event = new KEvent();
@@ -69,6 +70,13 @@ namespace Ryujinx.Core.OsHle.Services.Nifm
return 0;
}
+ public long SetConnectionConfirmationOption(ServiceCtx Context)
+ {
+ Context.Ns.Log.PrintStub(LogClass.ServiceNifm, "Stubbed.");
+
+ return 0;
+ }
+
public void Dispose()
{
Dispose(true);
diff --git a/Ryujinx.Core/OsHle/Services/Prepo/IPrepoService.cs b/Ryujinx.Core/OsHle/Services/Prepo/IPrepoService.cs
index 42e43841..dbf01c6b 100644
--- a/Ryujinx.Core/OsHle/Services/Prepo/IPrepoService.cs
+++ b/Ryujinx.Core/OsHle/Services/Prepo/IPrepoService.cs
@@ -1,3 +1,4 @@
+using Ryujinx.Core.Logging;
using Ryujinx.Core.OsHle.Ipc;
using System.Collections.Generic;
@@ -13,8 +14,15 @@ namespace Ryujinx.Core.OsHle.Services.Prepo
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
- //...
+ { 10101, SaveReportWithUser }
};
}
+
+ public static long SaveReportWithUser(ServiceCtx Context)
+ {
+ Context.Ns.Log.PrintStub(LogClass.ServicePrepo, "Stubbed.");
+
+ return 0;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/GalTexture.cs b/Ryujinx.Graphics/Gal/GalTexture.cs
index fcf1f1ad..75aef307 100644
--- a/Ryujinx.Graphics/Gal/GalTexture.cs
+++ b/Ryujinx.Graphics/Gal/GalTexture.cs
@@ -9,12 +9,29 @@ namespace Ryujinx.Graphics.Gal
public GalTextureFormat Format;
- public GalTexture(byte[] Data, int Width, int Height, GalTextureFormat Format)
+ public GalTextureSource XSource;
+ public GalTextureSource YSource;
+ public GalTextureSource ZSource;
+ public GalTextureSource WSource;
+
+ public GalTexture(
+ byte[] Data,
+ int Width,
+ int Height,
+ GalTextureFormat Format,
+ GalTextureSource XSource,
+ GalTextureSource YSource,
+ GalTextureSource ZSource,
+ GalTextureSource WSource)
{
- this.Data = Data;
- this.Width = Width;
- this.Height = Height;
- this.Format = Format;
+ this.Data = Data;
+ this.Width = Width;
+ this.Height = Height;
+ this.Format = Format;
+ this.XSource = XSource;
+ this.YSource = YSource;
+ this.ZSource = ZSource;
+ this.WSource = WSource;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/GalTextureSource.cs b/Ryujinx.Graphics/Gal/GalTextureSource.cs
new file mode 100644
index 00000000..72dbec60
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/GalTextureSource.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.Graphics.Gal
+{
+ public enum GalTextureSource
+ {
+ Zero = 0,
+ Red = 2,
+ Green = 3,
+ Blue = 4,
+ Alpha = 5,
+ OneInt = 6,
+ OneFloat = 7
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
index 4cc0a039..d266a87a 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
@@ -81,6 +81,22 @@ namespace Ryujinx.Graphics.Gal.OpenGL
throw new NotImplementedException(Format.ToString());
}
+ public static All GetTextureSwizzle(GalTextureSource Source)
+ {
+ switch (Source)
+ {
+ case GalTextureSource.Zero: return All.Zero;
+ case GalTextureSource.Red: return All.Red;
+ case GalTextureSource.Green: return All.Green;
+ case GalTextureSource.Blue: return All.Blue;
+ case GalTextureSource.Alpha: return All.Alpha;
+ case GalTextureSource.OneInt: return All.One;
+ case GalTextureSource.OneFloat: return All.One;
+ }
+
+ throw new ArgumentException(nameof(Source));
+ }
+
public static TextureWrapMode GetTextureWrapMode(GalTextureWrap Wrap)
{
switch (Wrap)
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
index fff6362b..e740a32e 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
@@ -87,10 +87,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public void Create(long Tag, GalShaderType Type, byte[] Data)
{
- Stages.GetOrAdd(Tag, (Key) => ShaderStageFactory(Type, Data));
+ Stages.GetOrAdd(Tag, (Key) => ShaderStageFactory(Type, Tag, Data));
}
- private ShaderStage ShaderStageFactory(GalShaderType Type, byte[] Data)
+ private ShaderStage ShaderStageFactory(GalShaderType Type, long Tag, byte[] Data)
{
GlslProgram Program = GetGlslProgram(Data, Type);
@@ -140,11 +140,21 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf))
{
- float Value = BitConverter.ToSingle(Data, DeclInfo.Index * 4);
-
int Location = GL.GetUniformLocation(CurrentProgramHandle, DeclInfo.Name);
- GL.Uniform1(Location, Value);
+ int Count = Data.Length >> 2;
+
+ //The Index is the index of the last element,
+ //so we can add 1 to get the uniform array size.
+ Count = Math.Min(Count, DeclInfo.Index + 1);
+
+ unsafe
+ {
+ fixed (byte* Ptr = Data)
+ {
+ GL.Uniform1(Location, Count, (float*)Ptr);
+ }
+ }
}
}
}
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
index 9ea25056..8dcfb2bd 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
@@ -51,6 +51,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Type,
Texture.Data);
}
+
+ int SwizzleR = (int)OGLEnumConverter.GetTextureSwizzle(Texture.XSource);
+ int SwizzleG = (int)OGLEnumConverter.GetTextureSwizzle(Texture.YSource);
+ int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Texture.ZSource);
+ int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Texture.WSource);
+
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, SwizzleB);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA);
}
public void Bind(int Index)
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
index cd901747..2650569e 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
@@ -28,7 +28,7 @@ namespace Ryujinx.Graphics.Gal.Shader
private Dictionary<int, ShaderDeclInfo> m_Textures;
- private Dictionary<(int, int), ShaderDeclInfo> m_Uniforms;
+ private Dictionary<int, ShaderDeclInfo> m_Uniforms;
private Dictionary<int, ShaderDeclInfo> m_InAttributes;
private Dictionary<int, ShaderDeclInfo> m_OutAttributes;
@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gal.Shader
public IReadOnlyDictionary<int, ShaderDeclInfo> Textures => m_Textures;
- public IReadOnlyDictionary<(int, int), ShaderDeclInfo> Uniforms => m_Uniforms;
+ public IReadOnlyDictionary<int, ShaderDeclInfo> Uniforms => m_Uniforms;
public IReadOnlyDictionary<int, ShaderDeclInfo> InAttributes => m_InAttributes;
public IReadOnlyDictionary<int, ShaderDeclInfo> OutAttributes => m_OutAttributes;
@@ -54,7 +54,7 @@ namespace Ryujinx.Graphics.Gal.Shader
StagePrefix = StagePrefixes[(int)ShaderType] + "_";
- m_Uniforms = new Dictionary<(int, int), ShaderDeclInfo>();
+ m_Uniforms = new Dictionary<int, ShaderDeclInfo>();
m_Textures = new Dictionary<int, ShaderDeclInfo>();
@@ -124,11 +124,27 @@ namespace Ryujinx.Graphics.Gal.Shader
case ShaderIrOperCbuf Cbuf:
{
- string Name = StagePrefix + UniformName + Cbuf.Index + "_" + Cbuf.Offs;
+ if (m_Uniforms.TryGetValue(Cbuf.Index, out ShaderDeclInfo DeclInfo))
+ {
+ DeclInfo.SetCbufOffs(Cbuf.Pos);
+ }
+ else
+ {
+ string Name = StagePrefix + UniformName + Cbuf.Index;
- ShaderDeclInfo DeclInfo = new ShaderDeclInfo(Name, Cbuf.Offs, Cbuf.Index);
+ DeclInfo = new ShaderDeclInfo(Name, Cbuf.Pos, Cbuf.Index);
- m_Uniforms.TryAdd((Cbuf.Index, Cbuf.Offs), DeclInfo);
+ m_Uniforms.Add(Cbuf.Index, DeclInfo);
+ }
+
+ if (Cbuf.Offs != null)
+ {
+ //The constant buffer is being accessed as an array,
+ //we have no way to know the max element it may access in this case.
+ //Here, we just assume the array size with arbitrary values.
+ //TODO: Find a better solution for this.
+ DeclInfo.SetCbufOffs(Cbuf.Pos + 15);
+ }
break;
}
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
index 1e0824d2..d6f171f4 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
@@ -6,7 +6,7 @@ using System.Text;
namespace Ryujinx.Graphics.Gal.Shader
{
- class GlslDecompiler
+ public class GlslDecompiler
{
private delegate string GetInstExpr(ShaderIrOp Op);
@@ -31,6 +31,8 @@ namespace Ryujinx.Graphics.Gal.Shader
{
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
{
+ { ShaderIrInst.Abs, GetAbsExpr },
+ { ShaderIrInst.Add, GetAddExpr },
{ ShaderIrInst.And, GetAndExpr },
{ ShaderIrInst.Asr, GetAsrExpr },
{ ShaderIrInst.Band, GetBandExpr },
@@ -45,8 +47,8 @@ namespace Ryujinx.Graphics.Gal.Shader
{ ShaderIrInst.Clt, GetCltExpr },
{ ShaderIrInst.Cne, GetCneExpr },
{ ShaderIrInst.Exit, GetExitExpr },
- { ShaderIrInst.Fabs, GetFabsExpr },
- { ShaderIrInst.Fadd, GetFaddExpr },
+ { ShaderIrInst.Fabs, GetAbsExpr },
+ { ShaderIrInst.Fadd, GetAddExpr },
{ ShaderIrInst.Fceq, GetCeqExpr },
{ ShaderIrInst.Fcge, GetCgeExpr },
{ ShaderIrInst.Fcgt, GetCgtExpr },
@@ -59,8 +61,10 @@ namespace Ryujinx.Graphics.Gal.Shader
{ ShaderIrInst.Ffma, GetFfmaExpr },
{ ShaderIrInst.Flg2, GetFlg2Expr },
{ ShaderIrInst.Floor, GetFloorExpr },
- { ShaderIrInst.Fmul, GetFmulExpr },
- { ShaderIrInst.Fneg, GetFnegExpr },
+ { ShaderIrInst.Fmax, GetFmaxExpr },
+ { ShaderIrInst.Fmin, GetFminExpr },
+ { ShaderIrInst.Fmul, GetMulExpr },
+ { ShaderIrInst.Fneg, GetNegExpr },
{ ShaderIrInst.Frcp, GetFrcpExpr },
{ ShaderIrInst.Frsq, GetFrsqExpr },
{ ShaderIrInst.Fsin, GetFsinExpr },
@@ -68,10 +72,14 @@ namespace Ryujinx.Graphics.Gal.Shader
{ ShaderIrInst.Ftou, GetFtouExpr },
{ ShaderIrInst.Ipa, GetIpaExpr },
{ ShaderIrInst.Kil, GetKilExpr },
+ { ShaderIrInst.Lsl, GetLslExpr },
{ ShaderIrInst.Lsr, GetLsrExpr },
+ { ShaderIrInst.Mul, GetMulExpr },
+ { ShaderIrInst.Neg, GetNegExpr },
{ ShaderIrInst.Not, GetNotExpr },
{ ShaderIrInst.Or, GetOrExpr },
{ ShaderIrInst.Stof, GetStofExpr },
+ { ShaderIrInst.Sub, GetSubExpr },
{ ShaderIrInst.Texq, GetTexqExpr },
{ ShaderIrInst.Texs, GetTexsExpr },
{ ShaderIrInst.Trunc, GetTruncExpr },
@@ -100,7 +108,7 @@ namespace Ryujinx.Graphics.Gal.Shader
PrintDeclGprs();
PrintDeclPreds();
- PrintBlockScope("void main()", 1, Nodes);
+ PrintBlockScope(Nodes, 0, Nodes.Length, "void main()", 1);
string GlslCode = SB.ToString();
@@ -124,7 +132,7 @@ namespace Ryujinx.Graphics.Gal.Shader
foreach (ShaderDeclInfo DeclInfo in Decl.Uniforms.Values.OrderBy(DeclKeySelector))
{
- SB.AppendLine($"uniform {GetDecl(DeclInfo)};");
+ SB.AppendLine($"uniform {GetDecl(DeclInfo)}[{DeclInfo.Index + 1}];");
}
if (Decl.Uniforms.Count > 0)
@@ -221,7 +229,12 @@ namespace Ryujinx.Graphics.Gal.Shader
return ElemTypes[DeclInfo.Size - 1] + " " + DeclInfo.Name;
}
- private void PrintBlockScope(string ScopeName, int IdentationLevel, params ShaderIrNode[] Nodes)
+ private void PrintBlockScope(
+ ShaderIrNode[] Nodes,
+ int Start,
+ int Count,
+ string ScopeName,
+ int IdentationLevel)
{
string Identation = string.Empty;
@@ -244,7 +257,7 @@ namespace Ryujinx.Graphics.Gal.Shader
Identation += IdentationStr;
}
- for (int Index = 0; Index < Nodes.Length; Index++)
+ for (int Index = Start; Index < Start + Count; Index++)
{
ShaderIrNode Node = Nodes[Index];
@@ -257,9 +270,44 @@ namespace Ryujinx.Graphics.Gal.Shader
IfExpr = "!(" + IfExpr + ")";
}
- string SubScopeName = "if (" + IfExpr + ")";
+ if (Cond.Child is ShaderIrOp Op && Op.Inst == ShaderIrInst.Bra)
+ {
+ ShaderIrLabel Label = (ShaderIrLabel)Op.OperandA;
+
+ int Target = FindLabel(Nodes, Label, Index + 1);
+
+ int IfCount = Target - Index - 1;
+
+ string SubScopeName = "if (!" + IfExpr + ")";
+
+ if (Nodes[Index + IfCount] is ShaderIrOp LastOp && LastOp.Inst == ShaderIrInst.Bra)
+ {
+ Target = FindLabel(Nodes, (ShaderIrLabel)LastOp.OperandA, Index + 1);
+
+ int ElseCount = Target - (Index + 1 + IfCount);
+
+ PrintBlockScope(Nodes, Index + 1, IfCount - 1, SubScopeName, IdentationLevel + 1);
+
+ PrintBlockScope(Nodes, Index + 1 + IfCount, ElseCount, "else", IdentationLevel + 1);
+
+ Index += IfCount + ElseCount;
+ }
+ else
+ {
+ PrintBlockScope(Nodes, Index + 1, IfCount, SubScopeName, IdentationLevel + 1);
+
+ Index += IfCount;
+ }
+ }
+ else
+ {
+ string SubScopeName = "if (" + IfExpr + ")";
+
+ ShaderIrNode[] Child = new ShaderIrNode[] { Cond.Child };
+
+ PrintBlockScope(Child, 0, 1, SubScopeName, IdentationLevel + 1);
+ }
- PrintBlockScope(SubScopeName, IdentationLevel + 1, Cond.Child);
}
else if (Node is ShaderIrAsg Asg)
{
@@ -288,6 +336,14 @@ namespace Ryujinx.Graphics.Gal.Shader
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
}
+ else if (Node is ShaderIrLabel Label)
+ {
+ //TODO: Add support for loops here.
+ }
+ else if (Node is ShaderIrCmnt Cmnt)
+ {
+ SB.AppendLine(Identation + "// " + Cmnt.Comment);
+ }
else
{
throw new InvalidOperationException();
@@ -297,6 +353,21 @@ namespace Ryujinx.Graphics.Gal.Shader
SB.AppendLine(LastLine);
}
+ private int FindLabel(ShaderIrNode[] Nodes, ShaderIrLabel Label, int Start)
+ {
+ int Target;
+
+ for (Target = Start; Target < Nodes.Length; Target++)
+ {
+ if (Nodes[Target] == Label)
+ {
+ return Target;
+ }
+ }
+
+ throw new InvalidOperationException();
+ }
+
private bool IsValidOutOper(ShaderIrNode Node)
{
if (Node is ShaderIrOperGpr Gpr && Gpr.IsConst)
@@ -383,12 +454,23 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetName(ShaderIrOperCbuf Cbuf)
{
- if (!Decl.Uniforms.TryGetValue((Cbuf.Index, Cbuf.Offs), out ShaderDeclInfo DeclInfo))
+ if (!Decl.Uniforms.TryGetValue(Cbuf.Index, out ShaderDeclInfo DeclInfo))
{
throw new InvalidOperationException();
}
- return DeclInfo.Name;
+ if (Cbuf.Offs != null)
+ {
+ //Note: We assume that the register value is always a multiple of 4.
+ //This may not be aways the case.
+ string Offset = "(floatBitsToInt(" + GetSrcExpr(Cbuf.Offs) + ") >> 2)";
+
+ return DeclInfo.Name + "[" + Cbuf.Pos + " + " + Offset + "]";
+ }
+ else
+ {
+ return DeclInfo.Name + "[" + Cbuf.Pos + "]";
+ }
}
private string GetOutAbufName(ShaderIrOperAbuf Abuf)
@@ -473,6 +555,10 @@ namespace Ryujinx.Graphics.Gal.Shader
return "xyzw".Substring(Elem, 1);
}
+ private string GetAbsExpr(ShaderIrOp Op) => GetUnaryCall(Op, "abs");
+
+ private string GetAddExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "+");
+
private string GetAndExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "&");
private string GetAsrExpr(ShaderIrOp Op) => GetBinaryExpr(Op, ">>");
@@ -506,10 +592,6 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetExitExpr(ShaderIrOp Op) => "return";
- private string GetFabsExpr(ShaderIrOp Op) => GetUnaryCall(Op, "abs");
-
- private string GetFaddExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "+");
-
private string GetFcosExpr(ShaderIrOp Op) => GetUnaryCall(Op, "cos");
private string GetFex2Expr(ShaderIrOp Op) => GetUnaryCall(Op, "exp2");
@@ -522,9 +604,8 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetFloorExpr(ShaderIrOp Op) => GetUnaryCall(Op, "floor");
- private string GetFmulExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "*");
-
- private string GetFnegExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "-");
+ private string GetFmaxExpr(ShaderIrOp Op) => GetBinaryCall(Op, "max");
+ private string GetFminExpr(ShaderIrOp Op) => GetBinaryCall(Op, "min");
private string GetFrcpExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "1 / ");
@@ -546,12 +627,17 @@ namespace Ryujinx.Graphics.Gal.Shader
private string GetKilExpr(ShaderIrOp Op) => "discard";
+ private string GetLslExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<<");
private string GetLsrExpr(ShaderIrOp Op)
{
return "int(uint(" + GetOperExpr(Op, Op.OperandA) + ") >> " +
GetOperExpr(Op, Op.OperandB) + ")";
}
+ private string GetMulExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "*");
+
+ private string GetNegExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "-");
+
private string GetNotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "~");
private string GetOrExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "|");
@@ -561,6 +647,8 @@ namespace Ryujinx.Graphics.Gal.Shader
return "float(" + GetOperExpr(Op, Op.OperandA) + ")";
}
+ private string GetSubExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "-");
+
private string GetTexqExpr(ShaderIrOp Op)
{
ShaderIrMetaTexq Meta = (ShaderIrMetaTexq)Op.MetaData;
@@ -621,6 +709,12 @@ namespace Ryujinx.Graphics.Gal.Shader
return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ")";
}
+ private string GetBinaryCall(ShaderIrOp Op, string FuncName)
+ {
+ return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ", " +
+ GetOperExpr(Op, Op.OperandB) + ")";
+ }
+
private string GetTernaryCall(ShaderIrOp Op, string FuncName)
{
return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ", " +
@@ -717,7 +811,10 @@ namespace Ryujinx.Graphics.Gal.Shader
{
float Value = BitConverter.Int32BitsToSingle(Imm.Value);
- return Value.ToString(CultureInfo.InvariantCulture);
+ if (!float.IsNaN(Value) && !float.IsInfinity(Value))
+ {
+ return Value.ToString(CultureInfo.InvariantCulture);
+ }
}
break;
}
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslProgram.cs b/Ryujinx.Graphics/Gal/Shader/GlslProgram.cs
index 729b6f1d..a7af05ae 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslProgram.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslProgram.cs
@@ -2,7 +2,7 @@ using System.Collections.Generic;
namespace Ryujinx.Graphics.Gal.Shader
{
- struct GlslProgram
+ public struct GlslProgram
{
public string Code { get; private set; }
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
index 42609bce..1bb5f478 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
@@ -6,6 +6,21 @@ namespace Ryujinx.Graphics.Gal.Shader
{
static partial class ShaderDecode
{
+ public static void Bfe_C(ShaderIrBlock Block, long OpCode)
+ {
+ EmitBfe(Block, OpCode, ShaderOper.CR);
+ }
+
+ public static void Bfe_I(ShaderIrBlock Block, long OpCode)
+ {
+ EmitBfe(Block, OpCode, ShaderOper.Imm);
+ }
+
+ public static void Bfe_R(ShaderIrBlock Block, long OpCode)
+ {
+ EmitBfe(Block, OpCode, ShaderOper.RR);
+ }
+
public static void Fadd_C(ShaderIrBlock Block, long OpCode)
{
EmitAluBinaryF(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fadd);
@@ -23,25 +38,40 @@ namespace Ryujinx.Graphics.Gal.Shader
public static void Ffma_CR(ShaderIrBlock Block, long OpCode)
{
- EmitAluFfma(Block, OpCode, ShaderOper.CR);
+ EmitFfma(Block, OpCode, ShaderOper.CR);
}
public static void Ffma_I(ShaderIrBlock Block, long OpCode)
{
- EmitAluFfma(Block, OpCode, ShaderOper.Immf);
+ EmitFfma(Block, OpCode, ShaderOper.Immf);
}
public static void Ffma_RC(ShaderIrBlock Block, long OpCode)
{
- EmitAluFfma(Block, OpCode, ShaderOper.RC);
+ EmitFfma(Block, OpCode, ShaderOper.RC);
}
public static void Ffma_RR(ShaderIrBlock Block, long OpCode)
{
- EmitAluFfma(Block, OpCode, ShaderOper.RR);
+ EmitFfma(Block, OpCode, ShaderOper.RR);
+ }
+
+ public static void Fmnmx_C(ShaderIrBlock Block, long OpCode)
+ {
+ EmitFmnmx(Block, OpCode, ShaderOper.CR);
}
- public static void Fmul32i(ShaderIrBlock Block, long OpCode)
+ public static void Fmnmx_I(ShaderIrBlock Block, long OpCode)
+ {
+ EmitFmnmx(Block, OpCode, ShaderOper.Immf);
+ }
+
+ public static void Fmnmx_R(ShaderIrBlock Block, long OpCode)
+ {
+ EmitFmnmx(Block, OpCode, ShaderOper.RR);
+ }
+
+ public static void Fmul_I32(ShaderIrBlock Block, long OpCode)
{
ShaderIrNode OperA = GetOperGpr8 (OpCode);
ShaderIrNode OperB = GetOperImmf32_20(OpCode);
@@ -106,6 +136,21 @@ namespace Ryujinx.Graphics.Gal.Shader
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
}
+ public static void Iscadd_C(ShaderIrBlock Block, long OpCode)
+ {
+ EmitIscadd(Block, OpCode, ShaderOper.CR);
+ }
+
+ public static void Iscadd_I(ShaderIrBlock Block, long OpCode)
+ {
+ EmitIscadd(Block, OpCode, ShaderOper.Imm);
+ }
+
+ public static void Iscadd_R(ShaderIrBlock Block, long OpCode)
+ {
+ EmitIscadd(Block, OpCode, ShaderOper.RR);
+ }
+
public static void Isetp_C(ShaderIrBlock Block, long OpCode)
{
EmitIsetp(Block, OpCode, ShaderOper.CR);
@@ -121,12 +166,12 @@ namespace Ryujinx.Graphics.Gal.Shader
EmitIsetp(Block, OpCode, ShaderOper.RR);
}
- public static void Lop32i(ShaderIrBlock Block, long OpCode)
+ public static void Lop_I32(ShaderIrBlock Block, long OpCode)
{
int SubOp = (int)(OpCode >> 53) & 3;
- bool Ia = ((OpCode >> 55) & 1) != 0;
- bool Ib = ((OpCode >> 56) & 1) != 0;
+ bool InvA = ((OpCode >> 55) & 1) != 0;
+ bool InvB = ((OpCode >> 56) & 1) != 0;
ShaderIrInst Inst = 0;
@@ -137,13 +182,13 @@ namespace Ryujinx.Graphics.Gal.Shader
case 2: Inst = ShaderIrInst.Xor; break;
}
- ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), Ia);
+ ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), InvA);
//SubOp == 3 is pass, used by the not instruction
//which just moves the inverted register value.
if (SubOp < 3)
{
- ShaderIrNode OperB = GetAluNot(GetOperImm32_20(OpCode), Ib);
+ ShaderIrNode OperB = GetAluNot(GetOperImm32_20(OpCode), InvB);
ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB);
@@ -159,8 +204,8 @@ namespace Ryujinx.Graphics.Gal.Shader
{
int SubOp = (int)(OpCode >> 20) & 7;
- bool Aa = ((OpCode >> 46) & 1) != 0;
- bool Na = ((OpCode >> 48) & 1) != 0;
+ bool AbsA = ((OpCode >> 46) & 1) != 0;
+ bool NegA = ((OpCode >> 48) & 1) != 0;
ShaderIrInst Inst = 0;
@@ -178,11 +223,26 @@ namespace Ryujinx.Graphics.Gal.Shader
ShaderIrNode OperA = GetOperGpr8(OpCode);
- ShaderIrOp Op = new ShaderIrOp(Inst, GetAluAbsNeg(OperA, Aa, Na));
+ ShaderIrOp Op = new ShaderIrOp(Inst, GetAluFabsFneg(OperA, AbsA, NegA));
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
}
+ public static void Shl_C(ShaderIrBlock Block, long OpCode)
+ {
+ EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl);
+ }
+
+ public static void Shl_I(ShaderIrBlock Block, long OpCode)
+ {
+ EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Lsl);
+ }
+
+ public static void Shl_R(ShaderIrBlock Block, long OpCode)
+ {
+ EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Lsl);
+ }
+
public static void Shr_C(ShaderIrBlock Block, long OpCode)
{
EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode));
@@ -233,16 +293,16 @@ namespace Ryujinx.Graphics.Gal.Shader
ShaderOper Oper,
ShaderIrInst Inst)
{
- bool Nb = ((OpCode >> 45) & 1) != 0;
- bool Aa = ((OpCode >> 46) & 1) != 0;
- bool Na = ((OpCode >> 48) & 1) != 0;
- bool Ab = ((OpCode >> 49) & 1) != 0;
+ bool NegB = ((OpCode >> 45) & 1) != 0;
+ bool AbsA = ((OpCode >> 46) & 1) != 0;
+ bool NegA = ((OpCode >> 48) & 1) != 0;
+ bool AbsB = ((OpCode >> 49) & 1) != 0;
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
if (Inst == ShaderIrInst.Fadd)
{
- OperA = GetAluAbsNeg(OperA, Aa, Na);
+ OperA = GetAluFabsFneg(OperA, AbsA, NegA);
}
switch (Oper)
@@ -254,17 +314,73 @@ namespace Ryujinx.Graphics.Gal.Shader
default: throw new ArgumentException(nameof(Oper));
}
- OperB = GetAluAbsNeg(OperB, Ab, Nb);
+ OperB = GetAluFabsFneg(OperB, AbsB, NegB);
ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
}
- private static void EmitAluFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+ private static void EmitBfe(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
{
- bool Nb = ((OpCode >> 48) & 1) != 0;
- bool Nc = ((OpCode >> 49) & 1) != 0;
+ //TODO: Handle the case where position + length
+ //is greater than the word size, in this case the sign bit
+ //needs to be replicated to fill the remaining space.
+ bool NegB = ((OpCode >> 48) & 1) != 0;
+ bool NegA = ((OpCode >> 49) & 1) != 0;
+
+ ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
+
+ switch (Oper)
+ {
+ case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
+ case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break;
+ case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
+
+ default: throw new ArgumentException(nameof(Oper));
+ }
+
+ ShaderIrNode Op;
+
+ bool Signed = ((OpCode >> 48) & 1) != 0; //?
+
+ if (OperB is ShaderIrOperImm PosLen)
+ {
+ int Position = (PosLen.Value >> 0) & 0xff;
+ int Length = (PosLen.Value >> 8) & 0xff;
+
+ int LSh = 32 - (Position + Length);
+
+ ShaderIrInst RightShift = Signed
+ ? ShaderIrInst.Asr
+ : ShaderIrInst.Lsr;
+
+ Op = new ShaderIrOp(ShaderIrInst.Lsl, OperA, new ShaderIrOperImm(LSh));
+ Op = new ShaderIrOp(RightShift, Op, new ShaderIrOperImm(LSh + Position));
+ }
+ else
+ {
+ ShaderIrOperImm Shift = new ShaderIrOperImm(8);
+ ShaderIrOperImm Mask = new ShaderIrOperImm(0xff);
+
+ ShaderIrNode OpPos, OpLen;
+
+ OpPos = new ShaderIrOp(ShaderIrInst.And, OperB, Mask);
+ OpLen = new ShaderIrOp(ShaderIrInst.Lsr, OperB, Shift);
+ OpLen = new ShaderIrOp(ShaderIrInst.And, OpLen, Mask);
+
+ Op = new ShaderIrOp(ShaderIrInst.Lsr, OperA, OpPos);
+
+ Op = ExtendTo32(Op, Signed, OpLen);
+ }
+
+ Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
+ }
+
+ private static void EmitFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+ {
+ bool NegB = ((OpCode >> 48) & 1) != 0;
+ bool NegC = ((OpCode >> 49) & 1) != 0;
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB, OperC;
@@ -278,15 +394,15 @@ namespace Ryujinx.Graphics.Gal.Shader
default: throw new ArgumentException(nameof(Oper));
}
- OperB = GetAluNeg(OperB, Nb);
+ OperB = GetAluFneg(OperB, NegB);
if (Oper == ShaderOper.RC)
{
- OperC = GetAluNeg(GetOperCbuf34(OpCode), Nc);
+ OperC = GetAluFneg(GetOperCbuf34(OpCode), NegC);
}
else
{
- OperC = GetAluNeg(GetOperGpr39(OpCode), Nc);
+ OperC = GetAluFneg(GetOperGpr39(OpCode), NegC);
}
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ffma, OperA, OperB, OperC);
@@ -294,6 +410,84 @@ namespace Ryujinx.Graphics.Gal.Shader
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
}
+ private static void EmitFmnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+ {
+ bool NegB = ((OpCode >> 45) & 1) != 0;
+ bool AbsA = ((OpCode >> 46) & 1) != 0;
+ bool NegA = ((OpCode >> 48) & 1) != 0;
+ bool AbsB = ((OpCode >> 49) & 1) != 0;
+
+ ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
+
+ OperA = GetAluFabsFneg(OperA, AbsA, NegA);
+
+ switch (Oper)
+ {
+ case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
+ case ShaderOper.Immf: OperB = GetOperImmf19_20(OpCode); break;
+ case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
+
+ default: throw new ArgumentException(nameof(Oper));
+ }
+
+ OperB = GetAluFabsFneg(OperB, AbsB, NegB);
+
+ ShaderIrOperPred Pred = GetOperPred39(OpCode);
+
+ ShaderIrOp Op;
+
+ if (Pred.IsConst)
+ {
+ bool IsMax = ((OpCode >> 42) & 1) != 0;
+
+ Op = new ShaderIrOp(IsMax
+ ? ShaderIrInst.Fmax
+ : ShaderIrInst.Fmin, OperA, OperB);
+
+ Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
+ }
+ else
+ {
+ ShaderIrNode PredN = GetOperPred39N(OpCode);
+
+ ShaderIrOp OpMax = new ShaderIrOp(ShaderIrInst.Fmax, OperA, OperB);
+ ShaderIrOp OpMin = new ShaderIrOp(ShaderIrInst.Fmin, OperA, OperB);
+
+ ShaderIrAsg AsgMax = new ShaderIrAsg(GetOperGpr0(OpCode), OpMax);
+ ShaderIrAsg AsgMin = new ShaderIrAsg(GetOperGpr0(OpCode), OpMin);
+
+ Block.AddNode(GetPredNode(new ShaderIrCond(PredN, AsgMax, Not: true), OpCode));
+ Block.AddNode(GetPredNode(new ShaderIrCond(PredN, AsgMin, Not: false), OpCode));
+ }
+ }
+
+ private static void EmitIscadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+ {
+ bool NegB = ((OpCode >> 48) & 1) != 0;
+ bool NegA = ((OpCode >> 49) & 1) != 0;
+
+ ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
+
+ ShaderIrOperImm Scale = GetOperImm5_39(OpCode);
+
+ switch (Oper)
+ {
+ case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
+ case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break;
+ case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
+
+ default: throw new ArgumentException(nameof(Oper));
+ }
+
+ OperA = GetAluIneg(OperA, NegA);
+ OperB = GetAluIneg(OperB, NegB);
+
+ ShaderIrOp ScaleOp = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Scale);
+ ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, OperB, ScaleOp);
+
+ Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), AddOp), OpCode));
+ }
+
private static void EmitFset(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
{
EmitSet(Block, OpCode, true, Oper);
@@ -306,10 +500,11 @@ namespace Ryujinx.Graphics.Gal.Shader
private static void EmitSet(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
{
- bool Na = ((OpCode >> 43) & 1) != 0;
- bool Ab = ((OpCode >> 44) & 1) != 0;
- bool Nb = ((OpCode >> 53) & 1) != 0;
- bool Aa = ((OpCode >> 54) & 1) != 0;
+ bool NegA = ((OpCode >> 43) & 1) != 0;
+ bool AbsB = ((OpCode >> 44) & 1) != 0;
+ bool BoolFloat = ((OpCode >> 52) & 1) != 0;
+ bool NegB = ((OpCode >> 53) & 1) != 0;
+ bool AbsA = ((OpCode >> 54) & 1) != 0;
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
@@ -327,8 +522,8 @@ namespace Ryujinx.Graphics.Gal.Shader
if (IsFloat)
{
- OperA = GetAluAbsNeg(OperA, Aa, Na);
- OperB = GetAluAbsNeg(OperB, Ab, Nb);
+ OperA = GetAluFabsFneg(OperA, AbsA, NegA);
+ OperB = GetAluFabsFneg(OperB, AbsB, NegB);
CmpInst = GetCmpF(OpCode);
}
@@ -343,8 +538,18 @@ namespace Ryujinx.Graphics.Gal.Shader
ShaderIrOperPred PNode = GetOperPred39(OpCode);
- ShaderIrOperImmf Imm0 = new ShaderIrOperImmf(0);
- ShaderIrOperImmf Imm1 = new ShaderIrOperImmf(1);
+ ShaderIrNode Imm0, Imm1;
+
+ if (BoolFloat)
+ {
+ Imm0 = new ShaderIrOperImmf(0);
+ Imm1 = new ShaderIrOperImmf(1);
+ }
+ else
+ {
+ Imm0 = new ShaderIrOperImm(0);
+ Imm1 = new ShaderIrOperImm(-1);
+ }
ShaderIrNode Asg0 = new ShaderIrAsg(GetOperGpr0(OpCode), Imm0);
ShaderIrNode Asg1 = new ShaderIrAsg(GetOperGpr0(OpCode), Imm1);
@@ -378,10 +583,10 @@ namespace Ryujinx.Graphics.Gal.Shader
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;
- bool Ab = ((OpCode >> 44) & 1) != 0;
+ bool AbsA = ((OpCode >> 7) & 1) != 0;
+ bool NegP = ((OpCode >> 42) & 1) != 0;
+ bool NegA = ((OpCode >> 43) & 1) != 0;
+ bool AbsB = ((OpCode >> 44) & 1) != 0;
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
@@ -399,8 +604,8 @@ namespace Ryujinx.Graphics.Gal.Shader
if (IsFloat)
{
- OperA = GetAluAbsNeg(OperA, Aa, Na);
- OperB = GetAluAbs (OperB, Ab);
+ OperA = GetAluFabsFneg(OperA, AbsA, NegA);
+ OperB = GetAluFabs (OperB, AbsB);
CmpInst = GetCmpF(OpCode);
}
@@ -426,7 +631,7 @@ namespace Ryujinx.Graphics.Gal.Shader
ShaderIrNode P2NNode = P2Node;
- if (Np)
+ if (NegP)
{
P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode);
}
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs
index d3feb92e..b5f3e0b7 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs
@@ -1,9 +1,27 @@
+using System;
+
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
namespace Ryujinx.Graphics.Gal.Shader
{
static partial class ShaderDecode
{
+ public static void Bra(ShaderIrBlock Block, long OpCode)
+ {
+ if ((OpCode & 0x20) != 0)
+ {
+ //This reads the target offset from the constant buffer.
+ //Almost impossible to support with GLSL.
+ throw new NotImplementedException();
+ }
+
+ int Target = ((int)(OpCode >> 20) << 8) >> 8;
+
+ Target += Block.Position + 8;
+
+ Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Bra, Block.GetLabel(Target)), OpCode));
+ }
+
public static void Exit(ShaderIrBlock Block, long OpCode)
{
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Exit), OpCode));
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
index efbce20f..73775cca 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
@@ -35,6 +35,13 @@ namespace Ryujinx.Graphics.Gal.Shader
(int)(OpCode >> 20) & 0x3fff);
}
+ public static ShaderIrOperCbuf GetOperCbuf36(long OpCode)
+ {
+ return new ShaderIrOperCbuf(
+ (int)(OpCode >> 36) & 0x1f,
+ (int)(OpCode >> 22) & 0x3fff, GetOperGpr8(OpCode));
+ }
+
public static ShaderIrOperGpr GetOperGpr8(long OpCode)
{
return new ShaderIrOperGpr((int)(OpCode >> 8) & 0xff);
@@ -60,6 +67,11 @@ namespace Ryujinx.Graphics.Gal.Shader
return new ShaderIrOperGpr((int)(OpCode >> 28) & 0xff);
}
+ public static ShaderIrOperImm GetOperImm5_39(long OpCode)
+ {
+ return new ShaderIrOperImm((int)(OpCode >> 39) & 0x1f);
+ }
+
public static ShaderIrOperImm GetOperImm13_36(long OpCode)
{
return new ShaderIrOperImm((int)(OpCode >> 36) & 0x1fff);
@@ -210,24 +222,69 @@ namespace Ryujinx.Graphics.Gal.Shader
return new ShaderIrOperPred(Pred);
}
- public static ShaderIrNode GetAluAbsNeg(ShaderIrNode Node, bool Abs, bool Neg)
+ public static ShaderIrNode GetAluFabsFneg(ShaderIrNode Node, bool Abs, bool Neg)
{
- return GetAluNeg(GetAluAbs(Node, Abs), Neg);
+ return GetAluFneg(GetAluFabs(Node, Abs), Neg);
}
- public static ShaderIrNode GetAluAbs(ShaderIrNode Node, bool Abs)
+ public static ShaderIrNode GetAluFabs(ShaderIrNode Node, bool Abs)
{
return Abs ? new ShaderIrOp(ShaderIrInst.Fabs, Node) : Node;
}
- public static ShaderIrNode GetAluNeg(ShaderIrNode Node, bool Neg)
+ public static ShaderIrNode GetAluFneg(ShaderIrNode Node, bool Neg)
{
return Neg ? new ShaderIrOp(ShaderIrInst.Fneg, Node) : Node;
}
+ public static ShaderIrNode GetAluIabsIneg(ShaderIrNode Node, bool Abs, bool Neg)
+ {
+ return GetAluIneg(GetAluIabs(Node, Abs), Neg);
+ }
+
+ public static ShaderIrNode GetAluIabs(ShaderIrNode Node, bool Abs)
+ {
+ return Abs ? new ShaderIrOp(ShaderIrInst.Abs, Node) : Node;
+ }
+
+ public static ShaderIrNode GetAluIneg(ShaderIrNode Node, bool Neg)
+ {
+ return Neg ? new ShaderIrOp(ShaderIrInst.Neg, Node) : Node;
+ }
+
public static ShaderIrNode GetAluNot(ShaderIrNode Node, bool Not)
{
return Not ? new ShaderIrOp(ShaderIrInst.Not, Node) : Node;
}
+
+ public static ShaderIrNode ExtendTo32(ShaderIrNode Node, bool Signed, int Size)
+ {
+ int Shift = 32 - Size;
+
+ ShaderIrInst RightShift = Signed
+ ? ShaderIrInst.Asr
+ : ShaderIrInst.Lsr;
+
+ Node = new ShaderIrOp(ShaderIrInst.Lsl, Node, new ShaderIrOperImm(Shift));
+ Node = new ShaderIrOp(RightShift, Node, new ShaderIrOperImm(Shift));
+
+ return Node;
+ }
+
+ public static ShaderIrNode ExtendTo32(ShaderIrNode Node, bool Signed, ShaderIrNode Size)
+ {
+ ShaderIrOperImm WordSize = new ShaderIrOperImm(32);
+
+ ShaderIrOp Shift = new ShaderIrOp(ShaderIrInst.Sub, WordSize, Size);
+
+ ShaderIrInst RightShift = Signed
+ ? ShaderIrInst.Asr
+ : ShaderIrInst.Lsr;
+
+ Node = new ShaderIrOp(ShaderIrInst.Lsl, Node, Shift);
+ Node = new ShaderIrOp(RightShift, Node, Shift);
+
+ return Node;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
index 24a61c0c..5ca485a3 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
@@ -1,3 +1,5 @@
+using System;
+
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
namespace Ryujinx.Graphics.Gal.Shader
@@ -20,6 +22,41 @@ namespace Ryujinx.Graphics.Gal.Shader
}
}
+ public static void Ld_C(ShaderIrBlock Block, long OpCode)
+ {
+ int Type = (int)(OpCode >> 48) & 7;
+
+ if (Type > 5)
+ {
+ throw new InvalidOperationException();
+ }
+
+ int Count = Type == 5 ? 2 : 1;
+
+ for (int Index = 0; Index < Count; Index++)
+ {
+ ShaderIrOperCbuf OperA = GetOperCbuf36(OpCode);
+ ShaderIrOperGpr OperD = GetOperGpr0 (OpCode);
+
+ OperA.Pos += Index;
+ OperD.Index += Index;
+
+ ShaderIrNode Node = OperA;
+
+ if (Type < 4)
+ {
+ //This is a 8 or 16 bits type.
+ bool Signed = (Type & 1) != 0;
+
+ int Size = 8 << (Type >> 1);
+
+ Node = ExtendTo32(Node, Signed, Size);
+ }
+
+ Block.AddNode(GetPredNode(new ShaderIrAsg(OperD, Node), OpCode));
+ }
+ }
+
public static void St_A(ShaderIrBlock Block, long OpCode)
{
ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
index b9cf02f1..dfcea905 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
@@ -99,24 +99,24 @@ namespace Ryujinx.Graphics.Gal.Shader
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
}
- public static void Mov_R(ShaderIrBlock Block, long OpCode)
+ public static void Mov_I32(ShaderIrBlock Block, long OpCode)
{
- ShaderIrOperGpr Gpr = GetOperGpr20(OpCode);
+ ShaderIrOperImm Imm = GetOperImm32_20(OpCode);
- Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Gpr), OpCode));
+ Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
}
- public static void Mov32i(ShaderIrBlock Block, long OpCode)
+ public static void Mov_R(ShaderIrBlock Block, long OpCode)
{
- ShaderIrOperImm Imm = GetOperImm32_20(OpCode);
+ ShaderIrOperGpr Gpr = GetOperGpr20(OpCode);
- Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
+ Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Gpr), OpCode));
}
private static void EmitF2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
{
- bool Na = ((OpCode >> 45) & 1) != 0;
- bool Aa = ((OpCode >> 49) & 1) != 0;
+ bool NegA = ((OpCode >> 45) & 1) != 0;
+ bool AbsA = ((OpCode >> 49) & 1) != 0;
ShaderIrNode OperA;
@@ -129,7 +129,7 @@ namespace Ryujinx.Graphics.Gal.Shader
default: throw new ArgumentException(nameof(Oper));
}
- OperA = GetAluAbsNeg(OperA, Aa, Na);
+ OperA = GetAluFabsFneg(OperA, AbsA, NegA);
ShaderIrInst RoundInst = GetRoundInst(OpCode);
@@ -153,8 +153,8 @@ namespace Ryujinx.Graphics.Gal.Shader
throw new NotImplementedException();
}
- bool Na = ((OpCode >> 45) & 1) != 0;
- bool Aa = ((OpCode >> 49) & 1) != 0;
+ bool NegA = ((OpCode >> 45) & 1) != 0;
+ bool AbsA = ((OpCode >> 49) & 1) != 0;
ShaderIrNode OperA;
@@ -167,7 +167,7 @@ namespace Ryujinx.Graphics.Gal.Shader
default: throw new ArgumentException(nameof(Oper));
}
- OperA = GetAluAbsNeg(OperA, Aa, Na);
+ OperA = GetAluFabsFneg(OperA, AbsA, NegA);
ShaderIrInst RoundInst = GetRoundInst(OpCode);
@@ -224,8 +224,8 @@ namespace Ryujinx.Graphics.Gal.Shader
int Sel = (int)(OpCode >> 41) & 3;
- bool Na = ((OpCode >> 45) & 1) != 0;
- bool Aa = ((OpCode >> 49) & 1) != 0;
+ bool NegA = ((OpCode >> 45) & 1) != 0;
+ bool AbsA = ((OpCode >> 49) & 1) != 0;
ShaderIrNode OperA;
@@ -238,7 +238,7 @@ namespace Ryujinx.Graphics.Gal.Shader
default: throw new ArgumentException(nameof(Oper));
}
- OperA = GetAluAbsNeg(OperA, Aa, Na);
+ OperA = GetAluIabsIneg(OperA, AbsA, NegA);
bool Signed = Type >= IntType.S8;
@@ -253,9 +253,7 @@ namespace Ryujinx.Graphics.Gal.Shader
if (Size < 32)
{
- uint Mask = uint.MaxValue >> (32 - Size);
-
- OperA = new ShaderIrOp(ShaderIrInst.And, OperA, new ShaderIrOperImm((int)Mask));
+ OperA = ExtendTo32(OperA, Signed, Size);
}
ShaderIrInst Inst = Signed
@@ -296,7 +294,7 @@ namespace Ryujinx.Graphics.Gal.Shader
default: throw new ArgumentException(nameof(Oper));
}
- OperA = GetAluAbsNeg(OperA, AbsA, NegA);
+ OperA = GetAluIabsIneg(OperA, AbsA, NegA);
bool Signed = Type >= IntType.S8;
@@ -335,7 +333,7 @@ namespace Ryujinx.Graphics.Gal.Shader
}
else
{
- OperA = new ShaderIrOp(ShaderIrInst.And, OperA, new ShaderIrOperImm((int)Mask));
+ OperA = ExtendTo32(OperA, Signed, Size);
}
}
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
index e44d5b7d..4958dfcf 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
@@ -2,14 +2,21 @@ namespace Ryujinx.Graphics.Gal.Shader
{
static class ShaderDecoder
{
+ private const bool AddDbgComments = true;
+
public static ShaderIrBlock DecodeBasicBlock(int[] Code, int Offset)
{
ShaderIrBlock Block = new ShaderIrBlock();
while (Offset + 2 <= Code.Length)
{
- //Ignore scheduling instructions, which are
- //written every 32 bytes.
+ int InstPos = Offset * 4;
+
+ Block.Position = InstPos;
+
+ Block.MarkLabel(InstPos);
+
+ //Ignore scheduling instructions, which are written every 32 bytes.
if ((Offset & 7) == 0)
{
Offset += 2;
@@ -24,6 +31,13 @@ namespace Ryujinx.Graphics.Gal.Shader
ShaderDecodeFunc Decode = ShaderOpCodeTable.GetDecoder(OpCode);
+ if (AddDbgComments)
+ {
+ string DbgOpCode = $"0x{InstPos:x8}: 0x{OpCode:x16} ";
+
+ Block.AddNode(new ShaderIrCmnt(DbgOpCode + (Decode?.Method.Name ?? "???")));
+ }
+
if (Decode == null)
{
continue;
@@ -31,7 +45,7 @@ namespace Ryujinx.Graphics.Gal.Shader
Decode(Block, OpCode);
- if (Block.GetLastNode() is ShaderIrOp Op && IsFlowChange(Op.Inst))
+ if (Block.GetLastNode() is ShaderIrOp Op && Op.Inst == ShaderIrInst.Exit)
{
break;
}
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs
index c920d9fa..5f365d8c 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs
@@ -6,9 +6,15 @@ namespace Ryujinx.Graphics.Gal.Shader
{
private List<ShaderIrNode> Nodes;
+ private Dictionary<int, ShaderIrLabel> LabelsToInsert;
+
+ public int Position;
+
public ShaderIrBlock()
{
Nodes = new List<ShaderIrNode>();
+
+ LabelsToInsert = new Dictionary<int, ShaderIrLabel>();
}
public void AddNode(ShaderIrNode Node)
@@ -16,6 +22,28 @@ namespace Ryujinx.Graphics.Gal.Shader
Nodes.Add(Node);
}
+ public ShaderIrLabel GetLabel(int Position)
+ {
+ if (LabelsToInsert.TryGetValue(Position, out ShaderIrLabel Label))
+ {
+ return Label;
+ }
+
+ Label = new ShaderIrLabel();
+
+ LabelsToInsert.Add(Position, Label);
+
+ return Label;
+ }
+
+ public void MarkLabel(int Position)
+ {
+ if (LabelsToInsert.TryGetValue(Position, out ShaderIrLabel Label))
+ {
+ Nodes.Add(Label);
+ }
+ }
+
public ShaderIrNode[] GetNodes()
{
return Nodes.ToArray();
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs
new file mode 100644
index 00000000..03031ec5
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Graphics.Gal.Shader
+{
+ class ShaderIrCmnt : ShaderIrNode
+ {
+ public string Comment { get; private set; }
+
+ public ShaderIrCmnt(string Comment)
+ {
+ this.Comment = Comment;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
index ce2b98fe..af2ccc3b 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
@@ -36,6 +36,8 @@ namespace Ryujinx.Graphics.Gal.Shader
Ffma,
Flg2,
Floor,
+ Fmax,
+ Fmin,
Fmul,
Fneg,
Frcp,
@@ -49,6 +51,8 @@ namespace Ryujinx.Graphics.Gal.Shader
F_End,
I_Start,
+ Abs,
+ Add,
And,
Asr,
Ceq,
@@ -59,16 +63,21 @@ namespace Ryujinx.Graphics.Gal.Shader
Cle,
Clt,
Cne,
+ Lsl,
Lsr,
+ Mul,
+ Neg,
Not,
Or,
Stof,
+ Sub,
Texq,
Txlf,
Utof,
Xor,
I_End,
+ Bra,
Exit,
Kil
}
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrLabel.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrLabel.cs
new file mode 100644
index 00000000..f5b3585a
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrLabel.cs
@@ -0,0 +1,4 @@
+namespace Ryujinx.Graphics.Gal.Shader
+{
+ class ShaderIrLabel : ShaderIrNode { }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs
index f2272056..b040c5c6 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs
@@ -3,11 +3,14 @@ namespace Ryujinx.Graphics.Gal.Shader
class ShaderIrOperCbuf : ShaderIrNode
{
public int Index { get; private set; }
- public int Offs { get; private set; }
+ public int Pos { get; set; }
- public ShaderIrOperCbuf(int Index, int Offs)
+ public ShaderIrNode Offs { get; private set; }
+
+ public ShaderIrOperCbuf(int Index, int Pos, ShaderIrNode Offs = null)
{
this.Index = Index;
+ this.Pos = Pos;
this.Offs = Offs;
}
}
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
index 65e24928..acfcc147 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
@@ -26,6 +26,10 @@ namespace Ryujinx.Graphics.Gal.Shader
OpCodes = new ShaderDecodeEntry[1 << EncodingBits];
#region Instructions
+ Set("0100110000000x", ShaderDecode.Bfe_C);
+ Set("0011100x00000x", ShaderDecode.Bfe_I);
+ Set("0101110000000x", ShaderDecode.Bfe_R);
+ Set("111000100100xx", ShaderDecode.Bra);
Set("111000110000xx", ShaderDecode.Exit);
Set("0100110010101x", ShaderDecode.F2f_C);
Set("0011100x10101x", ShaderDecode.F2f_I);
@@ -40,10 +44,13 @@ namespace Ryujinx.Graphics.Gal.Shader
Set("001100101xxxxx", ShaderDecode.Ffma_I);
Set("010100011xxxxx", ShaderDecode.Ffma_RC);
Set("010110011xxxxx", ShaderDecode.Ffma_RR);
- Set("00011110xxxxxx", ShaderDecode.Fmul32i);
+ Set("00011110xxxxxx", ShaderDecode.Fmul_I32);
Set("0100110001101x", ShaderDecode.Fmul_C);
Set("0011100x01101x", ShaderDecode.Fmul_I);
Set("0101110001101x", ShaderDecode.Fmul_R);
+ Set("0100110001100x", ShaderDecode.Fmnmx_C);
+ Set("0011100x01100x", ShaderDecode.Fmnmx_I);
+ Set("0101110001100x", ShaderDecode.Fmnmx_R);
Set("0100100xxxxxxx", ShaderDecode.Fset_C);
Set("0011000xxxxxxx", ShaderDecode.Fset_I);
Set("01011000xxxxxx", ShaderDecode.Fset_R);
@@ -57,17 +64,24 @@ namespace Ryujinx.Graphics.Gal.Shader
Set("0011100x11100x", ShaderDecode.I2i_I);
Set("0101110011100x", ShaderDecode.I2i_R);
Set("11100000xxxxxx", ShaderDecode.Ipa);
+ Set("0100110000011x", ShaderDecode.Iscadd_C);
+ Set("0011100x00011x", ShaderDecode.Iscadd_I);
+ Set("0101110000011x", ShaderDecode.Iscadd_R);
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("1110111110010x", ShaderDecode.Ld_C);
+ Set("000001xxxxxxxx", ShaderDecode.Lop_I32);
Set("0100110010011x", ShaderDecode.Mov_C);
Set("0011100x10011x", ShaderDecode.Mov_I);
+ Set("000000010000xx", ShaderDecode.Mov_I32);
Set("0101110010011x", ShaderDecode.Mov_R);
- Set("000000010000xx", ShaderDecode.Mov32i);
Set("0101000010000x", ShaderDecode.Mufu);
+ Set("0100110001001x", ShaderDecode.Shl_C);
+ Set("0011100x01001x", ShaderDecode.Shl_I);
+ Set("0101110001001x", ShaderDecode.Shl_R);
Set("0100110000101x", ShaderDecode.Shr_C);
Set("0011100x00101x", ShaderDecode.Shr_I);
Set("0101110000101x", ShaderDecode.Shr_R);
diff --git a/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs b/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs
index d400850c..e5ecee95 100644
--- a/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs
+++ b/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs
@@ -23,5 +23,13 @@ namespace Ryujinx.Graphics.Gal
Size = NewSize;
}
}
+
+ internal void SetCbufOffs(int Offs)
+ {
+ if (Index < Offs)
+ {
+ Index = Offs;
+ }
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.sln b/Ryujinx.sln
index 036421f9..213f7386 100644
--- a/Ryujinx.sln
+++ b/Ryujinx.sln
@@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics", "Ryujinx
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "Ryujinx.Audio\Ryujinx.Audio.csproj", "{5C1D818E-682A-46A5-9D54-30006E26C270}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryushader", "Ryushader\Ryushader.csproj", "{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -45,6 +47,10 @@ Global
{5C1D818E-682A-46A5-9D54-30006E26C270}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5C1D818E-682A-46A5-9D54-30006E26C270}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5C1D818E-682A-46A5-9D54-30006E26C270}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Ryushader/Program.cs b/Ryushader/Program.cs
new file mode 100644
index 00000000..21eb3d79
--- /dev/null
+++ b/Ryushader/Program.cs
@@ -0,0 +1,48 @@
+using Ryujinx.Graphics.Gal;
+using Ryujinx.Graphics.Gal.Shader;
+using System;
+using System.IO;
+
+namespace Ryushader
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ if (args.Length == 2)
+ {
+ GlslDecompiler Decompiler = new GlslDecompiler();
+
+ GalShaderType ShaderType = GalShaderType.Vertex;
+
+ switch (args[0].ToLower())
+ {
+ case "v": ShaderType = GalShaderType.Vertex; break;
+ case "tc": ShaderType = GalShaderType.TessControl; break;
+ case "te": ShaderType = GalShaderType.TessEvaluation; break;
+ case "g": ShaderType = GalShaderType.Geometry; break;
+ case "f": ShaderType = GalShaderType.Fragment; break;
+ }
+
+ byte[] Data = File.ReadAllBytes(args[1]);
+
+ int[] Code = new int[Data.Length / 4];
+
+ for (int Offset = 0; Offset < Data.Length; Offset += 4)
+ {
+ int Value = BitConverter.ToInt32(Data, Offset);
+
+ Code[Offset >> 2] = Value;
+ }
+
+ GlslProgram Program = Decompiler.Decompile(Code, ShaderType);
+
+ Console.WriteLine(Program.Code);
+ }
+ else
+ {
+ Console.WriteLine("Usage: Ryushader [v|tc|te|g|f] shader.bin");
+ }
+ }
+ }
+}
diff --git a/Ryushader/Ryushader.csproj b/Ryushader/Ryushader.csproj
new file mode 100644
index 00000000..9eeee2ba
--- /dev/null
+++ b/Ryushader/Ryushader.csproj
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <ItemGroup>
+ <ProjectReference Include="..\Ryujinx.Graphics\Ryujinx.Graphics.csproj" />
+ </ItemGroup>
+
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>netcoreapp2.1</TargetFramework>
+ </PropertyGroup>
+
+</Project>