diff options
| author | sharmander <saldabain.dev@gmail.com> | 2020-08-31 20:06:27 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-08-31 21:06:27 -0300 |
| commit | bc19114bb5a14f4563aa4bee68bda97234a7bcb0 (patch) | |
| tree | 4239be72361c1649378effdba4f21c25bf2ff08f /Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs | |
| parent | 92f7f163ef0ad3d7a542460a5500074188a9d8b1 (diff) | |
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
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs')
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs index 408f6e2a..b64a85a5 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 { @@ -23,6 +27,26 @@ namespace Ryujinx.Graphics.Gpu.Image } /// <summary> + /// Finds the appropriate depth format for a copy texture if the source texture has a depth format. + /// </summary> + /// <param name="dstTextureFormat">Destination CopyTexture Format</param> + /// <param name="srcTextureFormat">Source Texture Format</param> + /// <returns>Derived RtFormat if srcTextureFormat is a depth format, otherwise return dstTextureFormat.</returns> + 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 + }; + } + + /// <summary> /// Checks if two formats are compatible, according to the host API copy format compatibility rules. /// </summary> /// <param name="lhs">First comparand</param> @@ -54,6 +78,321 @@ namespace Ryujinx.Graphics.Gpu.Image } /// <summary> + /// Checks if the texture format matches with the specified texture information. + /// </summary> + /// <param name="lhs">Texture information to compare</param> + /// <param name="rhs">Texture information to compare with</param> + /// <param name="forSampler">Indicates that the texture will be used for shader sampling</param> + /// <param name="forCopy">Indicates that the texture will be used as copy source or target</param> + /// <returns>True if the format matches, with the given comparison rules</returns> + 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; + } + + /// <summary> + /// 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. + /// </summary> + /// <param name="lhs">Texture information to compare</param> + /// <param name="rhs">Texture information to compare with</param> + /// <returns>True if the layout matches, false otherwise</returns> + 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; + } + } + + /// <summary> + /// Checks if the view sizes of a two given texture informations match. + /// </summary> + /// <param name="lhs">Texture information of the texture view</param> + /// <param name="rhs">Texture information of the texture view to match against</param> + /// <param name="level">Mipmap level of the texture view in relation to this texture</param> + /// <param name="isCopy">True to check for copy compatibility rather than view compatibility</param> + /// <returns>True if the sizes are compatible, false otherwise</returns> + 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; + } + + /// <summary> + /// Checks if the texture sizes of the supplied texture informations match. + /// </summary> + /// <param name="lhs">Texture information to compare</param> + /// <param name="rhs">Texture information to compare with</param> + /// <returns>True if the size matches, false otherwise</returns> + public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs) + { + return SizeMatches(lhs, rhs, alignSizes: false); + } + + /// <summary> + /// Checks if the texture sizes of the supplied texture informations match the given level + /// </summary> + /// <param name="lhs">Texture information to compare</param> + /// <param name="rhs">Texture information to compare with</param> + /// <param name="level">Mipmap level of this texture to compare with</param> + /// <returns>True if the size matches with the level, false otherwise</returns> + 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(); + } + + /// <summary> + /// Checks if the texture sizes of the supplied texture informations match. + /// </summary> + /// <param name="lhs">Texture information to compare</param> + /// <param name="rhs">Texture information to compare with</param> + /// <param name="alignSizes">True to align the sizes according to the texture layout for comparison</param> + /// <returns>True if the sizes matches, false otherwise</returns> + 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(); + } + } + + /// <summary> + /// Gets the aligned sizes of the specified texture information. + /// The alignment depends on the texture layout and format bytes per pixel. + /// </summary> + /// <param name="info">Texture information to calculate the aligned size from</param> + /// <param name="level">Mipmap level for texture views</param> + /// <returns>The aligned texture size</returns> + 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); + } + } + + /// <summary> + /// 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. + /// </summary> + /// <param name="lhs">Texture information of the texture view</param> + /// <param name="rhs">Texture information of the texture view to compare against</param> + /// <param name="level">Start level of the texture view, in relation with the first texture</param> + /// <returns>True if the layout is compatible, false otherwise</returns> + 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; + } + } + + /// <summary> + /// 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. + /// </summary> + /// <param name="lhs">Texture information of the texture view</param> + /// <param name="rhs">Texture information of the texture view</param> + /// <returns>True if the formats are compatible, false otherwise</returns> + public static bool ViewFormatCompatible(TextureInfo lhs, TextureInfo rhs) + { + return FormatCompatible(lhs.FormatInfo, rhs.FormatInfo); + } + + /// <summary> + /// 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. + /// </summary> + /// <param name="lhs">Texture information of the texture view</param + /// <param name="rhs">Texture information of the texture view</param> + /// <param name="isCopy">True to check for copy rather than view compatibility</param> + /// <returns>True if the targets are compatible, false otherwise</returns> + 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; + } + + /// <summary> + /// Checks if the texture shader sampling parameters of two texture informations match. + /// </summary> + /// <param name="lhs">Texture information to compare</param> + /// <param name="rhs">Texture information to compare with</param> + /// <returns>True if the texture shader sampling parameters matches, false otherwise</returns> + 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; + } + + /// <summary> + /// Check if the texture target and samples count (for multisampled textures) matches. + /// </summary> + /// <param name="first">Texture information to compare with</param> + /// <param name="rhs">Texture information to compare with</param> + /// <returns>True if the texture target and samples count matches, false otherwise</returns> + public static bool TargetAndSamplesCompatible(TextureInfo lhs, TextureInfo rhs) + { + return lhs.Target == rhs.Target && + lhs.SamplesInX == rhs.SamplesInX && + lhs.SamplesInY == rhs.SamplesInY; + } + + /// <summary> /// Gets the texture format class, for compressed textures, or Unclassified otherwise. /// </summary> /// <param name="format">The format</param> |
