Implement multiple rendertarget attachments and depth writting (#375)

* Add depth writting

* Implement multiple attachments

* Address feedback
This commit is contained in:
ReinUsesLisp 2018-08-23 02:07:23 -03:00 committed by gdkchan
parent 9977acad0f
commit 624e813cd3
7 changed files with 201 additions and 29 deletions

View file

@ -18,6 +18,8 @@ namespace Ryujinx.Graphics.Gal
void Set(byte[] Data, int Width, int Height); void Set(byte[] Data, int Width, int Height);
void SetMap(int[] Map);
void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom); void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom);
void SetWindowSize(int Width, int Height); void SetWindowSize(int Width, int Height);

View file

@ -21,18 +21,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
} }
} }
private static readonly DrawBuffersEnum[] DrawBuffers = new DrawBuffersEnum[]
{
DrawBuffersEnum.ColorAttachment0,
DrawBuffersEnum.ColorAttachment1,
DrawBuffersEnum.ColorAttachment2,
DrawBuffersEnum.ColorAttachment3,
DrawBuffersEnum.ColorAttachment4,
DrawBuffersEnum.ColorAttachment5,
DrawBuffersEnum.ColorAttachment6,
DrawBuffersEnum.ColorAttachment7,
};
private const int NativeWidth = 1280; private const int NativeWidth = 1280;
private const int NativeHeight = 720; private const int NativeHeight = 720;
@ -194,6 +182,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL
ReadTex = RawTex; ReadTex = RawTex;
} }
public void SetMap(int[] Map)
{
if (Map != null && Map.Length > 0)
{
DrawBuffersEnum[] Mode = new DrawBuffersEnum[Map.Length];
for (int i = 0; i < Map.Length; i++)
{
Mode[i] = DrawBuffersEnum.ColorAttachment0 + Map[i];
}
GL.DrawBuffers(Mode.Length, Mode);
}
else
{
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
}
}
public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom) public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom)
{ {
this.FlipX = FlipX; this.FlipX = FlipX;
@ -421,8 +428,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
} }
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer); GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
GL.DrawBuffers(8, DrawBuffers);
} }
private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment) private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)

View file

