Fix render target clear when sizes mismatch (#2994)

This commit is contained in:
gdkchan 2022-01-11 16:15:17 -03:00 committed by GitHub
parent ef24c8983d
commit 6e0799580f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 181 additions and 25 deletions

View file

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