From 30b7aaefcad65f7b3487eb615e41f6445eda2f75 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Sun, 21 Nov 2021 10:25:03 -0300
Subject: [PATCH] Better depth range detection (#2754)

* Better depth range detection

* PR feedback

* Move depth mode set out of the loop and to a separate method
---
 .../Engine/Threed/StateUpdater.cs             | 61 +++++++++++++------
 1 file changed, 41 insertions(+), 20 deletions(-)

diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index 4a5633c9c6..cf74f649ec 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -485,6 +485,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
             var face = _state.State.FaceState;
 
             UpdateFrontFace(yControl, face.FrontFace);
+            UpdateDepthMode();
 
             bool flipY = yControl.HasFlag(YControl.NegateY);
 
@@ -492,8 +493,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
 
             for (int index = 0; index < Constants.TotalViewports; index++)
             {
-                var transform = _state.State.ViewportTransform[index];
-                var extents = _state.State.ViewportExtents[index];
+                ref var transform = ref _state.State.ViewportTransform[index];
+                ref var extents = ref _state.State.ViewportExtents[index];
 
                 float scaleX = MathF.Abs(transform.ScaleX);
                 float scaleY = transform.ScaleY;
@@ -508,24 +509,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
                     scaleY = -scaleY;
                 }
 
-                if (index == 0)
-                {
-                    // Try to guess the depth mode being used on the high level API
-                    // based on current transform.
-                    // It is setup like so by said APIs:
-                    // If depth mode is ZeroToOne:
-                    //  TranslateZ = Near
-                    //  ScaleZ = Far - Near
-                    // If depth mode is MinusOneToOne:
-                    //  TranslateZ = (Near + Far) / 2
-                    //  ScaleZ = (Far - Near) / 2
-                    // DepthNear/Far are sorted such as that Near is always less than Far.
-                    DepthMode depthMode = extents.DepthNear != transform.TranslateZ &&
-                                          extents.DepthFar != transform.TranslateZ ? DepthMode.MinusOneToOne : DepthMode.ZeroToOne;
-
-                    _context.Renderer.Pipeline.SetDepthMode(depthMode);
-                }
-
                 float x = transform.TranslateX - scaleX;
                 float y = transform.TranslateY - scaleY;
 
@@ -564,6 +547,44 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
             _context.Renderer.Pipeline.SetViewports(0, viewports);
         }
 
+        /// <summary>
+        /// Updates the depth mode (0 to 1 or -1 to 1) based on the current viewport and depth mode register state.
+        /// </summary>
+        private void UpdateDepthMode()
+        {
+            ref var transform = ref _state.State.ViewportTransform[0];
+            ref var extents = ref _state.State.ViewportExtents[0];
+
+            DepthMode depthMode;
+
+            if (!float.IsInfinity(extents.DepthNear) &&
+                !float.IsInfinity(extents.DepthFar) &&
+                (extents.DepthFar - extents.DepthNear) != 0)
+            {
+                // Try to guess the depth mode being used on the high level API
+                // based on current transform.
+                // It is setup like so by said APIs:
+                // If depth mode is ZeroToOne:
+                //  TranslateZ = Near
+                //  ScaleZ = Far - Near
+                // If depth mode is MinusOneToOne:
+                //  TranslateZ = (Near + Far) / 2
+                //  ScaleZ = (Far - Near) / 2
+                // DepthNear/Far are sorted such as that Near is always less than Far.
+                depthMode = extents.DepthNear != transform.TranslateZ &&
+                            extents.DepthFar  != transform.TranslateZ
+                    ? DepthMode.MinusOneToOne
+                    : DepthMode.ZeroToOne;
+            }
+            else
+            {
+                // If we can't guess from the viewport transform, then just use the depth mode register.
+                depthMode = (DepthMode)(_state.State.DepthMode & 1);
+            }
+
+            _context.Renderer.Pipeline.SetDepthMode(depthMode);
+        }
+
         /// <summary>
         /// Updates polygon mode state based on current GPU state.
         /// </summary>