From bc19114bb5a14f4563aa4bee68bda97234a7bcb0 Mon Sep 17 00:00:00 2001 From: sharmander Date: Mon, 31 Aug 2020 20:06:27 -0400 Subject: [PATCH] Fix: Issue #1475 Texture Compatibility Check methods need to be centralized (#1482) * Texture Compatibility Check methods need to be centralized #1475 * Fix spacing * Fix spacing * Undo removal of .ToString() * Move isPerfectMatch back to Texture.cs Rename parameters in TextureCompatibility.cs for consistency * Add switch from 1474 to TextureCompatibility as requested by mageven. * Actually add TextureCompatibility changes to the PR (Add DeriveDepthFormat method) * Alignment corrections + Derive method signature adjustment. * Removed empty line as erquested * Remove empty lines * Remove blank lines, fix alignment * Fix alignment * Remove emtpy line --- .../Engine/MethodCopyTexture.cs | 12 +- Ryujinx.Graphics.Gpu/Image/Texture.cs | 333 +---------------- .../Image/TextureCompatibility.cs | 339 ++++++++++++++++++ Ryujinx.Graphics.Gpu/Image/TextureManager.cs | 4 +- 4 files changed, 355 insertions(+), 333 deletions(-) diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs b/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs index af7ac038f..8e92685bc 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs @@ -1,4 +1,5 @@ using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Gpu.State; using System; @@ -28,16 +29,7 @@ namespace Ryujinx.Graphics.Gpu.Engine // When the source texture that was found has a depth format, // we must enforce the target texture also has a depth format, // as copies between depth and color formats are not allowed. - dstCopyTexture.Format = srcTexture.Format switch - { - Format.S8Uint => RtFormat.S8Uint, - Format.D16Unorm => RtFormat.D16Unorm, - Format.D24X8Unorm => RtFormat.D24Unorm, - Format.D32Float => RtFormat.D32Float, - Format.D24UnormS8Uint => RtFormat.D24UnormS8Uint, - Format.D32FloatS8Uint => RtFormat.D32FloatS8Uint, - _ => dstCopyTexture.Format - }; + dstCopyTexture.Format = TextureCompatibility.DeriveDepthFormat(dstCopyTexture.Format, srcTexture.Format); Texture dstTexture = TextureManager.FindOrCreateTexture(dstCopyTexture, srcTexture.ScaleMode == Image.TextureScaleMode.Scaled); diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index a312a8b7e..2a61b441c 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -659,32 +659,31 @@ namespace Ryujinx.Graphics.Gpu.Image } /// - /// Performs a comparison of this texture information, with the specified texture information. - /// This performs a strict comparison, used to check if two textures are equal. + /// This performs a strict comparison, used to check if this texture is equal to the one supplied. /// - /// Texture information to compare with + /// Texture information to compare against /// Comparison flags /// True if the textures are strictly equal or similar, false otherwise public bool IsPerfectMatch(TextureInfo info, TextureSearchFlags flags) { - if (!FormatMatches(info, (flags & TextureSearchFlags.ForSampler) != 0, (flags & TextureSearchFlags.ForCopy) != 0)) + if (!TextureCompatibility.FormatMatches(Info, info, (flags & TextureSearchFlags.ForSampler) != 0, (flags & TextureSearchFlags.ForCopy) != 0)) { return false; } - if (!LayoutMatches(info)) + if (!TextureCompatibility.LayoutMatches(Info, info)) { return false; } - if (!SizeMatches(info, (flags & TextureSearchFlags.Strict) == 0)) + if (!TextureCompatibility.SizeMatches(Info, info)) { return false; } if ((flags & TextureSearchFlags.ForSampler) != 0 || (flags & TextureSearchFlags.Strict) != 0) { - if (!SamplerParamsMatches(info)) + if (!TextureCompatibility.SamplerParamsMatches(Info, info)) { return false; } @@ -694,12 +693,12 @@ namespace Ryujinx.Graphics.Gpu.Image { bool msTargetCompatible = Info.Target == Target.Texture2DMultisample && info.Target == Target.Texture2D; - if (!msTargetCompatible && !TargetAndSamplesCompatible(info)) + if (!msTargetCompatible && !TextureCompatibility.TargetAndSamplesCompatible(Info, info)) { return false; } } - else if (!TargetAndSamplesCompatible(info)) + else if (!TextureCompatibility.TargetAndSamplesCompatible(Info, info)) { return false; } @@ -707,153 +706,6 @@ namespace Ryujinx.Graphics.Gpu.Image return Info.Address == info.Address && Info.Levels == info.Levels; } - /// - /// Checks if the texture format matches with the specified texture information. - /// - /// Texture information to compare with - /// Indicates that the texture will be used for shader sampling - /// Indicates that the texture will be used as copy source or target - /// True if the format matches, with the given comparison rules - private bool FormatMatches(TextureInfo info, bool forSampler, bool forCopy) - { - // D32F and R32F texture have the same representation internally, - // however the R32F format is used to sample from depth textures. - if (Info.FormatInfo.Format == Format.D32Float && info.FormatInfo.Format == Format.R32Float && (forSampler || forCopy)) - { - return true; - } - - if (forCopy) - { - // The 2D engine does not support depth-stencil formats, so it will instead - // use equivalent color formats. We must also consider them as compatible. - if (Info.FormatInfo.Format == Format.S8Uint && info.FormatInfo.Format == Format.R8Unorm) - { - return true; - } - - if (Info.FormatInfo.Format == Format.D16Unorm && info.FormatInfo.Format == Format.R16Unorm) - { - return true; - } - - if ((Info.FormatInfo.Format == Format.D24UnormS8Uint || - Info.FormatInfo.Format == Format.D24X8Unorm) && info.FormatInfo.Format == Format.B8G8R8A8Unorm) - { - return true; - } - } - - return Info.FormatInfo.Format == info.FormatInfo.Format; - } - - /// - /// Checks if the texture layout specified matches with this texture layout. - /// The layout information is composed of the Stride for linear textures, or GOB block size - /// for block linear textures. - /// - /// Texture information to compare with - /// True if the layout matches, false otherwise - private bool LayoutMatches(TextureInfo info) - { - if (Info.IsLinear != info.IsLinear) - { - return false; - } - - // For linear textures, gob block sizes are ignored. - // For block linear textures, the stride is ignored. - if (info.IsLinear) - { - return Info.Stride == info.Stride; - } - else - { - return Info.GobBlocksInY == info.GobBlocksInY && - Info.GobBlocksInZ == info.GobBlocksInZ; - } - } - - /// - /// Checks if the texture sizes of the supplied texture information matches this texture. - /// - /// Texture information to compare with - /// True if the size matches, false otherwise - public bool SizeMatches(TextureInfo info) - { - return SizeMatches(info, alignSizes: false); - } - - /// - /// Checks if the texture sizes of the supplied texture information matches the given level of - /// this texture. - /// - /// Texture information to compare with - /// Mipmap level of this texture to compare with - /// True if the size matches with the level, false otherwise - public bool SizeMatches(TextureInfo info, int level) - { - return Math.Max(1, Info.Width >> level) == info.Width && - Math.Max(1, Info.Height >> level) == info.Height && - Math.Max(1, Info.GetDepth() >> level) == info.GetDepth(); - } - - /// - /// Checks if the texture sizes of the supplied texture information matches this texture. - /// - /// Texture information to compare with - /// True to align the sizes according to the texture layout for comparison - /// True if the sizes matches, false otherwise - private bool SizeMatches(TextureInfo info, bool alignSizes) - { - if (Info.GetLayers() != info.GetLayers()) - { - return false; - } - - if (alignSizes) - { - Size size0 = GetAlignedSize(Info); - Size size1 = GetAlignedSize(info); - - return size0.Width == size1.Width && - size0.Height == size1.Height && - size0.Depth == size1.Depth; - } - else - { - return Info.Width == info.Width && - Info.Height == info.Height && - Info.GetDepth() == info.GetDepth(); - } - } - - /// - /// Checks if the texture shader sampling parameters matches. - /// - /// Texture information to compare with - /// True if the texture shader sampling parameters matches, false otherwise - private bool SamplerParamsMatches(TextureInfo info) - { - return Info.DepthStencilMode == info.DepthStencilMode && - Info.SwizzleR == info.SwizzleR && - Info.SwizzleG == info.SwizzleG && - Info.SwizzleB == info.SwizzleB && - Info.SwizzleA == info.SwizzleA; - } - - /// - /// Check if the texture target and samples count (for multisampled textures) matches. - /// - /// Texture information to compare with - /// True if the texture target and samples count matches, false otherwise - private bool TargetAndSamplesCompatible(TextureInfo info) - { - return Info.Target == info.Target && - Info.SamplesInX == info.SamplesInX && - Info.SamplesInY == info.SamplesInY; - } - /// /// Check if it's possible to create a view, with the given parameters, from this texture. /// @@ -903,22 +755,22 @@ namespace Ryujinx.Graphics.Gpu.Image return false; } - if (!ViewLayoutCompatible(info, firstLevel)) + if (!TextureCompatibility.ViewLayoutCompatible(Info, info, firstLevel)) { return false; } - if (!ViewFormatCompatible(info)) + if (!TextureCompatibility.ViewFormatCompatible(Info, info)) { return false; } - if (!ViewSizeMatches(info, firstLevel, isCopy)) + if (!TextureCompatibility.ViewSizeMatches(Info, info, firstLevel, isCopy)) { return false; } - if (!ViewTargetCompatible(info, isCopy)) + if (!TextureCompatibility.ViewTargetCompatible(Info, info, isCopy)) { return false; } @@ -927,167 +779,6 @@ namespace Ryujinx.Graphics.Gpu.Image Info.SamplesInY == info.SamplesInY; } - /// - /// Check if it's possible to create a view with the specified layout. - /// The layout information is composed of the Stride for linear textures, or GOB block size - /// for block linear textures. - /// - /// Texture information of the texture view - /// Start level of the texture view, in relation with this texture - /// True if the layout is compatible, false otherwise - private bool ViewLayoutCompatible(TextureInfo info, int level) - { - if (Info.IsLinear != info.IsLinear) - { - return false; - } - - // For linear textures, gob block sizes are ignored. - // For block linear textures, the stride is ignored. - if (info.IsLinear) - { - int width = Math.Max(1, Info.Width >> level); - - int stride = width * Info.FormatInfo.BytesPerPixel; - - stride = BitUtils.AlignUp(stride, 32); - - return stride == info.Stride; - } - else - { - int height = Math.Max(1, Info.Height >> level); - int depth = Math.Max(1, Info.GetDepth() >> level); - - (int gobBlocksInY, int gobBlocksInZ) = SizeCalculator.GetMipGobBlockSizes( - height, - depth, - Info.FormatInfo.BlockHeight, - Info.GobBlocksInY, - Info.GobBlocksInZ); - - return gobBlocksInY == info.GobBlocksInY && - gobBlocksInZ == info.GobBlocksInZ; - } - } - - /// - /// Checks if the view format is compatible with this texture format. - /// In general, the formats are considered compatible if the bytes per pixel values are equal, - /// but there are more complex rules for some formats, like compressed or depth-stencil formats. - /// This follows the host API copy compatibility rules. - /// - /// Texture information of the texture view - /// True if the formats are compatible, false otherwise - private bool ViewFormatCompatible(TextureInfo info) - { - return TextureCompatibility.FormatCompatible(Info.FormatInfo, info.FormatInfo); - } - - /// - /// Checks if the size of a given texture view is compatible with this texture. - /// - /// Texture information of the texture view - /// Mipmap level of the texture view in relation to this texture - /// True to check for copy compatibility rather than view compatibility - /// True if the sizes are compatible, false otherwise - private bool ViewSizeMatches(TextureInfo info, int level, bool isCopy) - { - Size size = GetAlignedSize(Info, level); - - Size otherSize = GetAlignedSize(info); - - // For copies, we can copy a subset of the 3D texture slices, - // so the depth may be different in this case. - if (!isCopy && info.Target == Target.Texture3D && size.Depth != otherSize.Depth) - { - return false; - } - - return size.Width == otherSize.Width && - size.Height == otherSize.Height; - } - - /// - /// Check if the target of the specified texture view information is compatible with this - /// texture. - /// This follows the host API target compatibility rules. - /// - /// Texture information of the texture view - /// True to check for copy rather than view compatibility - /// True if the targets are compatible, false otherwise - private bool ViewTargetCompatible(TextureInfo info, bool isCopy) - { - switch (Info.Target) - { - case Target.Texture1D: - case Target.Texture1DArray: - return info.Target == Target.Texture1D || - info.Target == Target.Texture1DArray; - - case Target.Texture2D: - return info.Target == Target.Texture2D || - info.Target == Target.Texture2DArray; - - case Target.Texture2DArray: - case Target.Cubemap: - case Target.CubemapArray: - return info.Target == Target.Texture2D || - info.Target == Target.Texture2DArray || - info.Target == Target.Cubemap || - info.Target == Target.CubemapArray; - - case Target.Texture2DMultisample: - case Target.Texture2DMultisampleArray: - return info.Target == Target.Texture2DMultisample || - info.Target == Target.Texture2DMultisampleArray; - - case Target.Texture3D: - return info.Target == Target.Texture3D || - (info.Target == Target.Texture2D && isCopy); - } - - return false; - } - - /// - /// Gets the aligned sizes of the specified texture information. - /// The alignment depends on the texture layout and format bytes per pixel. - /// - /// Texture information to calculate the aligned size from - /// Mipmap level for texture views - /// The aligned texture size - private static Size GetAlignedSize(TextureInfo info, int level = 0) - { - int width = Math.Max(1, info.Width >> level); - int height = Math.Max(1, info.Height >> level); - - if (info.IsLinear) - { - return SizeCalculator.GetLinearAlignedSize( - width, - height, - info.FormatInfo.BlockWidth, - info.FormatInfo.BlockHeight, - info.FormatInfo.BytesPerPixel); - } - else - { - int depth = Math.Max(1, info.GetDepth() >> level); - - return SizeCalculator.GetBlockLinearAlignedSize( - width, - height, - depth, - info.FormatInfo.BlockWidth, - info.FormatInfo.BlockHeight, - info.FormatInfo.BytesPerPixel, - info.GobBlocksInY, - info.GobBlocksInZ, - info.GobBlocksInTileX); - } - } - /// /// Gets a texture of the specified target type from this texture. /// This can be used to get an array texture from a non-array texture and vice-versa. diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs index 408f6e2ac..b64a85a5d 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs @@ -1,4 +1,8 @@ +using Ryujinx.Common; using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.Gpu.State; +using Ryujinx.Graphics.Texture; +using System; namespace Ryujinx.Graphics.Gpu.Image { @@ -22,6 +26,26 @@ namespace Ryujinx.Graphics.Gpu.Image Bc7 } + /// + /// Finds the appropriate depth format for a copy texture if the source texture has a depth format. + /// + /// Destination CopyTexture Format + /// Source Texture Format + /// Derived RtFormat if srcTextureFormat is a depth format, otherwise return dstTextureFormat. + public static RtFormat DeriveDepthFormat(RtFormat dstTextureFormat, Format srcTextureFormat) + { + return srcTextureFormat switch + { + Format.S8Uint => RtFormat.S8Uint, + Format.D16Unorm => RtFormat.D16Unorm, + Format.D24X8Unorm => RtFormat.D24Unorm, + Format.D32Float => RtFormat.D32Float, + Format.D24UnormS8Uint => RtFormat.D24UnormS8Uint, + Format.D32FloatS8Uint => RtFormat.D32FloatS8Uint, + _ => dstTextureFormat + }; + } + /// /// Checks if two formats are compatible, according to the host API copy format compatibility rules. /// @@ -53,6 +77,321 @@ namespace Ryujinx.Graphics.Gpu.Image } } + /// + /// Checks if the texture format matches with the specified texture information. + /// + /// Texture information to compare + /// Texture information to compare with + /// Indicates that the texture will be used for shader sampling + /// Indicates that the texture will be used as copy source or target + /// True if the format matches, with the given comparison rules + public static bool FormatMatches(TextureInfo lhs, TextureInfo rhs, bool forSampler, bool forCopy) + { + // D32F and R32F texture have the same representation internally, + // however the R32F format is used to sample from depth textures. + if (lhs.FormatInfo.Format == Format.D32Float && rhs.FormatInfo.Format == Format.R32Float && (forSampler || forCopy)) + { + return true; + } + + if (forCopy) + { + // The 2D engine does not support depth-stencil formats, so it will instead + // use equivalent color formats. We must also consider them as compatible. + if (lhs.FormatInfo.Format == Format.S8Uint && rhs.FormatInfo.Format == Format.R8Unorm) + { + return true; + } + + if (lhs.FormatInfo.Format == Format.D16Unorm && rhs.FormatInfo.Format == Format.R16Unorm) + { + return true; + } + + if ((lhs.FormatInfo.Format == Format.D24UnormS8Uint || + lhs.FormatInfo.Format == Format.D24X8Unorm) && rhs.FormatInfo.Format == Format.B8G8R8A8Unorm) + { + return true; + } + } + + return lhs.FormatInfo.Format == rhs.FormatInfo.Format; + } + + /// + /// Checks if the texture layout specified matches with this texture layout. + /// The layout information is composed of the Stride for linear textures, or GOB block size + /// for block linear textures. + /// + /// Texture information to compare + /// Texture information to compare with + /// True if the layout matches, false otherwise + public static bool LayoutMatches(TextureInfo lhs, TextureInfo rhs) + { + if (lhs.IsLinear != rhs.IsLinear) + { + return false; + } + + // For linear textures, gob block sizes are ignored. + // For block linear textures, the stride is ignored. + if (rhs.IsLinear) + { + return lhs.Stride == rhs.Stride; + } + else + { + return lhs.GobBlocksInY == rhs.GobBlocksInY && + lhs.GobBlocksInZ == rhs.GobBlocksInZ; + } + } + + /// + /// Checks if the view sizes of a two given texture informations match. + /// + /// Texture information of the texture view + /// Texture information of the texture view to match against + /// Mipmap level of the texture view in relation to this texture + /// True to check for copy compatibility rather than view compatibility + /// True if the sizes are compatible, false otherwise + public static bool ViewSizeMatches(TextureInfo lhs, TextureInfo rhs, int level, bool isCopy) + { + Size size = GetAlignedSize(lhs, level); + + Size otherSize = GetAlignedSize(rhs); + + // For copies, we can copy a subset of the 3D texture slices, + // so the depth may be different in this case. + if (!isCopy && rhs.Target == Target.Texture3D && size.Depth != otherSize.Depth) + { + return false; + } + + return size.Width == otherSize.Width && + size.Height == otherSize.Height; + } + + /// + /// Checks if the texture sizes of the supplied texture informations match. + /// + /// Texture information to compare + /// Texture information to compare with + /// True if the size matches, false otherwise + public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs) + { + return SizeMatches(lhs, rhs, alignSizes: false); + } + + /// + /// Checks if the texture sizes of the supplied texture informations match the given level + /// + /// Texture information to compare + /// Texture information to compare with + /// Mipmap level of this texture to compare with + /// True if the size matches with the level, false otherwise + public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs, int level) + { + return Math.Max(1, lhs.Width >> level) == rhs.Width && + Math.Max(1, lhs.Height >> level) == rhs.Height && + Math.Max(1, lhs.GetDepth() >> level) == rhs.GetDepth(); + } + + /// + /// Checks if the texture sizes of the supplied texture informations match. + /// + /// Texture information to compare + /// Texture information to compare with + /// True to align the sizes according to the texture layout for comparison + /// True if the sizes matches, false otherwise + private static bool SizeMatches(TextureInfo lhs, TextureInfo rhs, bool alignSizes) + { + if (lhs.GetLayers() != rhs.GetLayers()) + { + return false; + } + + if (alignSizes) + { + Size size0 = GetAlignedSize(lhs); + Size size1 = GetAlignedSize(rhs); + + return size0.Width == size1.Width && + size0.Height == size1.Height && + size0.Depth == size1.Depth; + } + else + { + return lhs.Width == rhs.Width && + lhs.Height == rhs.Height && + lhs.GetDepth() == rhs.GetDepth(); + } + } + + /// + /// Gets the aligned sizes of the specified texture information. + /// The alignment depends on the texture layout and format bytes per pixel. + /// + /// Texture information to calculate the aligned size from + /// Mipmap level for texture views + /// The aligned texture size + public static Size GetAlignedSize(TextureInfo info, int level = 0) + { + int width = Math.Max(1, info.Width >> level); + int height = Math.Max(1, info.Height >> level); + + if (info.IsLinear) + { + return SizeCalculator.GetLinearAlignedSize( + width, + height, + info.FormatInfo.BlockWidth, + info.FormatInfo.BlockHeight, + info.FormatInfo.BytesPerPixel); + } + else + { + int depth = Math.Max(1, info.GetDepth() >> level); + + return SizeCalculator.GetBlockLinearAlignedSize( + width, + height, + depth, + info.FormatInfo.BlockWidth, + info.FormatInfo.BlockHeight, + info.FormatInfo.BytesPerPixel, + info.GobBlocksInY, + info.GobBlocksInZ, + info.GobBlocksInTileX); + } + } + + /// + /// Check if it's possible to create a view with the layout of the second texture information from the first. + /// The layout information is composed of the Stride for linear textures, or GOB block size + /// for block linear textures. + /// + /// Texture information of the texture view + /// Texture information of the texture view to compare against + /// Start level of the texture view, in relation with the first texture + /// True if the layout is compatible, false otherwise + public static bool ViewLayoutCompatible(TextureInfo lhs, TextureInfo rhs, int level) + { + if (lhs.IsLinear != rhs.IsLinear) + { + return false; + } + + // For linear textures, gob block sizes are ignored. + // For block linear textures, the stride is ignored. + if (rhs.IsLinear) + { + int width = Math.Max(1, lhs.Width >> level); + int stride = width * lhs.FormatInfo.BytesPerPixel; + stride = BitUtils.AlignUp(stride, 32); + + return stride == rhs.Stride; + } + else + { + int height = Math.Max(1, lhs.Height >> level); + int depth = Math.Max(1, lhs.GetDepth() >> level); + + (int gobBlocksInY, int gobBlocksInZ) = SizeCalculator.GetMipGobBlockSizes( + height, + depth, + lhs.FormatInfo.BlockHeight, + lhs.GobBlocksInY, + lhs.GobBlocksInZ); + + return gobBlocksInY == rhs.GobBlocksInY && + gobBlocksInZ == rhs.GobBlocksInZ; + } + } + + /// + /// Checks if the view format of the first texture format is compatible with the format of the second. + /// In general, the formats are considered compatible if the bytes per pixel values are equal, + /// but there are more complex rules for some formats, like compressed or depth-stencil formats. + /// This follows the host API copy compatibility rules. + /// + /// Texture information of the texture view + /// Texture information of the texture view + /// True if the formats are compatible, false otherwise + public static bool ViewFormatCompatible(TextureInfo lhs, TextureInfo rhs) + { + return FormatCompatible(lhs.FormatInfo, rhs.FormatInfo); + } + + /// + /// Check if the target of the first texture view information is compatible with the target of the second texture view information. + /// This follows the host API target compatibility rules. + /// + /// Texture information of the texture viewTexture information of the texture view + /// True to check for copy rather than view compatibility + /// True if the targets are compatible, false otherwise + public static bool ViewTargetCompatible(TextureInfo lhs, TextureInfo rhs, bool isCopy) + { + switch (lhs.Target) + { + case Target.Texture1D: + case Target.Texture1DArray: + return rhs.Target == Target.Texture1D || + rhs.Target == Target.Texture1DArray; + + case Target.Texture2D: + return rhs.Target == Target.Texture2D || + rhs.Target == Target.Texture2DArray; + + case Target.Texture2DArray: + case Target.Cubemap: + case Target.CubemapArray: + return rhs.Target == Target.Texture2D || + rhs.Target == Target.Texture2DArray || + rhs.Target == Target.Cubemap || + rhs.Target == Target.CubemapArray; + + case Target.Texture2DMultisample: + case Target.Texture2DMultisampleArray: + return rhs.Target == Target.Texture2DMultisample || + rhs.Target == Target.Texture2DMultisampleArray; + + case Target.Texture3D: + return rhs.Target == Target.Texture3D || + (rhs.Target == Target.Texture2D && isCopy); + } + + return false; + } + + /// + /// Checks if the texture shader sampling parameters of two texture informations match. + /// + /// Texture information to compare + /// Texture information to compare with + /// True if the texture shader sampling parameters matches, false otherwise + public static bool SamplerParamsMatches(TextureInfo lhs, TextureInfo rhs) + { + return lhs.DepthStencilMode == rhs.DepthStencilMode && + lhs.SwizzleR == rhs.SwizzleR && + lhs.SwizzleG == rhs.SwizzleG && + lhs.SwizzleB == rhs.SwizzleB && + lhs.SwizzleA == rhs.SwizzleA; + } + + /// + /// Check if the texture target and samples count (for multisampled textures) matches. + /// + /// Texture information to compare with + /// Texture information to compare with + /// True if the texture target and samples count matches, false otherwise + public static bool TargetAndSamplesCompatible(TextureInfo lhs, TextureInfo rhs) + { + return lhs.Target == rhs.Target && + lhs.SamplesInX == rhs.SamplesInX && + lhs.SamplesInY == rhs.SamplesInY; + } + /// /// Gets the texture format class, for compressed textures, or Unclassified otherwise. /// diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs index c69f69c62..cab76da1b 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs @@ -634,7 +634,7 @@ namespace Ryujinx.Graphics.Gpu.Image // deletion. _cache.Lift(overlap); } - else if (!overlap.SizeMatches(info)) + else if (!TextureCompatibility.SizeMatches(overlap.Info, info)) { // If this is used for sampling, the size must match, // otherwise the shader would sample garbage data. @@ -707,7 +707,7 @@ namespace Ryujinx.Graphics.Gpu.Image // The size only matters (and is only really reliable) when the // texture is used on a sampler, because otherwise the size will be // aligned. - if (!overlap.SizeMatches(info, firstLevel) && isSamplerTexture) + if (!TextureCompatibility.SizeMatches(overlap.Info, info, firstLevel) && isSamplerTexture) { texture.ChangeSize(info.Width, info.Height, info.DepthOrLayers); }