From 468d8f841ffcbebf4130371eb64ab04165bce3e9 Mon Sep 17 00:00:00 2001
From: mageven <62494521+mageven@users.noreply.github.com>
Date: Tue, 7 Apr 2020 14:49:45 +0530
Subject: [PATCH] Simple GPU fixes (#1093)

* Implement RasterizeEnable

* Match viewport count to hardware

* Simplify ScissorTest tracking around Blits

* Disable RasterizerDiscard around Blits and track its state

* Read RasterizeEnable reg as bool and add doc
---
 Ryujinx.Graphics.GAL/IPipeline.cs           |  2 +
 Ryujinx.Graphics.Gpu/Constants.cs           |  2 +-
 Ryujinx.Graphics.Gpu/Engine/Methods.cs      | 15 +++++++
 Ryujinx.Graphics.Gpu/State/GpuState.cs      |  3 ++
 Ryujinx.Graphics.Gpu/State/GpuStateTable.cs |  6 +--
 Ryujinx.Graphics.Gpu/State/MethodOffset.cs  |  1 +
 Ryujinx.Graphics.OpenGL/Pipeline.cs         | 43 ++++++++++++++++-----
 Ryujinx.Graphics.OpenGL/TextureCopy.cs      |  6 ++-
 Ryujinx.Graphics.OpenGL/Window.cs           |  6 ++-
 9 files changed, 66 insertions(+), 18 deletions(-)

diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs
index fc5cf483db..5b663823f5 100644
--- a/Ryujinx.Graphics.GAL/IPipeline.cs
+++ b/Ryujinx.Graphics.GAL/IPipeline.cs
@@ -48,6 +48,8 @@ namespace Ryujinx.Graphics.GAL
 
         void SetProgram(IProgram program);
 
+        void SetRasterizerDiscard(bool discard);
+
         void SetRenderTargetColorMasks(uint[] componentMask);
 
         void SetRenderTargets(ITexture[] colors, ITexture depthStencil);
diff --git a/Ryujinx.Graphics.Gpu/Constants.cs b/Ryujinx.Graphics.Gpu/Constants.cs
index cc476654ce..3175ebd2fa 100644
--- a/Ryujinx.Graphics.Gpu/Constants.cs
+++ b/Ryujinx.Graphics.Gpu/Constants.cs
@@ -53,6 +53,6 @@ namespace Ryujinx.Graphics.Gpu
         /// <summary>
         /// Maximum number of viewports.
         /// </summary>
-        public const int TotalViewports = 8;
+        public const int TotalViewports = 16;
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
index 18720440da..5091380143 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
@@ -108,6 +108,11 @@ namespace Ryujinx.Graphics.Gpu.Engine
                 UpdateShaderState(state);
             }
 
