diff options
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine')
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; |