From 96cf242bcf168b9f9e6a1e27200529466217f396 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 8 Feb 2023 04:48:09 -0300 Subject: 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 --- Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs | 32 +++++++++-------- .../Engine/Threed/RenderTargetUpdateFlags.cs | 41 ++++++++++++++++++++++ Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs | 15 ++++---- Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs | 7 ++-- 4 files changed, 71 insertions(+), 24 deletions(-) create mode 100644 Ryujinx.Graphics.Gpu/Engine/Threed/RenderTargetUpdateFlags.cs (limited to 'Ryujinx.Graphics.Gpu/Engine') diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs index 0f249512..61f227d9 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs @@ -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) { diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/RenderTargetUpdateFlags.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/RenderTargetUpdateFlags.cs new file mode 100644 index 00000000..cf2e818c --- /dev/null +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/RenderTargetUpdateFlags.cs @@ -0,0 +1,41 @@ +using System; + +namespace Ryujinx.Graphics.Gpu.Engine.Threed +{ + /// + /// Flags indicating how the render targets should be updated. + /// + [Flags] + enum RenderTargetUpdateFlags + { + /// + /// No flags. + /// + None = 0, + + /// + /// Get render target index from the control register. + /// + UseControl = 1 << 0, + + /// + /// Indicates that all render targets are 2D array textures. + /// + Layered = 1 << 1, + + /// + /// Indicates that only a single color target will be used. + /// + SingleColor = 1 << 2, + + /// + /// Indicates that the depth-stencil target will be used. + /// + UpdateDepthStencil = 1 << 3, + + /// + /// Default update flags for draw. + /// + UpdateAll = UseControl | UpdateDepthStencil + } +} diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index 9b59009c..9b58e014 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -402,20 +402,23 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// private void UpdateRenderTargetState() { - UpdateRenderTargetState(true); + UpdateRenderTargetState(RenderTargetUpdateFlags.UpdateAll); } /// /// Updates render targets (color and depth-stencil buffers) based on current render target state. /// - /// Use draw buffers information from render target control register - /// Indicates if the texture is layered + /// Flags indicating which render targets should be updated and how /// If this is not -1, it indicates that only the given indexed target will be used. - 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; diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs index 19eb8b46..9a447a0b 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs @@ -139,12 +139,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed /// /// Updates render targets (color and depth-stencil buffers) based on current render target state. /// - /// Use draw buffers information from render target control register - /// Indicates if the texture is layered + /// Flags indicating which render targets should be updated and how /// If this is not -1, it indicates that only the given indexed target will be used. - 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); } /// -- cgit v1.2.3