@ -16,7 +16,6 @@ namespace Ryujinx.Graphics.Gal.Shader
public const int VertexIdAttr = 0x2fc; public const int VertexIdAttr = 0x2fc;
public const int FaceAttr = 0x3fc; public const int FaceAttr = 0x3fc;
public const int MaxFrameBufferAttachments = 8;
public const int MaxUboSize = 1024; public const int MaxUboSize = 1024;
public const int GlPositionVec4Index = 7; public const int GlPositionVec4Index = 7;
@ -94,16 +93,33 @@ namespace Ryujinx.Graphics.Gal.Shader
m_Preds = new Dictionary<int, ShaderDeclInfo>(); m_Preds = new Dictionary<int, ShaderDeclInfo>();
} }
public GlslDecl(ShaderIrBlock[] Blocks, GalShaderType ShaderType) : this(ShaderType) public GlslDecl(ShaderIrBlock[] Blocks, GalShaderType ShaderType, ShaderHeader Header)
: this(ShaderType)
{ {
StagePrefix = StagePrefixes[(int)ShaderType] + "_"; StagePrefix = StagePrefixes[(int)ShaderType] + "_";
if (ShaderType == GalShaderType.Fragment) if (ShaderType == GalShaderType.Fragment)
{ {
//Note: Replace 1 with MaxFrameBufferAttachments when attachments start to work int Index = 0;
for (int Index = 0; Index < 1; Index++)
for (int Attachment = 0; Attachment < 8; Attachment++)
{ {
m_Gprs.Add(Index * 4, new ShaderDeclInfo(FragmentOutputName + Index, Index * 4, false, 0, 4)); for (int Component = 0; Component < 4; Component++)
{
if (Header.OmapTargets[Attachment].ComponentEnabled(Component))
{
m_Gprs.TryAdd(Index, new ShaderDeclInfo(GetGprName(Index), Index));
Index++;
}
}
}
if (Header.OmapDepth)
{
Index = Header.DepthRegister;
m_Gprs.TryAdd(Index, new ShaderDeclInfo(GetGprName(Index), Index));
} }
} }
@ -153,6 +169,11 @@ namespace Ryujinx.Graphics.Gal.Shader
return Combined; return Combined;
} }
public static string GetGprName(int Index)
{
return GprName + Index;
}
private static void Merge( private static void Merge(
Dictionary<int, ShaderDeclInfo> C, Dictionary<int, ShaderDeclInfo> C,
Dictionary<int, ShaderDeclInfo> A, Dictionary<int, ShaderDeclInfo> A,
@ -316,9 +337,9 @@ namespace Ryujinx.Graphics.Gal.Shader
case ShaderIrOperGpr Gpr: case ShaderIrOperGpr Gpr:
{ {
if (!Gpr.IsConst && !HasName(m_Gprs, Gpr.Index)) if (!Gpr.IsConst)
{ {
string Name = GprName + Gpr.Index; string Name = GetGprName(Gpr.Index);
m_Gprs.TryAdd(Gpr.Index, new ShaderDeclInfo(Name, Gpr.Index)); m_Gprs.TryAdd(Gpr.Index, new ShaderDeclInfo(Name, Gpr.Index));
} }

View file

@ -120,8 +120,8 @@ namespace Ryujinx.Graphics.Gal.Shader
Blocks = ShaderDecoder.Decode(Memory, VpAPosition); Blocks = ShaderDecoder.Decode(Memory, VpAPosition);
BlocksB = ShaderDecoder.Decode(Memory, VpBPosition); BlocksB = ShaderDecoder.Decode(Memory, VpBPosition);
GlslDecl DeclVpA = new GlslDecl(Blocks, ShaderType); GlslDecl DeclVpA = new GlslDecl(Blocks, ShaderType, Header);
GlslDecl DeclVpB = new GlslDecl(BlocksB, ShaderType); GlslDecl DeclVpB = new GlslDecl(BlocksB, ShaderType, HeaderB);
Decl = GlslDecl.Merge(DeclVpA, DeclVpB); Decl = GlslDecl.Merge(DeclVpA, DeclVpB);
@ -136,7 +136,7 @@ namespace Ryujinx.Graphics.Gal.Shader
Blocks = ShaderDecoder.Decode(Memory, Position); Blocks = ShaderDecoder.Decode(Memory, Position);
BlocksB = null; BlocksB = null;
Decl = new GlslDecl(Blocks, ShaderType); Decl = new GlslDecl(Blocks, ShaderType, Header);
return Decompile(); return Decompile();
} }
@ -304,7 +304,17 @@ namespace Ryujinx.Graphics.Gal.Shader
private void PrintDeclOutAttributes() private void PrintDeclOutAttributes()
{ {
if (Decl.ShaderType != GalShaderType.Fragment) if (Decl.ShaderType == GalShaderType.Fragment)
{
for (int Attachment = 0; Attachment < 8; Attachment++)
{
if (Header.OmapTargets[Attachment].Enabled)
{
SB.AppendLine("layout (location = " + Attachment + ") out vec4 " + GlslDecl.FragmentOutputName + Attachment + ";");
}
}
}
else
{ {
SB.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") out vec4 " + GlslDecl.PositionOutAttrName + ";"); SB.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") out vec4 " + GlslDecl.PositionOutAttrName + ";");
} }
@ -432,6 +442,33 @@ namespace Ryujinx.Graphics.Gal.Shader
PrintAttrToOutput(); PrintAttrToOutput();
} }
if (Decl.ShaderType == GalShaderType.Fragment)
{
if (Header.OmapDepth)
{
SB.AppendLine(IdentationStr + "gl_FragDepth = " + GlslDecl.GetGprName(Header.DepthRegister) + ";");
}
int GprIndex = 0;
for (int Attachment = 0; Attachment < 8; Attachment++)
{
string Output = GlslDecl.FragmentOutputName + Attachment;
OmapTarget Target = Header.OmapTargets[Attachment];
for (int Component = 0; Component < 4; Component++)
{
if (Target.ComponentEnabled(Component))
{
SB.AppendLine(IdentationStr + Output + "[" + Component + "] = " + GlslDecl.GetGprName(GprIndex) + ";");
GprIndex++;
}
}
}
}
SB.AppendLine("}"); SB.AppendLine("}");
} }

View file

