diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs')
-rw-r--r-- | src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs index 18e7ac00..1c31312c 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs @@ -1,6 +1,7 @@ using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw; using Ryujinx.Graphics.Gpu.Engine.Types; +using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Gpu.Memory; using System; @@ -806,25 +807,69 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed updateFlags |= RenderTargetUpdateFlags.Layered; } - if (clearDepth || clearStencil) + bool clearDS = clearDepth || clearStencil; + + if (clearDS) { updateFlags |= RenderTargetUpdateFlags.UpdateDepthStencil; } - engine.UpdateRenderTargetState(updateFlags, singleUse: componentMask != 0 ? index : -1); - // 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; + bool clearAffectedByStencilMask = (_state.State.ClearFlags & 1) != 0; + bool clearAffectedByScissor = (_state.State.ClearFlags & 0x100) != 0; + + if (clearDS || componentMask == 15) + { + // A full clear if scissor is disabled, or it matches the screen scissor state. + + bool fullClear = screenScissorState.X == 0 && screenScissorState.Y == 0; + + if (fullClear && clearAffectedByScissor && _state.State.ScissorState[0].Enable) + { + ref var scissorState = ref _state.State.ScissorState[0]; + + fullClear = scissorState.X1 == screenScissorState.X && + scissorState.Y1 == screenScissorState.Y && + scissorState.X2 >= screenScissorState.X + screenScissorState.Width && + scissorState.Y2 >= screenScissorState.Y + screenScissorState.Height; + } + + if (fullClear && clearDS) + { + // Must clear all aspects of the depth-stencil format. + + FormatInfo dsFormat = _state.State.RtDepthStencilState.Format.Convert(); + + bool hasDepth = dsFormat.Format.HasDepth(); + bool hasStencil = dsFormat.Format.HasStencil(); + + if (hasStencil && (!clearStencil || (clearAffectedByStencilMask && _state.State.StencilTestState.FrontMask != 0xff))) + { + fullClear = false; + } + else if (hasDepth && !clearDepth) + { + fullClear = false; + } + } + + if (fullClear) + { + updateFlags |= RenderTargetUpdateFlags.DiscardClip; + } + } + + engine.UpdateRenderTargetState(updateFlags, singleUse: componentMask != 0 ? index : -1); + // 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. |