Handle mismatching texture size with copy dependencies (#4364)

* Handle mismatching texture size with copy dependencies

* Create copy and render textures with the minimum possible size

* Only align width for comparisons, assume that height is always exact

* Fix IsExactMatch size check

* Allow sampler and copy textures to match textures with larger width

* Delete texture ChangeSize related code

* Move AdjustSize to TextureInfo and give it a better name, adjust usages

* Fix GetMinimumWidthInGob when minimumWidth > width

* Only update render targets that are actually cleared for clear

Avoids creating textures with incorrect sizes

* Delete UpdateRenderTargetState method that is not needed anymore

Clears now only ever sets the render targets that will be cleared rather than all of them
This commit is contained in:
gdkchan 2023-02-08 04:48:09 -03:00 committed by GitHub
parent 59755818ef
commit 96cf242bcf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 271 additions and 406 deletions

View file

@ -725,10 +725,25 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
return;
}
bool clearDepth = (argument & 1) != 0;
bool clearStencil = (argument & 2) != 0;
uint componentMask = (uint)((argument >> 2) & 0xf);
int index = (argument >> 6) & 0xf;
int layer = (argument >> 10) & 0x3ff;
engine.UpdateRenderTargetState(useControl: false, layered: layer != 0 || layerCount > 1, singleUse: index);
RenderTargetUpdateFlags updateFlags = RenderTargetUpdateFlags.SingleColor;
if (layer != 0 || layerCount > 1)
{
updateFlags |= RenderTargetUpdateFlags.Layered;
}
if (clearDepth || clearStencil)
{
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
@ -788,18 +803,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_context.Renderer.Pipeline.SetScissors(scissors);
}
if (clipMismatch)
{
_channel.TextureManager.UpdateRenderTarget(index);
}
else
{
_channel.TextureManager.UpdateRenderTargets();
}
bool clearDepth = (argument & 1) != 0;
bool clearStencil = (argument & 2) != 0;
uint componentMask = (uint)((argument >> 2) & 0xf);
_channel.TextureManager.UpdateRenderTargets();
if (componentMask != 0)
{
@ -841,7 +845,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
engine.UpdateScissorState();
}
engine.UpdateRenderTargetState(useControl: true);
engine.UpdateRenderTargetState(RenderTargetUpdateFlags.UpdateAll);
if (renderEnable == ConditionalRenderEnabled.Host)
{

View file

@ -0,0 +1,41 @@
using System;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
/// <summary>
/// Flags indicating how the render targets should be updated.
/// </summary>
[Flags]
enum RenderTargetUpdateFlags
{
/// <summary>
/// No flags.
/// </summary>
None = 0,
/// <summary>
/// Get render target index from the control register.
/// </summary>
UseControl = 1 << 0,
/// <summary>
/// Indicates that all render targets are 2D array textures.
/// </summary>
Layered = 1 << 1,
/// <summary>
/// Indicates that only a single color target will be used.
/// </summary>
SingleColor = 1 << 2,
/// <summary>
/// Indicates that the depth-stencil target will be used.
/// </summary>
UpdateDepthStencil = 1 << 3,
/// <summary>
/// Default update flags for draw.
/// </summary>
UpdateAll = UseControl | UpdateDepthStencil
}
}

View file

@ -402,20 +402,23 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary>
private void UpdateRenderTargetState()
{
UpdateRenderTargetState(true);
UpdateRenderTargetState(RenderTargetUpdateFlags.UpdateAll);
}
/// <summary>
/// Updates render targets (color and depth-stencil buffers) based on current render target state.
/// </summary>
/// <param name="useControl">Use draw buffers information from render target control register</param>
/// <param name="layered">Indicates if the texture is layered</param>
/// <param name="updateFlags">Flags indicating which render targets should be updated and how</param>
/// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
public void UpdateRenderTargetState(bool useControl, bool layered = false, int singleUse = -1)
public void UpdateRenderTargetState(RenderTargetUpdateFlags updateFlags, int singleUse = -1)
{
var memoryManager = _channel.MemoryManager;
var rtControl = _state.State.RtControl;
bool useControl = updateFlags.HasFlag(RenderTargetUpdateFlags.UseControl);
bool layered = updateFlags.HasFlag(RenderTargetUpdateFlags.Layered);
bool singleColor = updateFlags.HasFlag(RenderTargetUpdateFlags.SingleColor);
int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
var msaaMode = _state.State.RtMsaaMode;
@ -438,7 +441,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
var colorState = _state.State.RtColorState[rtIndex];
if (index >= count || !IsRtEnabled(colorState))
if (index >= count || !IsRtEnabled(colorState) || (singleColor && index != singleUse))
{
changedScale |= _channel.TextureManager.SetRenderTargetColor(index, null);
@ -478,7 +481,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
Image.Texture depthStencil = null;
if (dsEnable)
if (dsEnable && updateFlags.HasFlag(RenderTargetUpdateFlags.UpdateDepthStencil))
{
var dsState = _state.State.RtDepthStencilState;
var dsSize = _state.State.RtDepthStencilSize;

View file

@ -139,12 +139,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <summary>
/// Updates render targets (color and depth-stencil buffers) based on current render target state.
/// </summary>
/// <param name="useControl">Use draw buffers information from render target control register</param>
/// <param name="layered">Indicates if the texture is layered</param>
/// <param name="updateFlags">Flags indicating which render targets should be updated and how</param>
/// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
public void UpdateRenderTargetState(bool useControl, bool layered = false, int singleUse = -1)
public void UpdateRenderTargetState(RenderTargetUpdateFlags updateFlags, int singleUse = -1)
{
_stateUpdater.UpdateRenderTargetState(useControl, layered, singleUse);
_stateUpdater.UpdateRenderTargetState(updateFlags, singleUse);
}
/// <summary>