Fix render target clear when sizes mismatch (#2994)
This commit is contained in:
parent
ef24c8983d
commit
6e0799580f
9 changed files with 181 additions and 25 deletions
|
@ -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)
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -137,6 +137,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||
_stateUpdater.UpdateRenderTargetState(useControl, singleUse);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue