aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Engine
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine')
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs69
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs33
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs8
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs4
4 files changed, 107 insertions, 7 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
index 8f69eaa7..b705d63e 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
@@ -1,5 +1,6 @@
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.Types;
+using System;
using System.Text;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
@@ -489,14 +490,62 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
return;
}
- // Scissor and rasterizer discard also affect clears.
- engine.UpdateState((1UL << StateUpdater.RasterizerStateIndex) | (1UL << StateUpdater.ScissorStateIndex));
-
int index = (argument >> 6) & 0xf;
engine.UpdateRenderTargetState(useControl: false, singleUse: index);
- _channel.TextureManager.UpdateRenderTargets();
+ // If there is a mismatch on the host clip region and the one explicitly defined by the guest
+ // on the screen scissor state, then we need to force only one texture to be bound to avoid
+ // host clipping.
+ var screenScissorState = _state.State.ScreenScissorState;
+
+ // Must happen after UpdateRenderTargetState to have up-to-date clip region values.
+ bool clipMismatch = (screenScissorState.X | screenScissorState.Y) != 0 ||
+ screenScissorState.Width != _channel.TextureManager.ClipRegionWidth ||
+ screenScissorState.Height != _channel.TextureManager.ClipRegionHeight;
+
+ bool clearAffectedByStencilMask = (_state.State.ClearFlags & 1) != 0;
+ bool clearAffectedByScissor = (_state.State.ClearFlags & 0x100) != 0;
+ bool needsCustomScissor = !clearAffectedByScissor || clipMismatch;
+
+ // Scissor and rasterizer discard also affect clears.
+ ulong updateMask = 1UL << StateUpdater.RasterizerStateIndex;
+
+ if (!needsCustomScissor)
+ {
+ updateMask |= 1UL << StateUpdater.ScissorStateIndex;
+ }
+
+ engine.UpdateState(updateMask);
+
+ if (needsCustomScissor)
+ {
+ int scissorX = screenScissorState.X;
+ int scissorY = screenScissorState.Y;
+ int scissorW = screenScissorState.Width;
+ int scissorH = screenScissorState.Height;
+
+ if (clearAffectedByScissor)
+ {
+ ref var scissorState = ref _state.State.ScissorState[0];
+
+ scissorX = Math.Max(scissorX, scissorState.X1);
+ scissorY = Math.Max(scissorY, scissorState.Y1);
+ scissorW = Math.Min(scissorW, scissorState.X2 - scissorState.X1);
+ scissorH = Math.Min(scissorH, scissorState.Y2 - scissorState.Y1);
+ }
+
+ _context.Renderer.Pipeline.SetScissor(0, true, scissorX, scissorY, scissorW, scissorH);
+ }
+
+ if (clipMismatch)
+ {
+ _channel.TextureManager.UpdateRenderTarget(index);
+ }
+ else
+ {
+ _channel.TextureManager.UpdateRenderTargets();
+ }
bool clearDepth = (argument & 1) != 0;
bool clearStencil = (argument & 2) != 0;
@@ -521,7 +570,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
if (clearStencil)
{
- stencilMask = _state.State.StencilTestState.FrontMask;
+ stencilMask = clearAffectedByStencilMask ? _state.State.StencilTestState.FrontMask : 0xff;
+ }
+
+ if (clipMismatch)
+ {
+ _channel.TextureManager.UpdateRenderTargetDepthStencil();
}
_context.Renderer.Pipeline.ClearRenderTargetDepthStencil(
@@ -531,6 +585,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
stencilMask);
}
+ if (needsCustomScissor)
+ {
+ engine.UpdateScissorState();
+ }
+
engine.UpdateRenderTargetState(useControl: true);
if (renderEnable == ConditionalRenderEnabled.Host)
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index 9f6ee17c..1228a944 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -339,6 +339,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
var scissor = _state.State.ScreenScissorState;
Size sizeHint = new Size(scissor.X + scissor.Width, scissor.Y + scissor.Height, 1);
+ int clipRegionWidth = int.MaxValue;
+ int clipRegionHeight = int.MaxValue;
+
bool changedScale = false;
for (int index = 0; index < Constants.TotalRenderTargets; index++)
@@ -363,6 +366,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
sizeHint);
changedScale |= _channel.TextureManager.SetRenderTargetColor(index, color);
+
+ if (color != null)
+ {
+ if (clipRegionWidth > color.Width)
+ {
+ clipRegionWidth = color.Width;
+ }
+
+ if (clipRegionHeight > color.Height)
+ {
+ clipRegionHeight = color.Height;
+ }
+ }
}
bool dsEnable = _state.State.RtDepthStencilEnable;
@@ -381,6 +397,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
samplesInX,
samplesInY,
sizeHint);
+
+ if (depthStencil != null)
+ {
+ if (clipRegionWidth > depthStencil.Width)
+ {
+ clipRegionWidth = depthStencil.Width;
+ }
+
+ if (clipRegionHeight > depthStencil.Height)
+ {
+ clipRegionHeight = depthStencil.Height;
+ }
+ }
}
changedScale |= _channel.TextureManager.SetRenderTargetDepthStencil(depthStencil);
@@ -398,6 +427,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
UpdateScissorState();
}
}
+
+ _channel.TextureManager.SetClipRegion(clipRegionWidth, clipRegionHeight);
}
/// <summary>
@@ -414,7 +445,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <summary>
/// Updates host scissor test state based on current GPU state.
/// </summary>
- private void UpdateScissorState()
+ public void UpdateScissorState()
{
for (int index = 0; index < Constants.TotalViewports; index++)
{
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
index f6de2730..a2e8c64c 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
@@ -138,6 +138,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
}
/// <summary>
+ /// Updates scissor based on current render target state.
+ /// </summary>
+ public void UpdateScissorState()
+ {
+ _stateUpdater.UpdateScissorState();
+ }
+
+ /// <summary>
/// Marks the entire state as dirty, forcing a full host state update before the next draw.
/// </summary>
public void ForceStateDirty()
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
index 9d8ad765..a6a5a2ab 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
@@ -754,7 +754,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
public int DrawTextureTextureId;
public int DrawTextureSrcX;
public int DrawTextureSrcY;
- public fixed uint Reserved10B0[44];
+ public fixed uint Reserved10B0[18];
+ public uint ClearFlags;
+ public fixed uint Reserved10FC[25];
public Array16<VertexAttribState> VertexAttribState;
public fixed uint Reserved11A0[31];
public RtControl RtControl;