From 3139a85a2b8e83aa6babfbc683bd46ca1d75e448 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 8 Apr 2022 06:26:48 -0300 Subject: [PATCH] Allow copy texture views to have mismatching multisample state (#3152) --- Ryujinx.Graphics.Gpu/Image/Texture.cs | 25 ++++++++++---- Ryujinx.Graphics.Gpu/Image/TextureCache.cs | 38 +++++++++++++++++++--- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index e1f00606..cfb7a3b7 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -1136,17 +1136,33 @@ namespace Ryujinx.Graphics.Gpu.Image /// Texture view physical memory ranges /// Layer size on the given texture /// Host GPU capabilities + /// Indicates that multisample textures are allowed to match non-multisample requested textures /// Texture view initial layer on this texture /// Texture view first mipmap level on this texture /// The level of compatiblilty a view with the given parameters created from this texture has - public TextureViewCompatibility IsViewCompatible(TextureInfo info, MultiRange range, int layerSize, Capabilities caps, out int firstLayer, out int firstLevel) + public TextureViewCompatibility IsViewCompatible(TextureInfo info, MultiRange range, int layerSize, Capabilities caps, bool allowMs, out int firstLayer, out int firstLevel) { TextureViewCompatibility result = TextureViewCompatibility.Full; result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewFormatCompatible(Info, info, caps)); if (result != TextureViewCompatibility.Incompatible) { - result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info)); + bool msTargetCompatible = false; + + if (allowMs) + { + msTargetCompatible = Info.Target == Target.Texture2DMultisample && info.Target == Target.Texture2D; + } + + if (!msTargetCompatible) + { + result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info)); + + if (Info.SamplesInX != info.SamplesInX || Info.SamplesInY != info.SamplesInY) + { + result = TextureViewCompatibility.Incompatible; + } + } if (result == TextureViewCompatibility.Full && Info.FormatInfo.Format != info.FormatInfo.Format && !_context.Capabilities.SupportsMismatchingViewFormat) { @@ -1156,11 +1172,6 @@ namespace Ryujinx.Graphics.Gpu.Image result = TextureViewCompatibility.CopyOnly; } - - if (Info.SamplesInX != info.SamplesInX || Info.SamplesInY != info.SamplesInY) - { - result = TextureViewCompatibility.Incompatible; - } } firstLayer = 0; diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs index 16248308..4fa80c95 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs @@ -542,7 +542,14 @@ namespace Ryujinx.Graphics.Gpu.Image for (int index = 0; index < overlapsCount; index++) { Texture overlap = _textureOverlaps[index]; - TextureViewCompatibility overlapCompatibility = overlap.IsViewCompatible(info, range.Value, sizeInfo.LayerSize, _context.Capabilities, out int firstLayer, out int firstLevel); + TextureViewCompatibility overlapCompatibility = overlap.IsViewCompatible( + info, + range.Value, + sizeInfo.LayerSize, + _context.Capabilities, + flags.HasFlag(TextureSearchFlags.ForCopy), + out int firstLayer, + out int firstLevel); if (overlapCompatibility == TextureViewCompatibility.Full) { @@ -650,7 +657,14 @@ namespace Ryujinx.Graphics.Gpu.Image Texture overlap = _textureOverlaps[index]; bool overlapInCache = overlap.CacheNode != null; - TextureViewCompatibility compatibility = texture.IsViewCompatible(overlap.Info, overlap.Range, overlap.LayerSize, _context.Capabilities, out int firstLayer, out int firstLevel); + TextureViewCompatibility compatibility = texture.IsViewCompatible( + overlap.Info, + overlap.Range, + overlap.LayerSize, + _context.Capabilities, + false, + out int firstLayer, + out int firstLevel); if (overlap.IsView && compatibility == TextureViewCompatibility.Full) { @@ -1000,20 +1014,34 @@ namespace Ryujinx.Graphics.Gpu.Image depthOrLayers = info.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 = info.Target; + int samplesInX = info.SamplesInX; + int samplesInY = info.SamplesInY; + + if (target == Target.Texture2D && parent.Target == Target.Texture2DMultisample) + { + target = Target.Texture2DMultisample; + samplesInX = parent.Info.SamplesInX; + samplesInY = parent.Info.SamplesInY; + } + return new TextureInfo( info.GpuAddress, width, height, depthOrLayers, info.Levels, - info.SamplesInX, - info.SamplesInY, + samplesInX, + samplesInY, info.Stride, info.IsLinear, info.GobBlocksInY, info.GobBlocksInZ, info.GobBlocksInTileX, - info.Target, + target, info.FormatInfo, info.DepthStencilMode, info.SwizzleR,