+            if (state.QueryModified(MethodOffset.RasterizeEnable))
+            {
+                UpdateRasterizerState(state);
+            }
+
             if (state.QueryModified(MethodOffset.RtColorState,
                                     MethodOffset.RtDepthStencilState,
                                     MethodOffset.RtControl,
@@ -211,6 +216,16 @@ namespace Ryujinx.Graphics.Gpu.Engine
             CommitBindings();
         }
 
+        /// <summary>
+        /// Updates Rasterizer primitive discard state based on guest gpu state.
+        /// </summary>
+        /// <param name="state">Current GPU state</param>
+        private void UpdateRasterizerState(GpuState state)
+        {
+            Boolean32 enable = state.Get<Boolean32>(MethodOffset.RasterizeEnable);
+            _context.Renderer.Pipeline.SetRasterizerDiscard(!enable);
+        }
+
         /// <summary>
         /// Ensures that the bindings are visible to the host GPU.
         /// Note: this actually performs the binding using the host graphics API.
diff --git a/Ryujinx.Graphics.Gpu/State/GpuState.cs b/Ryujinx.Graphics.Gpu/State/GpuState.cs
index de09f3e7da..4b81029c43 100644
--- a/Ryujinx.Graphics.Gpu/State/GpuState.cs
+++ b/Ryujinx.Graphics.Gpu/State/GpuState.cs
@@ -117,6 +117,9 @@ namespace Ryujinx.Graphics.Gpu.State
         /// </summary>
         private void InitializeDefaultState()
         {
+            // Enable Rasterizer
+            _backingMemory[(int)MethodOffset.RasterizeEnable] = 1;
+
             // Depth ranges.
             for (int index = 0; index < 8; index++)
             {
diff --git a/Ryujinx.Graphics.Gpu/State/GpuStateTable.cs b/Ryujinx.Graphics.Gpu/State/GpuStateTable.cs
index 8631efcc1f..e59a3aafbf 100644
--- a/Ryujinx.Graphics.Gpu/State/GpuStateTable.cs
+++ b/Ryujinx.Graphics.Gpu/State/GpuStateTable.cs
@@ -53,11 +53,11 @@ namespace Ryujinx.Graphics.Gpu.State
         public static TableItem[] Table = new TableItem[]
         {
             new TableItem(MethodOffset.RtColorState,           typeof(RtColorState),          8),
-            new TableItem(MethodOffset.ViewportTransform,      typeof(ViewportTransform),     8),
-            new TableItem(MethodOffset.ViewportExtents,        typeof(ViewportExtents),       8),
+            new TableItem(MethodOffset.ViewportTransform,      typeof(ViewportTransform),     Constants.TotalViewports),
+            new TableItem(MethodOffset.ViewportExtents,        typeof(ViewportExtents),       Constants.TotalViewports),
             new TableItem(MethodOffset.VertexBufferDrawState,  typeof(VertexBufferDrawState), 1),
             new TableItem(MethodOffset.DepthBiasState,         typeof(DepthBiasState),        1),
-            new TableItem(MethodOffset.ScissorState,           typeof(ScissorState),          8),
+            new TableItem(MethodOffset.ScissorState,           typeof(ScissorState),          Constants.TotalViewports),
             new TableItem(MethodOffset.StencilBackMasks,       typeof(StencilBackMasks),      1),
             new TableItem(MethodOffset.RtDepthStencilState,    typeof(RtDepthStencilState),   1),
             new TableItem(MethodOffset.VertexAttribState,      typeof(VertexAttribState),     16),
diff --git a/Ryujinx.Graphics.Gpu/State/MethodOffset.cs b/Ryujinx.Graphics.Gpu/State/MethodOffset.cs
index 0a720b2c48..a178c2f8c3 100644
--- a/Ryujinx.Graphics.Gpu/State/MethodOffset.cs
+++ b/Ryujinx.Graphics.Gpu/State/MethodOffset.cs
@@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.Gpu.State
         DispatchParamsAddress           = 0xad,
         Dispatch                        = 0xaf,
         CopyBuffer                      = 0xc0,
+        RasterizeEnable                 = 0xdf,
         CopyBufferParams                = 0x100,
         CopyBufferSwizzle               = 0x1c2,
         CopyBufferDstTexture            = 0x1c3,
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index 3480cf82cc..aef3383b16 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.OpenGL
     {
         private Program _program;
 
+        private bool _rasterizerDiscard;
+
         private VertexArray _vertexArray;
         private Framebuffer _framebuffer;
 
@@ -31,14 +33,13 @@ namespace Ryujinx.Graphics.OpenGL
 
         private uint[] _componentMasks;
 
-        private readonly bool[] _scissorEnable;
+        private bool _scissor0Enable = false;
 
         internal Pipeline()
         {
+            _rasterizerDiscard = false;
             _clipOrigin = ClipOrigin.LowerLeft;
             _clipDepthMode = ClipDepthMode.NegativeOneToOne;
-
-            _scissorEnable = new bool[8];
         }
 
         public void Barrier()
@@ -644,6 +645,20 @@ namespace Ryujinx.Graphics.OpenGL
             _program.Bind();
         }
 
+        public void SetRasterizerDiscard(bool discard)
+        {
+            if (discard)
+            {
+                GL.Enable(EnableCap.RasterizerDiscard);
+            }
+            else
+            {
+                GL.Disable(EnableCap.RasterizerDiscard);
+            }
+
+            _rasterizerDiscard = discard;
+        }
+
         public void SetRenderTargetColorMasks(uint[] componentMasks)
         {
             _componentMasks = (uint[])componentMasks.Clone();
@@ -697,7 +712,10 @@ namespace Ryujinx.Graphics.OpenGL
                 GL.Disable(IndexedEnableCap.ScissorTest, index);
             }
 
-            _scissorEnable[index] = enable;
+            if (index == 0)
+            {
+                _scissor0Enable = enable;
+            }
         }
 
         public void SetScissor(int index, int x, int y, int width, int height)
@@ -959,14 +977,19 @@ namespace Ryujinx.Graphics.OpenGL
             }
         }
 
-        public void RestoreScissorEnable()
+        public void RestoreScissor0Enable()
         {
-            for (int index = 0; index < 8; index++)
+            if (_scissor0Enable)
             {
-                if (_scissorEnable[index])
-                {
-                    GL.Enable(IndexedEnableCap.ScissorTest, index);
-                }
+                GL.Enable(IndexedEnableCap.ScissorTest, 0);
+            }
+        }
+
+        public void RestoreRasterizerDiscard()
+        {
+            if (_rasterizerDiscard)
+            {
+                GL.Enable(EnableCap.RasterizerDiscard);
             }
         }
 
diff --git a/Ryujinx.Graphics.OpenGL/TextureCopy.cs b/Ryujinx.Graphics.OpenGL/TextureCopy.cs
index ac9459d4aa..59db94a47c 100644
--- a/Ryujinx.Graphics.OpenGL/TextureCopy.cs
+++ b/Ryujinx.Graphics.OpenGL/TextureCopy.cs
@@ -41,7 +41,8 @@ namespace Ryujinx.Graphics.OpenGL
             GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
             GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
 
-            GL.Disable(EnableCap.ScissorTest);
+            GL.Disable(EnableCap.RasterizerDiscard);
+            GL.Disable(IndexedEnableCap.ScissorTest, 0);
 
             GL.BlitFramebuffer(
                 srcRegion.X1,
@@ -58,7 +59,8 @@ namespace Ryujinx.Graphics.OpenGL
             GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
             GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);
 
-            ((Pipeline)_renderer.Pipeline).RestoreScissorEnable();
+            ((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
+            ((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
         }
 
         private static void Attach(FramebufferTarget target, Format format, int handle)
diff --git a/Ryujinx.Graphics.OpenGL/Window.cs b/Ryujinx.Graphics.OpenGL/Window.cs
index c9b7daeb95..9f0007c4d8 100644
--- a/Ryujinx.Graphics.OpenGL/Window.cs
+++ b/Ryujinx.Graphics.OpenGL/Window.cs
@@ -59,7 +59,8 @@ namespace Ryujinx.Graphics.OpenGL
 
             GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
 
-            GL.Disable(EnableCap.ScissorTest);
+            GL.Disable(EnableCap.RasterizerDiscard);
+            GL.Disable(IndexedEnableCap.ScissorTest, 0);
 
             GL.Clear(ClearBufferMask.ColorBufferBit);
 
@@ -126,7 +127,8 @@ namespace Ryujinx.Graphics.OpenGL
             GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
             GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);
 
-            ((Pipeline)_renderer.Pipeline).RestoreScissorEnable();
+            ((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
+            ((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
         }
 
         private int GetCopyFramebufferHandleLazy()