From 0a5e2a036e97417e03abb8c348280a45afc2607d Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Wed, 22 Aug 2018 02:42:25 -0300 Subject: [PATCH] Implement multiple attachments --- Ryujinx.Graphics/Gal/IGalFrameBuffer.cs | 2 + Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs | 33 ++++++++++------- Ryujinx.Graphics/Gal/Shader/GlslDecl.cs | 25 ++++++++++--- Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs | 31 +++++++++++++++- Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs | 37 ++++++++++++++----- Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs | 35 +++++++++++++++++- Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs | 2 + 7 files changed, 134 insertions(+), 31 deletions(-) diff --git a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs index bce1981a47..108d3d9b1d 100644 --- a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs @@ -18,6 +18,8 @@ namespace Ryujinx.Graphics.Gal 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 SetWindowSize(int Width, int Height); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs index e0f12e4eca..12239c4f06 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs @@ -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 NativeHeight = 720; @@ -194,6 +182,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL 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) { this.FlipX = FlipX; @@ -421,8 +428,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL } GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer); - - GL.DrawBuffers(8, DrawBuffers); } private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment) diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs index d703653cc6..25f64db83d 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs @@ -16,7 +16,6 @@ namespace Ryujinx.Graphics.Gal.Shader public const int VertexIdAttr = 0x2fc; public const int FaceAttr = 0x3fc; - public const int MaxFrameBufferAttachments = 8; public const int MaxUboSize = 1024; public const int GlPositionVec4Index = 7; @@ -101,10 +100,26 @@ namespace Ryujinx.Graphics.Gal.Shader if (ShaderType == GalShaderType.Fragment) { - //Note: Replace 1 with MaxFrameBufferAttachments when attachments start to work - for (int Index = 0; Index < 1; Index++) + int Index = 0; + + 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)); } } @@ -322,7 +337,7 @@ namespace Ryujinx.Graphics.Gal.Shader case ShaderIrOperGpr Gpr: { - if (!Gpr.IsConst && !HasName(m_Gprs, Gpr.Index)) + if (!Gpr.IsConst) { string Name = GetGprName(Gpr.Index); diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index 335be0c3d3..8baf30e039 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -304,7 +304,17 @@ namespace Ryujinx.Graphics.Gal.Shader 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 + ";"); } @@ -438,6 +448,25 @@ namespace Ryujinx.Graphics.Gal.Shader { 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("}"); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs b/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs index 6b7375a155..eca90fc3aa 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs @@ -1,4 +1,6 @@ -namespace Ryujinx.Graphics.Gal.Shader +using System; + +namespace Ryujinx.Graphics.Gal.Shader { struct OmapTarget { @@ -8,6 +10,19 @@ 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 @@ -99,24 +114,28 @@ OmapDepth = ReadBits(Type2Omap, 1, 1) != 0; } - public int FragOutputCount + public int DepthRegister { get { - int Index = 0; + int Count = 0; - while (OmapTargets[Index].Enabled && Index < 8) + for (int Index = 0; Index < OmapTargets.Length; Index++) { - Index++; + for (int Component = 0; Component < 4; Component++) + { + if (OmapTargets[Index].ComponentEnabled(Component)) + { + Count++; + } + } } - return Index; + // Depth register is always two registers after the last color output + return Count + 1; } } - // Depth register is always two registers after the last color output - public int DepthRegister => FragOutputCount * 4 + 1; - private static int ReadBits(uint Word, int Offset, int BitWidth) { uint Mask = (1u << BitWidth) - 1u; diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs index 1d0834ddb5..f225722278 100644 --- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs @@ -102,10 +102,14 @@ namespace Ryujinx.HLE.Gpu.Engines SetAlphaBlending(State); SetPrimitiveRestart(State); - //Enabling multiple framebuffer attachments cause graphics reggresions - SetFrameBuffer(Vmm, 0); + for (int FbIndex = 0; FbIndex < 8; FbIndex++) + { + SetFrameBuffer(Vmm, 0); + } SetZeta(Vmm); + SetRenderTargets(); + long[] Keys = UploadShaders(Vmm); Gpu.Renderer.Shader.BindProgram(); @@ -415,6 +419,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) { long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs index b03aef0241..7eff13b58f 100644 --- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs @@ -22,11 +22,13 @@ namespace Ryujinx.HLE.Gpu.Engines StencilBackFuncRef = 0x3d5, StencilBackMask = 0x3d6, StencilBackFuncMask = 0x3d7, + RTSeparateFragData = 0x3eb, ZetaAddress = 0x3f8, ZetaFormat = 0x3fa, ZetaBlockDimensions = 0x3fb, ZetaLayerStride = 0x3fc, VertexAttribNFormat = 0x458, + RTControl = 0x487, ZetaHoriz = 0x48a, ZetaVert = 0x48b, ZetaArrayMode = 0x48c,