@ -1,5 +1,30 @@
namespace Ryujinx.Graphics.Gal.Shader using System;
namespace Ryujinx.Graphics.Gal.Shader
{ {
struct OmapTarget
{
public bool Red;
public bool Green;
public bool Blue;
public bool Alpha;
public bool Enabled => Red || Green || Blue || Alpha;
public bool ComponentEnabled(int Component)
{
switch (Component)
{
case 0: return Red;
case 1: return Green;
case 2: return Blue;
case 3: return Alpha;
}
throw new ArgumentException(nameof(Component));
}
}
class ShaderHeader class ShaderHeader
{ {
public const int PointList = 1; public const int PointList = 1;
@ -30,6 +55,10 @@
public int StoreReqStart { get; private set; } public int StoreReqStart { get; private set; }
public int StoreReqEnd { get; private set; } public int StoreReqEnd { get; private set; }
public OmapTarget[] OmapTargets { get; private set; }
public bool OmapSampleMask { get; private set; }
public bool OmapDepth { get; private set; }
public ShaderHeader(IGalMemory Memory, long Position) public ShaderHeader(IGalMemory Memory, long Position)
{ {
uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0); uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0);
@ -61,6 +90,50 @@
MaxOutputVertexCount = ReadBits(CommonWord4, 0, 12); MaxOutputVertexCount = ReadBits(CommonWord4, 0, 12);
StoreReqStart = ReadBits(CommonWord4, 12, 8); StoreReqStart = ReadBits(CommonWord4, 12, 8);
StoreReqEnd = ReadBits(CommonWord4, 24, 8); StoreReqEnd = ReadBits(CommonWord4, 24, 8);
//Type 2 (fragment?) reading
uint Type2OmapTarget = (uint)Memory.ReadInt32(Position + 72);
uint Type2Omap = (uint)Memory.ReadInt32(Position + 76);
OmapTargets = new OmapTarget[8];
for (int i = 0; i < OmapTargets.Length; i++)
{
int Offset = i * 4;
OmapTargets[i] = new OmapTarget
{
Red = ReadBits(Type2OmapTarget, Offset + 0, 1) != 0,
Green = ReadBits(Type2OmapTarget, Offset + 1, 1) != 0,
Blue = ReadBits(Type2OmapTarget, Offset + 2, 1) != 0,
Alpha = ReadBits(Type2OmapTarget, Offset + 3, 1) != 0
};
}
OmapSampleMask = ReadBits(Type2Omap, 0, 1) != 0;
OmapDepth = ReadBits(Type2Omap, 1, 1) != 0;
}
public int DepthRegister
{
get
{
int Count = 0;
for (int Index = 0; Index < OmapTargets.Length; Index++)
{
for (int Component = 0; Component < 4; Component++)
{
if (OmapTargets[Index].ComponentEnabled(Component))
{
Count++;
}
}
}
// Depth register is always two registers after the last color output
return Count + 1;
}
} }
private static int ReadBits(uint Word, int Offset, int BitWidth) private static int ReadBits(uint Word, int Offset, int BitWidth)

View file

@ -102,10 +102,15 @@ namespace Ryujinx.HLE.Gpu.Engines
SetAlphaBlending(State); SetAlphaBlending(State);
SetPrimitiveRestart(State); SetPrimitiveRestart(State);
//Enabling multiple framebuffer attachments cause graphics reggresions for (int FbIndex = 0; FbIndex < 8; FbIndex++)
{
SetFrameBuffer(Vmm, 0); SetFrameBuffer(Vmm, 0);
}
SetZeta(Vmm); SetZeta(Vmm);
SetRenderTargets();
long[] Keys = UploadShaders(Vmm); long[] Keys = UploadShaders(Vmm);
Gpu.Renderer.Shader.BindProgram(); Gpu.Renderer.Shader.BindProgram();
@ -415,6 +420,33 @@ namespace Ryujinx.HLE.Gpu.Engines
} }
} }
private void SetRenderTargets()
{
bool SeparateFragData = (ReadRegister(NvGpuEngine3dReg.RTSeparateFragData) & 1) != 0;
if (SeparateFragData)
{
uint Control = (uint)(ReadRegister(NvGpuEngine3dReg.RTControl));
uint Count = Control & 0xf;
int[] Map = new int[Count];
for (int i = 0; i < Count; i++)
{
int Shift = 4 + i * 3;
Map[i] = (int)((Control >> Shift) & 7);
}
Gpu.Renderer.FrameBuffer.SetMap(Map);
}
else
{
Gpu.Renderer.FrameBuffer.SetMap(null);
}
}
private void UploadTextures(NvGpuVmm Vmm, GalPipelineState State, long[] Keys) private void UploadTextures(NvGpuVmm Vmm, GalPipelineState State, long[] Keys)
{ {
long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);

View file

@ -22,11 +22,13 @@ namespace Ryujinx.HLE.Gpu.Engines
StencilBackFuncRef = 0x3d5, StencilBackFuncRef = 0x3d5,
StencilBackMask = 0x3d6, StencilBackMask = 0x3d6,
StencilBackFuncMask = 0x3d7, StencilBackFuncMask = 0x3d7,
RTSeparateFragData = 0x3eb,
ZetaAddress = 0x3f8, ZetaAddress = 0x3f8,
ZetaFormat = 0x3fa, ZetaFormat = 0x3fa,
ZetaBlockDimensions = 0x3fb, ZetaBlockDimensions = 0x3fb,
ZetaLayerStride = 0x3fc, ZetaLayerStride = 0x3fc,
VertexAttribNFormat = 0x458, VertexAttribNFormat = 0x458,
RTControl = 0x487,
ZetaHoriz = 0x48a, ZetaHoriz = 0x48a,
ZetaVert = 0x48b, ZetaVert = 0x48b,
ZetaArrayMode = 0x48c, ZetaArrayMode = 0x48c,