GPU: Discard data when getting texture before full clear (#5719)

* GPU: Discard data when getting texture before full clear

* Fix rules and order of clear checks

* Fix formatting
This commit is contained in:
riperiperi 2023-09-25 22:07:03 +01:00 committed by GitHub
parent 8026e1c804
commit f6c3f1cdfd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 205 additions and 11 deletions

View file

@ -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.