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/Image/TextureInfo.cs | 85 +++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) (limited to 'Ryujinx.Graphics.Gpu/Image/TextureInfo.cs') diff --git a/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs b/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs index 65cc698b..a7ee12bc 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs @@ -1,5 +1,7 @@ +using Ryujinx.Common; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Texture; +using System; namespace Ryujinx.Graphics.Gpu.Image { @@ -292,5 +294,88 @@ namespace Ryujinx.Graphics.Gpu.Image layerSize); } } + + /// + /// Creates texture information for a given mipmap level of the specified parent texture and this information. + /// + /// The parent texture + /// The first level of the texture view + /// The adjusted texture information with the new size + public TextureInfo CreateInfoForLevelView(Texture parent, int firstLevel) + { + // When the texture is used as view of another texture, we must + // ensure that the sizes are valid, otherwise data uploads would fail + // (and the size wouldn't match the real size used on the host API). + // Given a parent texture from where the view is created, we have the + // following rules: + // - The view size must be equal to the parent size, divided by (2 ^ l), + // where l is the first mipmap level of the view. The division result must + // be rounded down, and the result must be clamped to 1. + // - If the parent format is compressed, and the view format isn't, the + // view size is calculated as above, but the width and height of the + // view must be also divided by the compressed format block width and height. + // - If the parent format is not compressed, and the view is, the view + // size is calculated as described on the first point, but the width and height + // of the view must be also multiplied by the block width and height. + int width = Math.Max(1, parent.Info.Width >> firstLevel); + int height = Math.Max(1, parent.Info.Height >> firstLevel); + + if (parent.Info.FormatInfo.IsCompressed && !FormatInfo.IsCompressed) + { + width = BitUtils.DivRoundUp(width, parent.Info.FormatInfo.BlockWidth); + height = BitUtils.DivRoundUp(height, parent.Info.FormatInfo.BlockHeight); + } + else if (!parent.Info.FormatInfo.IsCompressed && FormatInfo.IsCompressed) + { + width *= FormatInfo.BlockWidth; + height *= FormatInfo.BlockHeight; + } + + int depthOrLayers; + + if (Target == Target.Texture3D) + { + depthOrLayers = Math.Max(1, parent.Info.DepthOrLayers >> firstLevel); + } + else + { + depthOrLayers = DepthOrLayers; + } + + // 2D and 2D multisample textures are not considered compatible. + // This specific case is required for copies, where the source texture might be multisample. + // In this case, we inherit the parent texture multisample state. + Target target = Target; + int samplesInX = SamplesInX; + int samplesInY = SamplesInY; + + if (target == Target.Texture2D && parent.Target == Target.Texture2DMultisample) + { + target = Target.Texture2DMultisample; + samplesInX = parent.Info.SamplesInX; + samplesInY = parent.Info.SamplesInY; + } + + return new TextureInfo( + GpuAddress, + width, + height, + depthOrLayers, + Levels, + samplesInX, + samplesInY, + Stride, + IsLinear, + GobBlocksInY, + GobBlocksInZ, + GobBlocksInTileX, + target, + FormatInfo, + DepthStencilMode, + SwizzleR, + SwizzleG, + SwizzleB, + SwizzleA); + } } } \ No newline at end of file -- cgit v1.2.3