aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinUsesLisp <reinuseslisp@airmail.cc>2018-08-23 02:07:23 -0300
committergdkchan <gab.dark.100@gmail.com>2018-08-23 02:07:23 -0300
commit624e813cd3e5d782847c577c2da0cfb8a121fd18 (patch)
treefa12638a42a406f1736662f1a2fdee1d9f9bd014
parent9977acad0fe08ee98a8174ce1c5609be22ba67ee (diff)
Implement multiple rendertarget attachments and depth writting (#375)
* Add depth writting * Implement multiple attachments * Address feedback
-rw-r--r--Ryujinx.Graphics/Gal/IGalFrameBuffer.cs2
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs33
-rw-r--r--Ryujinx.Graphics/Gal/Shader/GlslDecl.cs35
-rw-r--r--Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs45
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs75
-rw-r--r--Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs38
-rw-r--r--Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs2
7 files changed, 201 insertions, 29 deletions
diff --git a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs
index bce1981a..108d3d9b 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 e0f12e4e..12239c4f 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 56745bc1..25f64db8 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;
@@ -94,16 +93,33 @@ namespace Ryujinx.Graphics.Gal.Shader
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] + "_";
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));
}
}
@@ -153,6 +169,11 @@ namespace Ryujinx.Graphics.Gal.Shader
return Combined;
}
+ public static string GetGprName(int Index)
+ {
+ return GprName + Index;
+ }
+
private static void Merge(
Dictionary<int, ShaderDeclInfo> C,
Dictionary<int, ShaderDeclInfo> A,
@@ -316,9 +337,9 @@ namespace Ryujinx.Graphics.Gal.Shader
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));
}
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
index 72637984..8baf30e0 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
@@ -120,8 +120,8 @@ namespace Ryujinx.Graphics.Gal.Shader
Blocks = ShaderDecoder.Decode(Memory, VpAPosition);
BlocksB = ShaderDecoder.Decode(Memory, VpBPosition);
- GlslDecl DeclVpA = new GlslDecl(Blocks, ShaderType);
- GlslDecl DeclVpB = new GlslDecl(BlocksB, ShaderType);
+ GlslDecl DeclVpA = new GlslDecl(Blocks, ShaderType, Header);
+ GlslDecl DeclVpB = new GlslDecl(BlocksB, ShaderType, HeaderB);
Decl = GlslDecl.Merge(DeclVpA, DeclVpB);
@@ -136,7 +136,7 @@ namespace Ryujinx.Graphics.Gal.Shader
Blocks = ShaderDecoder.Decode(Memory, Position);
BlocksB = null;
- Decl = new GlslDecl(Blocks, ShaderType);
+ Decl = new GlslDecl(Blocks, ShaderType, Header);
return Decompile();
}
@@ -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 + ";");
}
@@ -432,6 +442,33 @@ namespace Ryujinx.Graphics.Gal.Shader
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("}");
}
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs b/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs
index 8e5057ed..eca90fc3 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs
@@ -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
{
public const int PointList = 1;
@@ -30,6 +55,10 @@
public int StoreReqStart { 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)
{
uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0);
@@ -61,6 +90,50 @@
MaxOutputVertexCount = ReadBits(CommonWord4, 0, 12);
StoreReqStart = ReadBits(CommonWord4, 12, 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)
diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs
index 419f6901..be47b66c 100644
--- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs
+++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs
@@ -102,10 +102,15 @@ 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 +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)
{
long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
@@ -801,4 +833,4 @@ namespace Ryujinx.HLE.Gpu.Engines
return Vmm.IsRegionModified(Key, Size, Type);
}
}
-} \ No newline at end of file
+}
diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs
index b03aef02..7eff13b5 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,