Add WIP support for Vertex Program A, add the FADD_I32 shader instruction, small fix on FFMA_I encoding, nits
This commit is contained in:
parent
af5f059d4e
commit
c9a42f0305
8 changed files with 144 additions and 23 deletions
|
@ -6,6 +6,8 @@ namespace Ryujinx.Graphics.Gal
|
|||
{
|
||||
void Create(IGalMemory Memory, long Key, GalShaderType Type);
|
||||
|
||||
void Create(IGalMemory Memory, long VpAPos, long Key, GalShaderType Type);
|
||||
|
||||
IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key);
|
||||
|
||||
void SetConstBuffer(long Key, int Cbuf, byte[] Data);
|
||||
|
|
|
@ -97,12 +97,37 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
public void Create(IGalMemory Memory, long Key, GalShaderType Type)
|
||||
{
|
||||
Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, Key, Type));
|
||||
Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, Key, 0, false, Type));
|
||||
}
|
||||
|
||||
private ShaderStage ShaderStageFactory(IGalMemory Memory, long Position, GalShaderType Type)
|
||||
public void Create(IGalMemory Memory, long VpAPos, long Key, GalShaderType Type)
|
||||
{
|
||||
GlslProgram Program = GetGlslProgram(Memory, Position, Type);
|
||||
Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, VpAPos, Key, true, Type));
|
||||
}
|
||||
|
||||
private ShaderStage ShaderStageFactory(
|
||||
IGalMemory Memory,
|
||||
long Position,
|
||||
long PositionB,
|
||||
bool IsDualVp,
|
||||
GalShaderType Type)
|
||||
{
|
||||
GlslProgram Program;
|
||||
|
||||
GlslDecompiler Decompiler = new GlslDecompiler();
|
||||
|
||||
if (IsDualVp)
|
||||
{
|
||||
Program = Decompiler.Decompile(
|
||||
Memory,
|
||||
Position + 0x50,
|
||||
PositionB + 0x50,
|
||||
Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
Program = Decompiler.Decompile(Memory, Position + 0x50, Type);
|
||||
}
|
||||
|
||||
return new ShaderStage(
|
||||
Type,
|
||||
|
@ -111,13 +136,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Program.Uniforms);
|
||||
}
|
||||
|
||||
private GlslProgram GetGlslProgram(IGalMemory Memory, long Position, GalShaderType Type)
|
||||
{
|
||||
GlslDecompiler Decompiler = new GlslDecompiler();
|
||||
|
||||
return Decompiler.Decompile(Memory, Position + 0x50, Type);
|
||||
}
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key)
|
||||
{
|
||||
if (Stages.TryGetValue(Key, out ShaderStage Stage))
|
||||
|
@ -283,7 +301,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
return FreeBinding;
|
||||
}
|
||||
|
||||
|
||||
BindUniformBuffersIfNotNull(Current.Vertex);
|
||||
BindUniformBuffersIfNotNull(Current.TessControl);
|
||||
BindUniformBuffersIfNotNull(Current.TessEvaluation);
|
||||
|
|
|
@ -28,12 +28,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public const string FlipUniformName = "flip";
|
||||
|
||||
public const string StageProgramBName = "program_b";
|
||||
|
||||
private string[] StagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" };
|
||||
|
||||
private string StagePrefix;
|
||||
|
||||
private Dictionary<int, ShaderDeclInfo> m_Textures;
|
||||
|
||||
private Dictionary<int, ShaderDeclInfo> m_Uniforms;
|
||||
|
||||
private Dictionary<int, ShaderDeclInfo> m_InAttributes;
|
||||
|
@ -43,7 +44,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
private Dictionary<int, ShaderDeclInfo> m_Preds;
|
||||
|
||||
public IReadOnlyDictionary<int, ShaderDeclInfo> Textures => m_Textures;
|
||||
|
||||
public IReadOnlyDictionary<int, ShaderDeclInfo> Uniforms => m_Uniforms;
|
||||
|
||||
public IReadOnlyDictionary<int, ShaderDeclInfo> InAttributes => m_InAttributes;
|
||||
|
@ -54,7 +54,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public GalShaderType ShaderType { get; private set; }
|
||||
|
||||
public GlslDecl(ShaderIrBlock[] Blocks, GalShaderType ShaderType)
|
||||
public GlslDecl(GalShaderType ShaderType)
|
||||
{
|
||||
this.ShaderType = ShaderType;
|
||||
|
||||
|
@ -80,7 +80,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
m_OutAttributes.Add(7, new ShaderDeclInfo("gl_Position", -1, 0, 4));
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(ShaderIrBlock[] Blocks)
|
||||
{
|
||||
foreach (ShaderIrBlock Block in Blocks)
|
||||
{
|
||||
foreach (ShaderIrNode Node in Block.GetNodes())
|
||||
|
@ -89,7 +92,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Traverse(ShaderIrNode Parent, ShaderIrNode Node)
|
||||
{
|
||||
switch (Node)
|
||||
|
|
|
@ -25,10 +25,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private GlslDecl Decl;
|
||||
|
||||
private ShaderIrBlock[] Blocks;
|
||||
private ShaderIrBlock[] Blocks, BlocksB;
|
||||
|
||||
private StringBuilder SB;
|
||||
|
||||
private bool NeedsProgramBCall;
|
||||
|
||||
public GlslDecompiler()
|
||||
{
|
||||
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
|
||||
|
@ -104,12 +106,37 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
};
|
||||
}
|
||||
|
||||
public GlslProgram Decompile(
|
||||
IGalMemory Memory,
|
||||
long VpAPosition,
|
||||
long VpBPosition,
|
||||
GalShaderType ShaderType)
|
||||
{
|
||||
Blocks = ShaderDecoder.Decode(Memory, VpAPosition);
|
||||
BlocksB = ShaderDecoder.Decode(Memory, VpBPosition);
|
||||
|
||||
Decl = new GlslDecl(ShaderType);
|
||||
|
||||
Decl.Add(Blocks);
|
||||
Decl.Add(BlocksB);
|
||||
|
||||
return Decompile();
|
||||
}
|
||||
|
||||
public GlslProgram Decompile(IGalMemory Memory, long Position, GalShaderType ShaderType)
|
||||
{
|
||||
Blocks = ShaderDecoder.Decode(Memory, Position);
|
||||
Blocks = ShaderDecoder.Decode(Memory, Position);
|
||||
BlocksB = null;
|
||||
|
||||
Decl = new GlslDecl(Blocks, ShaderType);
|
||||
Decl = new GlslDecl(ShaderType);
|
||||
|
||||
Decl.Add(Blocks);
|
||||
|
||||
return Decompile();
|
||||
}
|
||||
|
||||
private GlslProgram Decompile()
|
||||
{
|
||||
SB = new StringBuilder();
|
||||
|
||||
SB.AppendLine("#version 410 core");
|
||||
|
@ -121,8 +148,21 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
PrintDeclGprs();
|
||||
PrintDeclPreds();
|
||||
|
||||
if (BlocksB != null)
|
||||
{
|
||||
string SubName = "void " + GlslDecl.StageProgramBName + "()";
|
||||
|
||||
PrintBlockScope(BlocksB[0], null, null, SubName, IdentationStr);
|
||||
|
||||
SB.AppendLine();
|
||||
|
||||
NeedsProgramBCall = true;
|
||||
}
|
||||
|
||||
PrintBlockScope(Blocks[0], null, null, "void main()", IdentationStr);
|
||||
|
||||
NeedsProgramBCall = false;
|
||||
|
||||
string GlslCode = SB.ToString();
|
||||
|
||||
return new GlslProgram(
|
||||
|
@ -146,8 +186,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
foreach (ShaderDeclInfo DeclInfo in Decl.Uniforms.Values.OrderBy(DeclKeySelector))
|
||||
{
|
||||
SB.AppendLine($"layout (std140) uniform {DeclInfo.Name} {{");
|
||||
|
||||
SB.AppendLine($"{IdentationStr}vec4 {DeclInfo.Name}_data[{DeclInfo.Index / 4 + 1}];");
|
||||
SB.AppendLine($"}};");
|
||||
|
||||
SB.AppendLine("};");
|
||||
}
|
||||
|
||||
if (Decl.Uniforms.Count > 0)
|
||||
|
@ -389,6 +431,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
//the shader ends here.
|
||||
if (Decl.ShaderType == GalShaderType.Vertex)
|
||||
{
|
||||
if (NeedsProgramBCall)
|
||||
{
|
||||
SB.AppendLine(Identation + GlslDecl.StageProgramBName + "();");
|
||||
}
|
||||
|
||||
SB.AppendLine(Identation + "gl_Position.xy *= flip;");
|
||||
|
||||
SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + " = gl_Position;");
|
||||
|
|
|
@ -31,6 +31,24 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
EmitAluBinaryF(Block, OpCode, ShaderOper.Immf, ShaderIrInst.Fadd);
|
||||
}
|
||||
|
||||
public static void Fadd_I32(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
ShaderIrNode OperA = GetOperGpr8 (OpCode);
|
||||
ShaderIrNode OperB = GetOperImmf32_20(OpCode);
|
||||
|
||||
bool NegB = ((OpCode >> 53) & 1) != 0;
|
||||
bool AbsA = ((OpCode >> 54) & 1) != 0;
|
||||
bool NegA = ((OpCode >> 56) & 1) != 0;
|
||||
bool AbsB = ((OpCode >> 57) & 1) != 0;
|
||||
|
||||
OperA = GetAluFabsFneg(OperA, AbsA, NegA);
|
||||
OperB = GetAluFabsFneg(OperB, AbsB, NegB);
|
||||
|
||||
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB);
|
||||
|
||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||
}
|
||||
|
||||
public static void Fadd_R(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
EmitAluBinaryF(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fadd);
|
||||
|
|
|
@ -24,7 +24,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public static void Exit(ShaderIrBlock Block, long OpCode)
|
||||
{
|
||||
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Exit), OpCode));
|
||||
int CCode = (int)OpCode & 0x1f;
|
||||
|
||||
//TODO: Figure out what the other condition codes mean...
|
||||
if (CCode == 0xf)
|
||||
{
|
||||
Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Exit), OpCode));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void Kil(ShaderIrBlock Block, long OpCode)
|
||||
|
|
|
@ -39,14 +39,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
Set("0101110010110x", ShaderDecode.F2i_R);
|
||||
Set("0100110001011x", ShaderDecode.Fadd_C);
|
||||
Set("0011100x01011x", ShaderDecode.Fadd_I);
|
||||
Set("000010xxxxxxxx", ShaderDecode.Fadd_I32);
|
||||
Set("0101110001011x", ShaderDecode.Fadd_R);
|
||||
Set("010010011xxxxx", ShaderDecode.Ffma_CR);
|
||||
Set("001100101xxxxx", ShaderDecode.Ffma_I);
|
||||
Set("0011001x1xxxxx", ShaderDecode.Ffma_I);
|
||||
Set("010100011xxxxx", ShaderDecode.Ffma_RC);
|
||||
Set("010110011xxxxx", ShaderDecode.Ffma_RR);
|
||||
Set("00011110xxxxxx", ShaderDecode.Fmul_I32);
|
||||
Set("0100110001101x", ShaderDecode.Fmul_C);
|
||||
Set("0011100x01101x", ShaderDecode.Fmul_I);
|
||||
Set("00011110xxxxxx", ShaderDecode.Fmul_I32);
|
||||
Set("0101110001101x", ShaderDecode.Fmul_R);
|
||||
Set("0100110001100x", ShaderDecode.Fmnmx_C);
|
||||
Set("0011100x01100x", ShaderDecode.Fmnmx_I);
|
||||
|
|
|
@ -125,7 +125,33 @@ namespace Ryujinx.HLE.Gpu.Engines
|
|||
|
||||
long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
||||
|
||||
for (int Index = 0; Index < 6; Index++)
|
||||
int Index = 1;
|
||||
|
||||
int VpAControl = ReadRegister(NvGpuEngine3dReg.ShaderNControl);
|
||||
|
||||
bool VpAEnable = (VpAControl & 1) != 0;
|
||||
|
||||
if (VpAEnable)
|
||||
{
|
||||
//Note: The maxwell supports 2 vertex programs, usually
|
||||
//only VP B is used, but in some cases VP A is also used.
|
||||
//In this case, it seems to function as an extra vertex
|
||||
//shader stage.
|
||||
//The graphics abstraction layer has a special overload for this
|
||||
//case, which should merge the two shaders into one vertex shader.
|
||||
int VpAOffset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset);
|
||||
int VpBOffset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + 0x10);
|
||||
|
||||
long VpAPos = BasePosition + (uint)VpAOffset;
|
||||
long VpBPos = BasePosition + (uint)VpBOffset;
|
||||
|
||||
Gpu.Renderer.Shader.Create(Vmm, VpAPos, VpBPos, GalShaderType.Vertex);
|
||||
Gpu.Renderer.Shader.Bind(VpBPos);
|
||||
|
||||
Index = 2;
|
||||
}
|
||||
|
||||
for (; Index < 6; Index++)
|
||||
{
|
||||
int Control = ReadRegister(NvGpuEngine3dReg.ShaderNControl + Index * 0x10);
|
||||
int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + Index * 0x10);
|
||||
|
|
Loading…
Add table
Reference in a new issue