mirror of
https://github.com/GreemDev/Ryujinx.git
synced 2024-12-22 22:45:46 +00:00
Added more shader instructions, including BFE, BRA (partial), FMNMX, ISCADD, SHL, LD_C, some shader related fixes, added support for texture component selection
This commit is contained in:
parent
9b9ead94cd
commit
b19c474082
28 changed files with 806 additions and 118 deletions
|
@ -11,6 +11,11 @@ namespace Ryujinx.Core.Gpu
|
||||||
|
|
||||||
GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);
|
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];
|
long TextureAddress = (uint)Tic[1];
|
||||||
|
|
||||||
TextureAddress |= (long)((ushort)Tic[2]) << 32;
|
TextureAddress |= (long)((ushort)Tic[2]) << 32;
|
||||||
|
@ -37,7 +42,15 @@ namespace Ryujinx.Core.Gpu
|
||||||
|
|
||||||
byte[] Data = TextureReader.Read(Vmm, Texture);
|
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)
|
public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition)
|
||||||
|
|
|
@ -141,6 +141,13 @@ namespace Ryujinx.Core.OsHle.Kernel
|
||||||
|
|
||||||
private void SvcSetThreadCoreMask(AThreadState ThreadState)
|
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 Handle = (int)ThreadState.X0;
|
||||||
int IdealCore = (int)ThreadState.X1;
|
int IdealCore = (int)ThreadState.X1;
|
||||||
long CoreMask = (long)ThreadState.X2;
|
long CoreMask = (long)ThreadState.X2;
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace Ryujinx.Core.OsHle.Services.Nifm
|
||||||
{ 2, GetSystemEventReadableHandles },
|
{ 2, GetSystemEventReadableHandles },
|
||||||
{ 3, Cancel },
|
{ 3, Cancel },
|
||||||
{ 4, Submit },
|
{ 4, Submit },
|
||||||
|
{ 11, SetConnectionConfirmationOption }
|
||||||
};
|
};
|
||||||
|
|
||||||
Event = new KEvent();
|
Event = new KEvent();
|
||||||
|
@ -69,6 +70,13 @@ namespace Ryujinx.Core.OsHle.Services.Nifm
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long SetConnectionConfirmationOption(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
Context.Ns.Log.PrintStub(LogClass.ServiceNifm, "Stubbed.");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Ryujinx.Core.Logging;
|
||||||
using Ryujinx.Core.OsHle.Ipc;
|
using Ryujinx.Core.OsHle.Ipc;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
@ -13,8 +14,15 @@ namespace Ryujinx.Core.OsHle.Services.Prepo
|
||||||
{
|
{
|
||||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||||
{
|
{
|
||||||
//...
|
{ 10101, SaveReportWithUser }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long SaveReportWithUser(ServiceCtx Context)
|
||||||
|
{
|
||||||
|
Context.Ns.Log.PrintStub(LogClass.ServicePrepo, "Stubbed.");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,12 +9,29 @@ namespace Ryujinx.Graphics.Gal
|
||||||
|
|
||||||
public GalTextureFormat Format;
|
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.Data = Data;
|
||||||
this.Width = Width;
|
this.Width = Width;
|
||||||
this.Height = Height;
|
this.Height = Height;
|
||||||
this.Format = Format;
|
this.Format = Format;
|
||||||
|
this.XSource = XSource;
|
||||||
|
this.YSource = YSource;
|
||||||
|
this.ZSource = ZSource;
|
||||||
|
this.WSource = WSource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
13
Ryujinx.Graphics/Gal/GalTextureSource.cs
Normal file
13
Ryujinx.Graphics/Gal/GalTextureSource.cs
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -81,6 +81,22 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
throw new NotImplementedException(Format.ToString());
|
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)
|
public static TextureWrapMode GetTextureWrapMode(GalTextureWrap Wrap)
|
||||||
{
|
{
|
||||||
switch (Wrap)
|
switch (Wrap)
|
||||||
|
|
|
@ -87,10 +87,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public void Create(long Tag, GalShaderType Type, byte[] Data)
|
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);
|
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))
|
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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Type,
|
Type,
|
||||||
Texture.Data);
|
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)
|
public void Bind(int Index)
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private Dictionary<int, ShaderDeclInfo> m_Textures;
|
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_InAttributes;
|
||||||
private Dictionary<int, ShaderDeclInfo> m_OutAttributes;
|
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, 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> InAttributes => m_InAttributes;
|
||||||
public IReadOnlyDictionary<int, ShaderDeclInfo> OutAttributes => m_OutAttributes;
|
public IReadOnlyDictionary<int, ShaderDeclInfo> OutAttributes => m_OutAttributes;
|
||||||
|
@ -54,7 +54,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
StagePrefix = StagePrefixes[(int)ShaderType] + "_";
|
StagePrefix = StagePrefixes[(int)ShaderType] + "_";
|
||||||
|
|
||||||
m_Uniforms = new Dictionary<(int, int), ShaderDeclInfo>();
|
m_Uniforms = new Dictionary<int, ShaderDeclInfo>();
|
||||||
|
|
||||||
m_Textures = new Dictionary<int, ShaderDeclInfo>();
|
m_Textures = new Dictionary<int, ShaderDeclInfo>();
|
||||||
|
|
||||||
|
@ -124,11 +124,27 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
case ShaderIrOperCbuf Cbuf:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ using System.Text;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
class GlslDecompiler
|
public class GlslDecompiler
|
||||||
{
|
{
|
||||||
private delegate string GetInstExpr(ShaderIrOp Op);
|
private delegate string GetInstExpr(ShaderIrOp Op);
|
||||||
|
|
||||||
|
@ -31,6 +31,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
|
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
|
||||||
{
|
{
|
||||||
|
{ ShaderIrInst.Abs, GetAbsExpr },
|
||||||
|
{ ShaderIrInst.Add, GetAddExpr },
|
||||||
{ ShaderIrInst.And, GetAndExpr },
|
{ ShaderIrInst.And, GetAndExpr },
|
||||||
{ ShaderIrInst.Asr, GetAsrExpr },
|
{ ShaderIrInst.Asr, GetAsrExpr },
|
||||||
{ ShaderIrInst.Band, GetBandExpr },
|
{ ShaderIrInst.Band, GetBandExpr },
|
||||||
|
@ -45,8 +47,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{ ShaderIrInst.Clt, GetCltExpr },
|
{ ShaderIrInst.Clt, GetCltExpr },
|
||||||
{ ShaderIrInst.Cne, GetCneExpr },
|
{ ShaderIrInst.Cne, GetCneExpr },
|
||||||
{ ShaderIrInst.Exit, GetExitExpr },
|
{ ShaderIrInst.Exit, GetExitExpr },
|
||||||
{ ShaderIrInst.Fabs, GetFabsExpr },
|
{ ShaderIrInst.Fabs, GetAbsExpr },
|
||||||
{ ShaderIrInst.Fadd, GetFaddExpr },
|
{ ShaderIrInst.Fadd, GetAddExpr },
|
||||||
{ ShaderIrInst.Fceq, GetCeqExpr },
|
{ ShaderIrInst.Fceq, GetCeqExpr },
|
||||||
{ ShaderIrInst.Fcge, GetCgeExpr },
|
{ ShaderIrInst.Fcge, GetCgeExpr },
|
||||||
{ ShaderIrInst.Fcgt, GetCgtExpr },
|
{ ShaderIrInst.Fcgt, GetCgtExpr },
|
||||||
|
@ -59,8 +61,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{ ShaderIrInst.Ffma, GetFfmaExpr },
|
{ ShaderIrInst.Ffma, GetFfmaExpr },
|
||||||
{ ShaderIrInst.Flg2, GetFlg2Expr },
|
{ ShaderIrInst.Flg2, GetFlg2Expr },
|
||||||
{ ShaderIrInst.Floor, GetFloorExpr },
|
{ ShaderIrInst.Floor, GetFloorExpr },
|
||||||
{ ShaderIrInst.Fmul, GetFmulExpr },
|
{ ShaderIrInst.Fmax, GetFmaxExpr },
|
||||||
{ ShaderIrInst.Fneg, GetFnegExpr },
|
{ ShaderIrInst.Fmin, GetFminExpr },
|
||||||
|
{ ShaderIrInst.Fmul, GetMulExpr },
|
||||||
|
{ ShaderIrInst.Fneg, GetNegExpr },
|
||||||
{ ShaderIrInst.Frcp, GetFrcpExpr },
|
{ ShaderIrInst.Frcp, GetFrcpExpr },
|
||||||
{ ShaderIrInst.Frsq, GetFrsqExpr },
|
{ ShaderIrInst.Frsq, GetFrsqExpr },
|
||||||
{ ShaderIrInst.Fsin, GetFsinExpr },
|
{ ShaderIrInst.Fsin, GetFsinExpr },
|
||||||
|
@ -68,10 +72,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{ ShaderIrInst.Ftou, GetFtouExpr },
|
{ ShaderIrInst.Ftou, GetFtouExpr },
|
||||||
{ ShaderIrInst.Ipa, GetIpaExpr },
|
{ ShaderIrInst.Ipa, GetIpaExpr },
|
||||||
{ ShaderIrInst.Kil, GetKilExpr },
|
{ ShaderIrInst.Kil, GetKilExpr },
|
||||||
|
{ ShaderIrInst.Lsl, GetLslExpr },
|
||||||
{ ShaderIrInst.Lsr, GetLsrExpr },
|
{ ShaderIrInst.Lsr, GetLsrExpr },
|
||||||
|
{ ShaderIrInst.Mul, GetMulExpr },
|
||||||
|
{ ShaderIrInst.Neg, GetNegExpr },
|
||||||
{ ShaderIrInst.Not, GetNotExpr },
|
{ ShaderIrInst.Not, GetNotExpr },
|
||||||
{ ShaderIrInst.Or, GetOrExpr },
|
{ ShaderIrInst.Or, GetOrExpr },
|
||||||
{ ShaderIrInst.Stof, GetStofExpr },
|
{ ShaderIrInst.Stof, GetStofExpr },
|
||||||
|
{ ShaderIrInst.Sub, GetSubExpr },
|
||||||
{ ShaderIrInst.Texq, GetTexqExpr },
|
{ ShaderIrInst.Texq, GetTexqExpr },
|
||||||
{ ShaderIrInst.Texs, GetTexsExpr },
|
{ ShaderIrInst.Texs, GetTexsExpr },
|
||||||
{ ShaderIrInst.Trunc, GetTruncExpr },
|
{ ShaderIrInst.Trunc, GetTruncExpr },
|
||||||
|
@ -100,7 +108,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
PrintDeclGprs();
|
PrintDeclGprs();
|
||||||
PrintDeclPreds();
|
PrintDeclPreds();
|
||||||
|
|
||||||
PrintBlockScope("void main()", 1, Nodes);
|
PrintBlockScope(Nodes, 0, Nodes.Length, "void main()", 1);
|
||||||
|
|
||||||
string GlslCode = SB.ToString();
|
string GlslCode = SB.ToString();
|
||||||
|
|
||||||
|
@ -124,7 +132,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
foreach (ShaderDeclInfo DeclInfo in Decl.Uniforms.Values.OrderBy(DeclKeySelector))
|
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)
|
if (Decl.Uniforms.Count > 0)
|
||||||
|
@ -221,7 +229,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return ElemTypes[DeclInfo.Size - 1] + " " + DeclInfo.Name;
|
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;
|
string Identation = string.Empty;
|
||||||
|
|
||||||
|
@ -244,7 +257,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Identation += IdentationStr;
|
Identation += IdentationStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int Index = 0; Index < Nodes.Length; Index++)
|
for (int Index = Start; Index < Start + Count; Index++)
|
||||||
{
|
{
|
||||||
ShaderIrNode Node = Nodes[Index];
|
ShaderIrNode Node = Nodes[Index];
|
||||||
|
|
||||||
|
@ -257,9 +270,44 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
IfExpr = "!(" + IfExpr + ")";
|
IfExpr = "!(" + 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 + ")";
|
string SubScopeName = "if (" + IfExpr + ")";
|
||||||
|
|
||||||
PrintBlockScope(SubScopeName, IdentationLevel + 1, Cond.Child);
|
ShaderIrNode[] Child = new ShaderIrNode[] { Cond.Child };
|
||||||
|
|
||||||
|
PrintBlockScope(Child, 0, 1, SubScopeName, IdentationLevel + 1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (Node is ShaderIrAsg Asg)
|
else if (Node is ShaderIrAsg Asg)
|
||||||
{
|
{
|
||||||
|
@ -288,6 +336,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
|
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
|
else
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
|
@ -297,6 +353,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
SB.AppendLine(LastLine);
|
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)
|
private bool IsValidOutOper(ShaderIrNode Node)
|
||||||
{
|
{
|
||||||
if (Node is ShaderIrOperGpr Gpr && Gpr.IsConst)
|
if (Node is ShaderIrOperGpr Gpr && Gpr.IsConst)
|
||||||
|
@ -383,12 +454,23 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetName(ShaderIrOperCbuf Cbuf)
|
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();
|
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)
|
private string GetOutAbufName(ShaderIrOperAbuf Abuf)
|
||||||
|
@ -473,6 +555,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return "xyzw".Substring(Elem, 1);
|
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 GetAndExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "&");
|
||||||
|
|
||||||
private string GetAsrExpr(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 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 GetFcosExpr(ShaderIrOp Op) => GetUnaryCall(Op, "cos");
|
||||||
|
|
||||||
private string GetFex2Expr(ShaderIrOp Op) => GetUnaryCall(Op, "exp2");
|
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 GetFloorExpr(ShaderIrOp Op) => GetUnaryCall(Op, "floor");
|
||||||
|
|
||||||
private string GetFmulExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "*");
|
private string GetFmaxExpr(ShaderIrOp Op) => GetBinaryCall(Op, "max");
|
||||||
|
private string GetFminExpr(ShaderIrOp Op) => GetBinaryCall(Op, "min");
|
||||||
private string GetFnegExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "-");
|
|
||||||
|
|
||||||
private string GetFrcpExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "1 / ");
|
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 GetKilExpr(ShaderIrOp Op) => "discard";
|
||||||
|
|
||||||
|
private string GetLslExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<<");
|
||||||
private string GetLsrExpr(ShaderIrOp Op)
|
private string GetLsrExpr(ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
return "int(uint(" + GetOperExpr(Op, Op.OperandA) + ") >> " +
|
return "int(uint(" + GetOperExpr(Op, Op.OperandA) + ") >> " +
|
||||||
GetOperExpr(Op, Op.OperandB) + ")";
|
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 GetNotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "~");
|
||||||
|
|
||||||
private string GetOrExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "|");
|
private string GetOrExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "|");
|
||||||
|
@ -561,6 +647,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return "float(" + GetOperExpr(Op, Op.OperandA) + ")";
|
return "float(" + GetOperExpr(Op, Op.OperandA) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetSubExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "-");
|
||||||
|
|
||||||
private string GetTexqExpr(ShaderIrOp Op)
|
private string GetTexqExpr(ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
ShaderIrMetaTexq Meta = (ShaderIrMetaTexq)Op.MetaData;
|
ShaderIrMetaTexq Meta = (ShaderIrMetaTexq)Op.MetaData;
|
||||||
|
@ -621,6 +709,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ")";
|
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)
|
private string GetTernaryCall(ShaderIrOp Op, string FuncName)
|
||||||
{
|
{
|
||||||
return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ", " +
|
return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ", " +
|
||||||
|
@ -717,8 +811,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
float Value = BitConverter.Int32BitsToSingle(Imm.Value);
|
float Value = BitConverter.Int32BitsToSingle(Imm.Value);
|
||||||
|
|
||||||
|
if (!float.IsNaN(Value) && !float.IsInfinity(Value))
|
||||||
|
{
|
||||||
return Value.ToString(CultureInfo.InvariantCulture);
|
return Value.ToString(CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
struct GlslProgram
|
public struct GlslProgram
|
||||||
{
|
{
|
||||||
public string Code { get; private set; }
|
public string Code { get; private set; }
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
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)
|
public static void Fadd_C(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
EmitAluBinaryF(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fadd);
|
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)
|
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)
|
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)
|
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)
|
public static void Ffma_RR(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
EmitAluFfma(Block, OpCode, ShaderOper.RR);
|
EmitFfma(Block, OpCode, ShaderOper.RR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fmul32i(ShaderIrBlock Block, long OpCode)
|
public static void Fmnmx_C(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitFmnmx(Block, OpCode, ShaderOper.CR);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 OperA = GetOperGpr8 (OpCode);
|
||||||
ShaderIrNode OperB = GetOperImmf32_20(OpCode);
|
ShaderIrNode OperB = GetOperImmf32_20(OpCode);
|
||||||
|
@ -106,6 +136,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void 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)
|
public static void Isetp_C(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
EmitIsetp(Block, OpCode, ShaderOper.CR);
|
EmitIsetp(Block, OpCode, ShaderOper.CR);
|
||||||
|
@ -121,12 +166,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
EmitIsetp(Block, OpCode, ShaderOper.RR);
|
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;
|
int SubOp = (int)(OpCode >> 53) & 3;
|
||||||
|
|
||||||
bool Ia = ((OpCode >> 55) & 1) != 0;
|
bool InvA = ((OpCode >> 55) & 1) != 0;
|
||||||
bool Ib = ((OpCode >> 56) & 1) != 0;
|
bool InvB = ((OpCode >> 56) & 1) != 0;
|
||||||
|
|
||||||
ShaderIrInst Inst = 0;
|
ShaderIrInst Inst = 0;
|
||||||
|
|
||||||
|
@ -137,13 +182,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
case 2: Inst = ShaderIrInst.Xor; break;
|
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
|
//SubOp == 3 is pass, used by the not instruction
|
||||||
//which just moves the inverted register value.
|
//which just moves the inverted register value.
|
||||||
if (SubOp < 3)
|
if (SubOp < 3)
|
||||||
{
|
{
|
||||||
ShaderIrNode OperB = GetAluNot(GetOperImm32_20(OpCode), Ib);
|
ShaderIrNode OperB = GetAluNot(GetOperImm32_20(OpCode), InvB);
|
||||||
|
|
||||||
ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB);
|
ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB);
|
||||||
|
|
||||||
|
@ -159,8 +204,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
int SubOp = (int)(OpCode >> 20) & 7;
|
int SubOp = (int)(OpCode >> 20) & 7;
|
||||||
|
|
||||||
bool Aa = ((OpCode >> 46) & 1) != 0;
|
bool AbsA = ((OpCode >> 46) & 1) != 0;
|
||||||
bool Na = ((OpCode >> 48) & 1) != 0;
|
bool NegA = ((OpCode >> 48) & 1) != 0;
|
||||||
|
|
||||||
ShaderIrInst Inst = 0;
|
ShaderIrInst Inst = 0;
|
||||||
|
|
||||||
|
@ -178,11 +223,26 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
ShaderIrNode OperA = GetOperGpr8(OpCode);
|
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));
|
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)
|
public static void Shr_C(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode));
|
EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode));
|
||||||
|
@ -233,16 +293,16 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
ShaderOper Oper,
|
ShaderOper Oper,
|
||||||
ShaderIrInst Inst)
|
ShaderIrInst Inst)
|
||||||
{
|
{
|
||||||
bool Nb = ((OpCode >> 45) & 1) != 0;
|
bool NegB = ((OpCode >> 45) & 1) != 0;
|
||||||
bool Aa = ((OpCode >> 46) & 1) != 0;
|
bool AbsA = ((OpCode >> 46) & 1) != 0;
|
||||||
bool Na = ((OpCode >> 48) & 1) != 0;
|
bool NegA = ((OpCode >> 48) & 1) != 0;
|
||||||
bool Ab = ((OpCode >> 49) & 1) != 0;
|
bool AbsB = ((OpCode >> 49) & 1) != 0;
|
||||||
|
|
||||||
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
|
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
|
||||||
|
|
||||||
if (Inst == ShaderIrInst.Fadd)
|
if (Inst == ShaderIrInst.Fadd)
|
||||||
{
|
{
|
||||||
OperA = GetAluAbsNeg(OperA, Aa, Na);
|
OperA = GetAluFabsFneg(OperA, AbsA, NegA);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Oper)
|
switch (Oper)
|
||||||
|
@ -254,17 +314,73 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
OperB = GetAluAbsNeg(OperB, Ab, Nb);
|
OperB = GetAluFabsFneg(OperB, AbsB, NegB);
|
||||||
|
|
||||||
ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);
|
ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
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;
|
//TODO: Handle the case where position + length
|
||||||
bool Nc = ((OpCode >> 49) & 1) != 0;
|
//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;
|
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB, OperC;
|
||||||
|
|
||||||
|
@ -278,15 +394,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
OperB = GetAluNeg(OperB, Nb);
|
OperB = GetAluFneg(OperB, NegB);
|
||||||
|
|
||||||
if (Oper == ShaderOper.RC)
|
if (Oper == ShaderOper.RC)
|
||||||
{
|
{
|
||||||
OperC = GetAluNeg(GetOperCbuf34(OpCode), Nc);
|
OperC = GetAluFneg(GetOperCbuf34(OpCode), NegC);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OperC = GetAluNeg(GetOperGpr39(OpCode), Nc);
|
OperC = GetAluFneg(GetOperGpr39(OpCode), NegC);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ffma, OperA, OperB, OperC);
|
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));
|
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)
|
private static void EmitFset(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
EmitSet(Block, OpCode, true, 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)
|
private static void EmitSet(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
bool Na = ((OpCode >> 43) & 1) != 0;
|
bool NegA = ((OpCode >> 43) & 1) != 0;
|
||||||
bool Ab = ((OpCode >> 44) & 1) != 0;
|
bool AbsB = ((OpCode >> 44) & 1) != 0;
|
||||||
bool Nb = ((OpCode >> 53) & 1) != 0;
|
bool BoolFloat = ((OpCode >> 52) & 1) != 0;
|
||||||
bool Aa = ((OpCode >> 54) & 1) != 0;
|
bool NegB = ((OpCode >> 53) & 1) != 0;
|
||||||
|
bool AbsA = ((OpCode >> 54) & 1) != 0;
|
||||||
|
|
||||||
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
|
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
|
||||||
|
|
||||||
|
@ -327,8 +522,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (IsFloat)
|
if (IsFloat)
|
||||||
{
|
{
|
||||||
OperA = GetAluAbsNeg(OperA, Aa, Na);
|
OperA = GetAluFabsFneg(OperA, AbsA, NegA);
|
||||||
OperB = GetAluAbsNeg(OperB, Ab, Nb);
|
OperB = GetAluFabsFneg(OperB, AbsB, NegB);
|
||||||
|
|
||||||
CmpInst = GetCmpF(OpCode);
|
CmpInst = GetCmpF(OpCode);
|
||||||
}
|
}
|
||||||
|
@ -343,8 +538,18 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
ShaderIrOperPred PNode = GetOperPred39(OpCode);
|
ShaderIrOperPred PNode = GetOperPred39(OpCode);
|
||||||
|
|
||||||
ShaderIrOperImmf Imm0 = new ShaderIrOperImmf(0);
|
ShaderIrNode Imm0, Imm1;
|
||||||
ShaderIrOperImmf Imm1 = new ShaderIrOperImmf(1);
|
|
||||||
|
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 Asg0 = new ShaderIrAsg(GetOperGpr0(OpCode), Imm0);
|
||||||
ShaderIrNode Asg1 = new ShaderIrAsg(GetOperGpr0(OpCode), Imm1);
|
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)
|
private static void EmitSetp(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
bool Aa = ((OpCode >> 7) & 1) != 0;
|
bool AbsA = ((OpCode >> 7) & 1) != 0;
|
||||||
bool Np = ((OpCode >> 42) & 1) != 0;
|
bool NegP = ((OpCode >> 42) & 1) != 0;
|
||||||
bool Na = ((OpCode >> 43) & 1) != 0;
|
bool NegA = ((OpCode >> 43) & 1) != 0;
|
||||||
bool Ab = ((OpCode >> 44) & 1) != 0;
|
bool AbsB = ((OpCode >> 44) & 1) != 0;
|
||||||
|
|
||||||
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
|
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
|
||||||
|
|
||||||
|
@ -399,8 +604,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (IsFloat)
|
if (IsFloat)
|
||||||
{
|
{
|
||||||
OperA = GetAluAbsNeg(OperA, Aa, Na);
|
OperA = GetAluFabsFneg(OperA, AbsA, NegA);
|
||||||
OperB = GetAluAbs (OperB, Ab);
|
OperB = GetAluFabs (OperB, AbsB);
|
||||||
|
|
||||||
CmpInst = GetCmpF(OpCode);
|
CmpInst = GetCmpF(OpCode);
|
||||||
}
|
}
|
||||||
|
@ -426,7 +631,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
ShaderIrNode P2NNode = P2Node;
|
ShaderIrNode P2NNode = P2Node;
|
||||||
|
|
||||||
if (Np)
|
if (NegP)
|
||||||
{
|
{
|
||||||
P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode);
|
P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,27 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
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)
|
public static void Exit(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Exit), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Exit), OpCode));
|
||||||
|
|
|
@ -35,6 +35,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
(int)(OpCode >> 20) & 0x3fff);
|
(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)
|
public static ShaderIrOperGpr GetOperGpr8(long OpCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperGpr((int)(OpCode >> 8) & 0xff);
|
return new ShaderIrOperGpr((int)(OpCode >> 8) & 0xff);
|
||||||
|
@ -60,6 +67,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return new ShaderIrOperGpr((int)(OpCode >> 28) & 0xff);
|
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)
|
public static ShaderIrOperImm GetOperImm13_36(long OpCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperImm((int)(OpCode >> 36) & 0x1fff);
|
return new ShaderIrOperImm((int)(OpCode >> 36) & 0x1fff);
|
||||||
|
@ -210,24 +222,69 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return new ShaderIrOperPred(Pred);
|
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;
|
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;
|
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)
|
public static ShaderIrNode GetAluNot(ShaderIrNode Node, bool Not)
|
||||||
{
|
{
|
||||||
return Not ? new ShaderIrOp(ShaderIrInst.Not, Node) : Node;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
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)
|
public static void St_A(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
|
ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
|
||||||
|
|
|
@ -99,6 +99,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Mov_I32(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
ShaderIrOperImm Imm = GetOperImm32_20(OpCode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
public static void Mov_R(ShaderIrBlock Block, long OpCode)
|
public static void Mov_R(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
ShaderIrOperGpr Gpr = GetOperGpr20(OpCode);
|
ShaderIrOperGpr Gpr = GetOperGpr20(OpCode);
|
||||||
|
@ -106,17 +113,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Gpr), 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)
|
private static void EmitF2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
bool Na = ((OpCode >> 45) & 1) != 0;
|
bool NegA = ((OpCode >> 45) & 1) != 0;
|
||||||
bool Aa = ((OpCode >> 49) & 1) != 0;
|
bool AbsA = ((OpCode >> 49) & 1) != 0;
|
||||||
|
|
||||||
ShaderIrNode OperA;
|
ShaderIrNode OperA;
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
OperA = GetAluAbsNeg(OperA, Aa, Na);
|
OperA = GetAluFabsFneg(OperA, AbsA, NegA);
|
||||||
|
|
||||||
ShaderIrInst RoundInst = GetRoundInst(OpCode);
|
ShaderIrInst RoundInst = GetRoundInst(OpCode);
|
||||||
|
|
||||||
|
@ -153,8 +153,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Na = ((OpCode >> 45) & 1) != 0;
|
bool NegA = ((OpCode >> 45) & 1) != 0;
|
||||||
bool Aa = ((OpCode >> 49) & 1) != 0;
|
bool AbsA = ((OpCode >> 49) & 1) != 0;
|
||||||
|
|
||||||
ShaderIrNode OperA;
|
ShaderIrNode OperA;
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
OperA = GetAluAbsNeg(OperA, Aa, Na);
|
OperA = GetAluFabsFneg(OperA, AbsA, NegA);
|
||||||
|
|
||||||
ShaderIrInst RoundInst = GetRoundInst(OpCode);
|
ShaderIrInst RoundInst = GetRoundInst(OpCode);
|
||||||
|
|
||||||
|
@ -224,8 +224,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
int Sel = (int)(OpCode >> 41) & 3;
|
int Sel = (int)(OpCode >> 41) & 3;
|
||||||
|
|
||||||
bool Na = ((OpCode >> 45) & 1) != 0;
|
bool NegA = ((OpCode >> 45) & 1) != 0;
|
||||||
bool Aa = ((OpCode >> 49) & 1) != 0;
|
bool AbsA = ((OpCode >> 49) & 1) != 0;
|
||||||
|
|
||||||
ShaderIrNode OperA;
|
ShaderIrNode OperA;
|
||||||
|
|
||||||
|
@ -238,7 +238,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
OperA = GetAluAbsNeg(OperA, Aa, Na);
|
OperA = GetAluIabsIneg(OperA, AbsA, NegA);
|
||||||
|
|
||||||
bool Signed = Type >= IntType.S8;
|
bool Signed = Type >= IntType.S8;
|
||||||
|
|
||||||
|
@ -253,9 +253,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (Size < 32)
|
if (Size < 32)
|
||||||
{
|
{
|
||||||
uint Mask = uint.MaxValue >> (32 - Size);
|
OperA = ExtendTo32(OperA, Signed, Size);
|
||||||
|
|
||||||
OperA = new ShaderIrOp(ShaderIrInst.And, OperA, new ShaderIrOperImm((int)Mask));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrInst Inst = Signed
|
ShaderIrInst Inst = Signed
|
||||||
|
@ -296,7 +294,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
OperA = GetAluAbsNeg(OperA, AbsA, NegA);
|
OperA = GetAluIabsIneg(OperA, AbsA, NegA);
|
||||||
|
|
||||||
bool Signed = Type >= IntType.S8;
|
bool Signed = Type >= IntType.S8;
|
||||||
|
|
||||||
|
@ -335,7 +333,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OperA = new ShaderIrOp(ShaderIrInst.And, OperA, new ShaderIrOperImm((int)Mask));
|
OperA = ExtendTo32(OperA, Signed, Size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static class ShaderDecoder
|
static class ShaderDecoder
|
||||||
{
|
{
|
||||||
|
private const bool AddDbgComments = true;
|
||||||
|
|
||||||
public static ShaderIrBlock DecodeBasicBlock(int[] Code, int Offset)
|
public static ShaderIrBlock DecodeBasicBlock(int[] Code, int Offset)
|
||||||
{
|
{
|
||||||
ShaderIrBlock Block = new ShaderIrBlock();
|
ShaderIrBlock Block = new ShaderIrBlock();
|
||||||
|
|
||||||
while (Offset + 2 <= Code.Length)
|
while (Offset + 2 <= Code.Length)
|
||||||
{
|
{
|
||||||
//Ignore scheduling instructions, which are
|
int InstPos = Offset * 4;
|
||||||
//written every 32 bytes.
|
|
||||||
|
Block.Position = InstPos;
|
||||||
|
|
||||||
|
Block.MarkLabel(InstPos);
|
||||||
|
|
||||||
|
//Ignore scheduling instructions, which are written every 32 bytes.
|
||||||
if ((Offset & 7) == 0)
|
if ((Offset & 7) == 0)
|
||||||
{
|
{
|
||||||
Offset += 2;
|
Offset += 2;
|
||||||
|
@ -24,6 +31,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
ShaderDecodeFunc Decode = ShaderOpCodeTable.GetDecoder(OpCode);
|
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)
|
if (Decode == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -31,7 +45,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
Decode(Block, OpCode);
|
Decode(Block, OpCode);
|
||||||
|
|
||||||
if (Block.GetLastNode() is ShaderIrOp Op && IsFlowChange(Op.Inst))
|
if (Block.GetLastNode() is ShaderIrOp Op && Op.Inst == ShaderIrInst.Exit)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
private List<ShaderIrNode> Nodes;
|
private List<ShaderIrNode> Nodes;
|
||||||
|
|
||||||
|
private Dictionary<int, ShaderIrLabel> LabelsToInsert;
|
||||||
|
|
||||||
|
public int Position;
|
||||||
|
|
||||||
public ShaderIrBlock()
|
public ShaderIrBlock()
|
||||||
{
|
{
|
||||||
Nodes = new List<ShaderIrNode>();
|
Nodes = new List<ShaderIrNode>();
|
||||||
|
|
||||||
|
LabelsToInsert = new Dictionary<int, ShaderIrLabel>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddNode(ShaderIrNode Node)
|
public void AddNode(ShaderIrNode Node)
|
||||||
|
@ -16,6 +22,28 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Nodes.Add(Node);
|
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()
|
public ShaderIrNode[] GetNodes()
|
||||||
{
|
{
|
||||||
return Nodes.ToArray();
|
return Nodes.ToArray();
|
||||||
|
|
12
Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs
Normal file
12
Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,6 +36,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Ffma,
|
Ffma,
|
||||||
Flg2,
|
Flg2,
|
||||||
Floor,
|
Floor,
|
||||||
|
Fmax,
|
||||||
|
Fmin,
|
||||||
Fmul,
|
Fmul,
|
||||||
Fneg,
|
Fneg,
|
||||||
Frcp,
|
Frcp,
|
||||||
|
@ -49,6 +51,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
F_End,
|
F_End,
|
||||||
|
|
||||||
I_Start,
|
I_Start,
|
||||||
|
Abs,
|
||||||
|
Add,
|
||||||
And,
|
And,
|
||||||
Asr,
|
Asr,
|
||||||
Ceq,
|
Ceq,
|
||||||
|
@ -59,16 +63,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Cle,
|
Cle,
|
||||||
Clt,
|
Clt,
|
||||||
Cne,
|
Cne,
|
||||||
|
Lsl,
|
||||||
Lsr,
|
Lsr,
|
||||||
|
Mul,
|
||||||
|
Neg,
|
||||||
Not,
|
Not,
|
||||||
Or,
|
Or,
|
||||||
Stof,
|
Stof,
|
||||||
|
Sub,
|
||||||
Texq,
|
Texq,
|
||||||
Txlf,
|
Txlf,
|
||||||
Utof,
|
Utof,
|
||||||
Xor,
|
Xor,
|
||||||
I_End,
|
I_End,
|
||||||
|
|
||||||
|
Bra,
|
||||||
Exit,
|
Exit,
|
||||||
Kil
|
Kil
|
||||||
}
|
}
|
||||||
|
|
4
Ryujinx.Graphics/Gal/Shader/ShaderIrLabel.cs
Normal file
4
Ryujinx.Graphics/Gal/Shader/ShaderIrLabel.cs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
class ShaderIrLabel : ShaderIrNode { }
|
||||||
|
}
|
|
@ -3,11 +3,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
class ShaderIrOperCbuf : ShaderIrNode
|
class ShaderIrOperCbuf : ShaderIrNode
|
||||||
{
|
{
|
||||||
public int Index { get; private set; }
|
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.Index = Index;
|
||||||
|
this.Pos = Pos;
|
||||||
this.Offs = Offs;
|
this.Offs = Offs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
OpCodes = new ShaderDecodeEntry[1 << EncodingBits];
|
OpCodes = new ShaderDecodeEntry[1 << EncodingBits];
|
||||||
|
|
||||||
#region Instructions
|
#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("111000110000xx", ShaderDecode.Exit);
|
||||||
Set("0100110010101x", ShaderDecode.F2f_C);
|
Set("0100110010101x", ShaderDecode.F2f_C);
|
||||||
Set("0011100x10101x", ShaderDecode.F2f_I);
|
Set("0011100x10101x", ShaderDecode.F2f_I);
|
||||||
|
@ -40,10 +44,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Set("001100101xxxxx", ShaderDecode.Ffma_I);
|
Set("001100101xxxxx", ShaderDecode.Ffma_I);
|
||||||
Set("010100011xxxxx", ShaderDecode.Ffma_RC);
|
Set("010100011xxxxx", ShaderDecode.Ffma_RC);
|
||||||
Set("010110011xxxxx", ShaderDecode.Ffma_RR);
|
Set("010110011xxxxx", ShaderDecode.Ffma_RR);
|
||||||
Set("00011110xxxxxx", ShaderDecode.Fmul32i);
|
Set("00011110xxxxxx", ShaderDecode.Fmul_I32);
|
||||||
Set("0100110001101x", ShaderDecode.Fmul_C);
|
Set("0100110001101x", ShaderDecode.Fmul_C);
|
||||||
Set("0011100x01101x", ShaderDecode.Fmul_I);
|
Set("0011100x01101x", ShaderDecode.Fmul_I);
|
||||||
Set("0101110001101x", ShaderDecode.Fmul_R);
|
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("0100100xxxxxxx", ShaderDecode.Fset_C);
|
||||||
Set("0011000xxxxxxx", ShaderDecode.Fset_I);
|
Set("0011000xxxxxxx", ShaderDecode.Fset_I);
|
||||||
Set("01011000xxxxxx", ShaderDecode.Fset_R);
|
Set("01011000xxxxxx", ShaderDecode.Fset_R);
|
||||||
|
@ -57,17 +64,24 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Set("0011100x11100x", ShaderDecode.I2i_I);
|
Set("0011100x11100x", ShaderDecode.I2i_I);
|
||||||
Set("0101110011100x", ShaderDecode.I2i_R);
|
Set("0101110011100x", ShaderDecode.I2i_R);
|
||||||
Set("11100000xxxxxx", ShaderDecode.Ipa);
|
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("010010110110xx", ShaderDecode.Isetp_C);
|
||||||
Set("0011011x0110xx", ShaderDecode.Isetp_I);
|
Set("0011011x0110xx", ShaderDecode.Isetp_I);
|
||||||
Set("010110110110xx", ShaderDecode.Isetp_R);
|
Set("010110110110xx", ShaderDecode.Isetp_R);
|
||||||
Set("111000110011xx", ShaderDecode.Kil);
|
Set("111000110011xx", ShaderDecode.Kil);
|
||||||
Set("1110111111011x", ShaderDecode.Ld_A);
|
Set("1110111111011x", ShaderDecode.Ld_A);
|
||||||
Set("000001xxxxxxxx", ShaderDecode.Lop32i);
|
Set("1110111110010x", ShaderDecode.Ld_C);
|
||||||
|
Set("000001xxxxxxxx", ShaderDecode.Lop_I32);
|
||||||
Set("0100110010011x", ShaderDecode.Mov_C);
|
Set("0100110010011x", ShaderDecode.Mov_C);
|
||||||
Set("0011100x10011x", ShaderDecode.Mov_I);
|
Set("0011100x10011x", ShaderDecode.Mov_I);
|
||||||
|
Set("000000010000xx", ShaderDecode.Mov_I32);
|
||||||
Set("0101110010011x", ShaderDecode.Mov_R);
|
Set("0101110010011x", ShaderDecode.Mov_R);
|
||||||
Set("000000010000xx", ShaderDecode.Mov32i);
|
|
||||||
Set("0101000010000x", ShaderDecode.Mufu);
|
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("0100110000101x", ShaderDecode.Shr_C);
|
||||||
Set("0011100x00101x", ShaderDecode.Shr_I);
|
Set("0011100x00101x", ShaderDecode.Shr_I);
|
||||||
Set("0101110000101x", ShaderDecode.Shr_R);
|
Set("0101110000101x", ShaderDecode.Shr_R);
|
||||||
|
|
|
@ -23,5 +23,13 @@ namespace Ryujinx.Graphics.Gal
|
||||||
Size = NewSize;
|
Size = NewSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void SetCbufOffs(int Offs)
|
||||||
|
{
|
||||||
|
if (Index < Offs)
|
||||||
|
{
|
||||||
|
Index = Offs;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics", "Ryujinx
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "Ryujinx.Audio\Ryujinx.Audio.csproj", "{5C1D818E-682A-46A5-9D54-30006E26C270}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "Ryujinx.Audio\Ryujinx.Audio.csproj", "{5C1D818E-682A-46A5-9D54-30006E26C270}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryushader", "Ryushader\Ryushader.csproj", "{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{5C1D818E-682A-46A5-9D54-30006E26C270}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
48
Ryushader/Program.cs
Normal file
48
Ryushader/Program.cs
Normal file
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
Ryushader/Ryushader.csproj
Normal file
12
Ryushader/Ryushader.csproj
Normal file
|
@ -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>
|
Loading…
Reference in a new issue