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:
gdkchan 2018-06-26 18:01:10 -03:00
parent af5f059d4e
commit c9a42f0305
8 changed files with 144 additions and 23 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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)

View file

@ -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;");

View file

@ -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);

View file

@ -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)

View file

@ -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);

View file

@ -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);