diff --git a/Ryujinx.Graphics.GAL/Format.cs b/Ryujinx.Graphics.GAL/Format.cs index a66673614..a4e434b1f 100644 --- a/Ryujinx.Graphics.GAL/Format.cs +++ b/Ryujinx.Graphics.GAL/Format.cs @@ -341,38 +341,5 @@ namespace Ryujinx.Graphics.GAL { return format.IsUint() || format.IsSint(); } - - /// <summary> - /// Checks if the texture format only has one component. - /// </summary> - /// <param name="format">Texture format</param> - /// <returns>True if the texture format only has one component, false otherwise</returns> - public static bool HasOneComponent(this Format format) - { - switch (format) - { - case Format.R8Unorm: - case Format.R8Snorm: - case Format.R8Uint: - case Format.R8Sint: - case Format.R16Float: - case Format.R16Unorm: - case Format.R16Snorm: - case Format.R16Uint: - case Format.R16Sint: - case Format.R32Float: - case Format.R32Uint: - case Format.R32Sint: - case Format.R8Uscaled: - case Format.R8Sscaled: - case Format.R16Uscaled: - case Format.R16Sscaled: - case Format.R32Uscaled: - case Format.R32Sscaled: - return true; - } - - return false; - } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs b/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs index 12f3aecbb..62f41cbb0 100644 --- a/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs +++ b/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs @@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// <summary> /// A default, generic RGBA8 texture format. /// </summary> - public static FormatInfo Default { get; } = new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4); + public static FormatInfo Default { get; } = new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4); /// <summary> /// The format of the texture data. @@ -38,6 +38,11 @@ namespace Ryujinx.Graphics.Gpu.Image /// </summary> public int BytesPerPixel { get; } + /// <summary> + /// The maximum number of components this format has defined (in RGBA order). + /// </summary> + public int Components { get; } + /// <summary> /// Whenever or not the texture format is a compressed format. Determined from block size. /// </summary> @@ -54,12 +59,14 @@ namespace Ryujinx.Graphics.Gpu.Image Format format, int blockWidth, int blockHeight, - int bytesPerPixel) + int bytesPerPixel, + int components) { Format = format; BlockWidth = blockWidth; BlockHeight = blockHeight; BytesPerPixel = bytesPerPixel; + Components = components; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Image/FormatTable.cs b/Ryujinx.Graphics.Gpu/Image/FormatTable.cs index 9f8b0fa06..d8f2a9d45 100644 --- a/Ryujinx.Graphics.Gpu/Image/FormatTable.cs +++ b/Ryujinx.Graphics.Gpu/Image/FormatTable.cs @@ -10,102 +10,102 @@ namespace Ryujinx.Graphics.Gpu.Image { private static Dictionary<uint, FormatInfo> _textureFormats = new Dictionary<uint, FormatInfo>() { - { 0x2491d, new FormatInfo(Format.R8Unorm, 1, 1, 1) }, - { 0x1249d, new FormatInfo(Format.R8Snorm, 1, 1, 1) }, - { 0x4921d, new FormatInfo(Format.R8Uint, 1, 1, 1) }, - { 0x36d9d, new FormatInfo(Format.R8Sint, 1, 1, 1) }, - { 0x7ff9b, new FormatInfo(Format.R16Float, 1, 1, 2) }, - { 0x2491b, new FormatInfo(Format.R16Unorm, 1, 1, 2) }, - { 0x1249b, new FormatInfo(Format.R16Snorm, 1, 1, 2) }, - { 0x4921b, new FormatInfo(Format.R16Uint, 1, 1, 2) }, - { 0x36d9b, new FormatInfo(Format.R16Sint, 1, 1, 2) }, - { 0x7ff8f, new FormatInfo(Format.R32Float, 1, 1, 4) }, - { 0x4920f, new FormatInfo(Format.R32Uint, 1, 1, 4) }, - { 0x36d8f, new FormatInfo(Format.R32Sint, 1, 1, 4) }, - { 0x24918, new FormatInfo(Format.R8G8Unorm, 1, 1, 2) }, - { 0x12498, new FormatInfo(Format.R8G8Snorm, 1, 1, 2) }, - { 0x49218, new FormatInfo(Format.R8G8Uint, 1, 1, 2) }, - { 0x36d98, new FormatInfo(Format.R8G8Sint, 1, 1, 2) }, - { 0x7ff8c, new FormatInfo(Format.R16G16Float, 1, 1, 4) }, - { 0x2490c, new FormatInfo(Format.R16G16Unorm, 1, 1, 4) }, - { 0x1248c, new FormatInfo(Format.R16G16Snorm, 1, 1, 4) }, - { 0x4920c, new FormatInfo(Format.R16G16Uint, 1, 1, 4) }, - { 0x36d8c, new FormatInfo(Format.R16G16Sint, 1, 1, 4) }, - { 0x7ff84, new FormatInfo(Format.R32G32Float, 1, 1, 8) }, - { 0x49204, new FormatInfo(Format.R32G32Uint, 1, 1, 8) }, - { 0x36d84, new FormatInfo(Format.R32G32Sint, 1, 1, 8) }, - { 0x7ff82, new FormatInfo(Format.R32G32B32Float, 1, 1, 12) }, - { 0x49202, new FormatInfo(Format.R32G32B32Uint, 1, 1, 12) }, - { 0x36d82, new FormatInfo(Format.R32G32B32Sint, 1, 1, 12) }, - { 0x24908, new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4) }, - { 0x12488, new FormatInfo(Format.R8G8B8A8Snorm, 1, 1, 4) }, - { 0x49208, new FormatInfo(Format.R8G8B8A8Uint, 1, 1, 4) }, - { 0x36d88, new FormatInfo(Format.R8G8B8A8Sint, 1, 1, 4) }, - { 0x7ff83, new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8) }, - { 0x24903, new FormatInfo(Format.R16G16B16A16Unorm, 1, 1, 8) }, - { 0x12483, new FormatInfo(Format.R16G16B16A16Snorm, 1, 1, 8) }, - { 0x49203, new FormatInfo(Format.R16G16B16A16Uint, 1, 1, 8) }, - { 0x36d83, new FormatInfo(Format.R16G16B16A16Sint, 1, 1, 8) }, - { 0x7ff81, new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16) }, - { 0x49201, new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16) }, - { 0x36d81, new FormatInfo(Format.R32G32B32A32Sint, 1, 1, 16) }, - { 0x2493a, new FormatInfo(Format.D16Unorm, 1, 1, 2) }, - { 0x7ffaf, new FormatInfo(Format.D32Float, 1, 1, 4) }, - { 0x24a0e, new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4) }, - { 0x24a29, new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4) }, - { 0x25385, new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8) }, - { 0x253b0, new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8) }, - { 0xa4908, new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4) }, - { 0x24912, new FormatInfo(Format.R4G4B4A4Unorm, 1, 1, 2) }, - { 0x24914, new FormatInfo(Format.R5G5B5A1Unorm, 1, 1, 2) }, - { 0x24915, new FormatInfo(Format.R5G6B5Unorm, 1, 1, 2) }, - { 0x24909, new FormatInfo(Format.R10G10B10A2Unorm, 1, 1, 4) }, - { 0x49209, new FormatInfo(Format.R10G10B10A2Uint, 1, 1, 4) }, - { 0x7ffa1, new FormatInfo(Format.R11G11B10Float, 1, 1, 4) }, - { 0x7ffa0, new FormatInfo(Format.R9G9B9E5Float, 1, 1, 4) }, - { 0x24924, new FormatInfo(Format.Bc1RgbaUnorm, 4, 4, 8) }, - { 0x24925, new FormatInfo(Format.Bc2Unorm, 4, 4, 16) }, - { 0x24926, new FormatInfo(Format.Bc3Unorm, 4, 4, 16) }, - { 0xa4924, new FormatInfo(Format.Bc1RgbaSrgb, 4, 4, 8) }, - { 0xa4925, new FormatInfo(Format.Bc2Srgb, 4, 4, 16) }, - { 0xa4926, new FormatInfo(Format.Bc3Srgb, 4, 4, 16) }, - { 0x24927, new FormatInfo(Format.Bc4Unorm, 4, 4, 8) }, - { 0x124a7, new FormatInfo(Format.Bc4Snorm, 4, 4, 8) }, - { 0x24928, new FormatInfo(Format.Bc5Unorm, 4, 4, 16) }, - { 0x124a8, new FormatInfo(Format.Bc5Snorm, 4, 4, 16) }, - { 0x24917, new FormatInfo(Format.Bc7Unorm, 4, 4, 16) }, - { 0xa4917, new FormatInfo(Format.Bc7Srgb, 4, 4, 16) }, - { 0x7ff90, new FormatInfo(Format.Bc6HSfloat, 4, 4, 16) }, - { 0x7ff91, new FormatInfo(Format.Bc6HUfloat, 4, 4, 16) }, - { 0x24940, new FormatInfo(Format.Astc4x4Unorm, 4, 4, 16) }, - { 0x24950, new FormatInfo(Format.Astc5x4Unorm, 5, 4, 16) }, - { 0x24941, new FormatInfo(Format.Astc5x5Unorm, 5, 5, 16) }, - { 0x24951, new FormatInfo(Format.Astc6x5Unorm, 6, 5, 16) }, - { 0x24942, new FormatInfo(Format.Astc6x6Unorm, 6, 6, 16) }, - { 0x24955, new FormatInfo(Format.Astc8x5Unorm, 8, 5, 16) }, - { 0x24952, new FormatInfo(Format.Astc8x6Unorm, 8, 6, 16) }, - { 0x24944, new FormatInfo(Format.Astc8x8Unorm, 8, 8, 16) }, - { 0x24956, new FormatInfo(Format.Astc10x5Unorm, 10, 5, 16) }, - { 0x24957, new FormatInfo(Format.Astc10x6Unorm, 10, 6, 16) }, - { 0x24953, new FormatInfo(Format.Astc10x8Unorm, 10, 8, 16) }, - { 0x24945, new FormatInfo(Format.Astc10x10Unorm, 10, 10, 16) }, - { 0x24954, new FormatInfo(Format.Astc12x10Unorm, 12, 10, 16) }, - { 0x24946, new FormatInfo(Format.Astc12x12Unorm, 12, 12, 16) }, - { 0xa4940, new FormatInfo(Format.Astc4x4Srgb, 4, 4, 16) }, - { 0xa4950, new FormatInfo(Format.Astc5x4Srgb, 5, 4, 16) }, - { 0xa4941, new FormatInfo(Format.Astc5x5Srgb, 5, 5, 16) }, - { 0xa4951, new FormatInfo(Format.Astc6x5Srgb, 6, 5, 16) }, - { 0xa4942, new FormatInfo(Format.Astc6x6Srgb, 6, 6, 16) }, - { 0xa4955, new FormatInfo(Format.Astc8x5Srgb, 8, 5, 16) }, - { 0xa4952, new FormatInfo(Format.Astc8x6Srgb, 8, 6, 16) }, - { 0xa4944, new FormatInfo(Format.Astc8x8Srgb, 8, 8, 16) }, - { 0xa4956, new FormatInfo(Format.Astc10x5Srgb, 10, 5, 16) }, - { 0xa4957, new FormatInfo(Format.Astc10x6Srgb, 10, 6, 16) }, - { 0xa4953, new FormatInfo(Format.Astc10x8Srgb, 10, 8, 16) }, - { 0xa4945, new FormatInfo(Format.Astc10x10Srgb, 10, 10, 16) }, - { 0xa4954, new FormatInfo(Format.Astc12x10Srgb, 12, 10, 16) }, - { 0xa4946, new FormatInfo(Format.Astc12x12Srgb, 12, 12, 16) }, - { 0x24913, new FormatInfo(Format.A1B5G5R5Unorm, 1, 1, 2) } + { 0x2491d, new FormatInfo(Format.R8Unorm, 1, 1, 1, 1) }, + { 0x1249d, new FormatInfo(Format.R8Snorm, 1, 1, 1, 1) }, + { 0x4921d, new FormatInfo(Format.R8Uint, 1, 1, 1, 1) }, + { 0x36d9d, new FormatInfo(Format.R8Sint, 1, 1, 1, 1) }, + { 0x7ff9b, new FormatInfo(Format.R16Float, 1, 1, 2, 1) }, + { 0x2491b, new FormatInfo(Format.R16Unorm, 1, 1, 2, 1) }, + { 0x1249b, new FormatInfo(Format.R16Snorm, 1, 1, 2, 1) }, + { 0x4921b, new FormatInfo(Format.R16Uint, 1, 1, 2, 1) }, + { 0x36d9b, new FormatInfo(Format.R16Sint, 1, 1, 2, 1) }, + { 0x7ff8f, new FormatInfo(Format.R32Float, 1, 1, 4, 1) }, + { 0x4920f, new FormatInfo(Format.R32Uint, 1, 1, 4, 1) }, + { 0x36d8f, new FormatInfo(Format.R32Sint, 1, 1, 4, 1) }, + { 0x24918, new FormatInfo(Format.R8G8Unorm, 1, 1, 2, 2) }, + { 0x12498, new FormatInfo(Format.R8G8Snorm, 1, 1, 2, 2) }, + { 0x49218, new FormatInfo(Format.R8G8Uint, 1, 1, 2, 2) }, + { 0x36d98, new FormatInfo(Format.R8G8Sint, 1, 1, 2, 2) }, + { 0x7ff8c, new FormatInfo(Format.R16G16Float, 1, 1, 4, 2) }, + { 0x2490c, new FormatInfo(Format.R16G16Unorm, 1, 1, 4, 2) }, + { 0x1248c, new FormatInfo(Format.R16G16Snorm, 1, 1, 4, 2) }, + { 0x4920c, new FormatInfo(Format.R16G16Uint, 1, 1, 4, 2) }, + { 0x36d8c, new FormatInfo(Format.R16G16Sint, 1, 1, 4, 2) }, + { 0x7ff84, new FormatInfo(Format.R32G32Float, 1, 1, 8, 2) }, + { 0x49204, new FormatInfo(Format.R32G32Uint, 1, 1, 8, 2) }, + { 0x36d84, new FormatInfo(Format.R32G32Sint, 1, 1, 8, 2) }, + { 0x7ff82, new FormatInfo(Format.R32G32B32Float, 1, 1, 12, 3) }, + { 0x49202, new FormatInfo(Format.R32G32B32Uint, 1, 1, 12, 3) }, + { 0x36d82, new FormatInfo(Format.R32G32B32Sint, 1, 1, 12, 3) }, + { 0x24908, new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4) }, + { 0x12488, new FormatInfo(Format.R8G8B8A8Snorm, 1, 1, 4, 4) }, + { 0x49208, new FormatInfo(Format.R8G8B8A8Uint, 1, 1, 4, 4) }, + { 0x36d88, new FormatInfo(Format.R8G8B8A8Sint, 1, 1, 4, 4) }, + { 0x7ff83, new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8, 4) }, + { 0x24903, new FormatInfo(Format.R16G16B16A16Unorm, 1, 1, 8, 4) }, + { 0x12483, new FormatInfo(Format.R16G16B16A16Snorm, 1, 1, 8, 4) }, + { 0x49203, new FormatInfo(Format.R16G16B16A16Uint, 1, 1, 8, 4) }, + { 0x36d83, new FormatInfo(Format.R16G16B16A16Sint, 1, 1, 8, 4) }, + { 0x7ff81, new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16, 4) }, + { 0x49201, new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16, 4) }, + { 0x36d81, new FormatInfo(Format.R32G32B32A32Sint, 1, 1, 16, 4) }, + { 0x2493a, new FormatInfo(Format.D16Unorm, 1, 1, 2, 1) }, + { 0x7ffaf, new FormatInfo(Format.D32Float, 1, 1, 4, 1) }, + { 0x24a0e, new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 2) }, + { 0x24a29, new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 2) }, + { 0x25385, new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8, 2) }, + { 0x253b0, new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8, 2) }, + { 0xa4908, new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4) }, + { 0x24912, new FormatInfo(Format.R4G4B4A4Unorm, 1, 1, 2, 4) }, + { 0x24914, new FormatInfo(Format.R5G5B5A1Unorm, 1, 1, 2, 4) }, + { 0x24915, new FormatInfo(Format.R5G6B5Unorm, 1, 1, 2, 3) }, + { 0x24909, new FormatInfo(Format.R10G10B10A2Unorm, 1, 1, 4, 4) }, + { 0x49209, new FormatInfo(Format.R10G10B10A2Uint, 1, 1, 4, 4) }, + { 0x7ffa1, new FormatInfo(Format.R11G11B10Float, 1, 1, 4, 3) }, + { 0x7ffa0, new FormatInfo(Format.R9G9B9E5Float, 1, 1, 4, 4) }, + { 0x24924, new FormatInfo(Format.Bc1RgbaUnorm, 4, 4, 8, 4) }, + { 0x24925, new FormatInfo(Format.Bc2Unorm, 4, 4, 16, 4) }, + { 0x24926, new FormatInfo(Format.Bc3Unorm, 4, 4, 16, 4) }, + { 0xa4924, new FormatInfo(Format.Bc1RgbaSrgb, 4, 4, 8, 4) }, + { 0xa4925, new FormatInfo(Format.Bc2Srgb, 4, 4, 16, 4) }, + { 0xa4926, new FormatInfo(Format.Bc3Srgb, 4, 4, 16, 4) }, + { 0x24927, new FormatInfo(Format.Bc4Unorm, 4, 4, 8, 1) }, + { 0x124a7, new FormatInfo(Format.Bc4Snorm, 4, 4, 8, 1) }, + { 0x24928, new FormatInfo(Format.Bc5Unorm, 4, 4, 16, 2) }, + { 0x124a8, new FormatInfo(Format.Bc5Snorm, 4, 4, 16, 2) }, + { 0x24917, new FormatInfo(Format.Bc7Unorm, 4, 4, 16, 4) }, + { 0xa4917, new FormatInfo(Format.Bc7Srgb, 4, 4, 16, 4) }, + { 0x7ff90, new FormatInfo(Format.Bc6HSfloat, 4, 4, 16, 4) }, + { 0x7ff91, new FormatInfo(Format.Bc6HUfloat, 4, 4, 16, 4) }, + { 0x24940, new FormatInfo(Format.Astc4x4Unorm, 4, 4, 16, 4) }, + { 0x24950, new FormatInfo(Format.Astc5x4Unorm, 5, 4, 16, 4) }, + { 0x24941, new FormatInfo(Format.Astc5x5Unorm, 5, 5, 16, 4) }, + { 0x24951, new FormatInfo(Format.Astc6x5Unorm, 6, 5, 16, 4) }, + { 0x24942, new FormatInfo(Format.Astc6x6Unorm, 6, 6, 16, 4) }, + { 0x24955, new FormatInfo(Format.Astc8x5Unorm, 8, 5, 16, 4) }, + { 0x24952, new FormatInfo(Format.Astc8x6Unorm, 8, 6, 16, 4) }, + { 0x24944, new FormatInfo(Format.Astc8x8Unorm, 8, 8, 16, 4) }, + { 0x24956, new FormatInfo(Format.Astc10x5Unorm, 10, 5, 16, 4) }, + { 0x24957, new FormatInfo(Format.Astc10x6Unorm, 10, 6, 16, 4) }, + { 0x24953, new FormatInfo(Format.Astc10x8Unorm, 10, 8, 16, 4) }, + { 0x24945, new FormatInfo(Format.Astc10x10Unorm, 10, 10, 16, 4) }, + { 0x24954, new FormatInfo(Format.Astc12x10Unorm, 12, 10, 16, 4) }, + { 0x24946, new FormatInfo(Format.Astc12x12Unorm, 12, 12, 16, 4) }, + { 0xa4940, new FormatInfo(Format.Astc4x4Srgb, 4, 4, 16, 4) }, + { 0xa4950, new FormatInfo(Format.Astc5x4Srgb, 5, 4, 16, 4) }, + { 0xa4941, new FormatInfo(Format.Astc5x5Srgb, 5, 5, 16, 4) }, + { 0xa4951, new FormatInfo(Format.Astc6x5Srgb, 6, 5, 16, 4) }, + { 0xa4942, new FormatInfo(Format.Astc6x6Srgb, 6, 6, 16, 4) }, + { 0xa4955, new FormatInfo(Format.Astc8x5Srgb, 8, 5, 16, 4) }, + { 0xa4952, new FormatInfo(Format.Astc8x6Srgb, 8, 6, 16, 4) }, + { 0xa4944, new FormatInfo(Format.Astc8x8Srgb, 8, 8, 16, 4) }, + { 0xa4956, new FormatInfo(Format.Astc10x5Srgb, 10, 5, 16, 4) }, + { 0xa4957, new FormatInfo(Format.Astc10x6Srgb, 10, 6, 16, 4) }, + { 0xa4953, new FormatInfo(Format.Astc10x8Srgb, 10, 8, 16, 4) }, + { 0xa4945, new FormatInfo(Format.Astc10x10Srgb, 10, 10, 16, 4) }, + { 0xa4954, new FormatInfo(Format.Astc12x10Srgb, 12, 10, 16, 4) }, + { 0xa4946, new FormatInfo(Format.Astc12x12Srgb, 12, 12, 16, 4) }, + { 0x24913, new FormatInfo(Format.A1B5G5R5Unorm, 1, 1, 2, 4) } }; private static Dictionary<ulong, Format> _attribFormats = new Dictionary<ulong, Format>() diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs index e8e3c2c24..22473a1b1 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs @@ -397,6 +397,49 @@ namespace Ryujinx.Graphics.Gpu.Image return result ? TextureViewCompatibility.Full : TextureViewCompatibility.Incompatible; } + /// <summary> + /// Checks if a swizzle component in two textures functionally match, taking into account if the components are defined. + /// </summary> + /// <param name="lhs">Texture information to compare</param> + /// <param name="rhs">Texture information to compare with</param> + /// <param name="swizzleLhs">Swizzle component for the first texture</param> + /// <param name="swizzleRhs">Swizzle component for the second texture</param> + /// <param name="component">Component index, starting at 0 for red</param> + /// <returns>True if the swizzle components functionally match, false othersize</returns> + private static bool SwizzleComponentMatches(TextureInfo lhs, TextureInfo rhs, SwizzleComponent swizzleLhs, SwizzleComponent swizzleRhs, int component) + { + int lhsComponents = lhs.FormatInfo.Components; + int rhsComponents = rhs.FormatInfo.Components; + + if (lhsComponents == 4 && rhsComponents == 4) + { + return swizzleLhs == swizzleRhs; + } + + // Swizzles after the number of components a format defines are "undefined". + // We allow these to not be equal under certain circumstances. + // This can only happen when there are less than 4 components in a format. + // It tends to happen when float depth textures are sampled. + + bool lhsDefined = (swizzleLhs - SwizzleComponent.Red) < lhsComponents; + bool rhsDefined = (swizzleRhs - SwizzleComponent.Red) < rhsComponents; + + if (lhsDefined == rhsDefined) + { + // If both are undefined, return true. Otherwise just check if they're equal. + return lhsDefined ? swizzleLhs == swizzleRhs : true; + } + else + { + SwizzleComponent defined = lhsDefined ? swizzleLhs : swizzleRhs; + SwizzleComponent undefined = lhsDefined ? swizzleRhs : swizzleLhs; + + // Undefined swizzle can be matched by a forced value (0, 1), exact equality, or expected value. + // For example, R___ matches R001, RGBA but not RBGA. + return defined == undefined || defined < SwizzleComponent.Red || defined == SwizzleComponent.Red + component; + } + } + /// <summary> /// Checks if the texture shader sampling parameters of two texture informations match. /// </summary> @@ -406,10 +449,10 @@ namespace Ryujinx.Graphics.Gpu.Image 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; + SwizzleComponentMatches(lhs, rhs, lhs.SwizzleR, rhs.SwizzleR, 0) && + SwizzleComponentMatches(lhs, rhs, lhs.SwizzleG, rhs.SwizzleG, 1) && + SwizzleComponentMatches(lhs, rhs, lhs.SwizzleB, rhs.SwizzleB, 2) && + SwizzleComponentMatches(lhs, rhs, lhs.SwizzleA, rhs.SwizzleA, 3); } /// <summary> diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs index 0b1d38d10..f8720695d 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs @@ -398,7 +398,7 @@ namespace Ryujinx.Graphics.Gpu.Image // While upscaling works for all targets defined by IsUpscaleCompatible, we additionally blacklist targets here that // may have undesirable results (upscaling blur textures) or simply waste GPU resources (upscaling texture atlas). - if (!(info.FormatInfo.Format.IsDepthOrStencil() || info.FormatInfo.Format.HasOneComponent())) + if (!(info.FormatInfo.Format.IsDepthOrStencil() || info.FormatInfo.Components == 1)) { // Discount square textures that aren't depth-stencil like. (excludes game textures, cubemap faces, most 3D texture LUT, texture atlas) // Detect if the texture is possibly square. Widths may be aligned, so to remove the uncertainty we align both the width and height. @@ -1037,11 +1037,11 @@ namespace Ryujinx.Graphics.Gpu.Image { if (formatInfo.Format.IsAstcUnorm()) { - formatInfo = new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4); + formatInfo = new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4); } else if (formatInfo.Format.IsAstcSrgb()) { - formatInfo = new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4); + formatInfo = new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4); } } @@ -1052,12 +1052,12 @@ namespace Ryujinx.Graphics.Gpu.Image // The shader will need the appropriate conversion code to compensate. switch (formatInfo.Format) { - case Format.R8Snorm: formatInfo = new FormatInfo(Format.R8Sint, 1, 1, 1); break; - case Format.R16Snorm: formatInfo = new FormatInfo(Format.R16Sint, 1, 1, 2); break; - case Format.R8G8Snorm: formatInfo = new FormatInfo(Format.R8G8Sint, 1, 1, 2); break; - case Format.R16G16Snorm: formatInfo = new FormatInfo(Format.R16G16Sint, 1, 1, 4); break; - case Format.R8G8B8A8Snorm: formatInfo = new FormatInfo(Format.R8G8B8A8Sint, 1, 1, 4); break; - case Format.R16G16B16A16Snorm: formatInfo = new FormatInfo(Format.R16G16B16A16Sint, 1, 1, 8); break; + case Format.R8Snorm: formatInfo = new FormatInfo(Format.R8Sint, 1, 1, 1, 1); break; + case Format.R16Snorm: formatInfo = new FormatInfo(Format.R16Sint, 1, 1, 2, 1); break; + case Format.R8G8Snorm: formatInfo = new FormatInfo(Format.R8G8Sint, 1, 1, 2, 2); break; + case Format.R16G16Snorm: formatInfo = new FormatInfo(Format.R16G16Sint, 1, 1, 4, 2); break; + case Format.R8G8B8A8Snorm: formatInfo = new FormatInfo(Format.R8G8B8A8Sint, 1, 1, 4, 4); break; + case Format.R16G16B16A16Snorm: formatInfo = new FormatInfo(Format.R16G16B16A16Sint, 1, 1, 8, 4); break; } } diff --git a/Ryujinx.Graphics.Gpu/State/RtFormat.cs b/Ryujinx.Graphics.Gpu/State/RtFormat.cs index ffd2492b6..f20ad2cda 100644 --- a/Ryujinx.Graphics.Gpu/State/RtFormat.cs +++ b/Ryujinx.Graphics.Gpu/State/RtFormat.cs @@ -81,66 +81,66 @@ namespace Ryujinx.Graphics.Gpu.State { return format switch { - RtFormat.D32Float => new FormatInfo(Format.D32Float, 1, 1, 4), - RtFormat.D16Unorm => new FormatInfo(Format.D16Unorm, 1, 1, 2), - RtFormat.D24UnormS8Uint => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4), - RtFormat.D24Unorm => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4), - RtFormat.S8UintD24Unorm => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4), - RtFormat.S8Uint => new FormatInfo(Format.S8Uint, 1, 1, 1), - RtFormat.D32FloatS8Uint => new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8), - RtFormat.R32G32B32A32Float => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16), - RtFormat.R32G32B32A32Sint => new FormatInfo(Format.R32G32B32A32Sint, 1, 1, 16), - RtFormat.R32G32B32A32Uint => new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16), - RtFormat.R32G32B32X32Float => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16), - RtFormat.R32G32B32X32Sint => new FormatInfo(Format.R32G32B32A32Sint, 1, 1, 16), - RtFormat.R32G32B32X32Uint => new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16), - RtFormat.R16G16B16X16Unorm => new FormatInfo(Format.R16G16B16A16Unorm, 1, 1, 8), - RtFormat.R16G16B16X16Snorm => new FormatInfo(Format.R16G16B16A16Snorm, 1, 1, 8), - RtFormat.R16G16B16X16Sint => new FormatInfo(Format.R16G16B16A16Sint, 1, 1, 8), - RtFormat.R16G16B16X16Uint => new FormatInfo(Format.R16G16B16A16Uint, 1, 1, 8), - RtFormat.R16G16B16A16Float => new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8), - RtFormat.R32G32Float => new FormatInfo(Format.R32G32Float, 1, 1, 8), - RtFormat.R32G32Sint => new FormatInfo(Format.R32G32Sint, 1, 1, 8), - RtFormat.R32G32Uint => new FormatInfo(Format.R32G32Uint, 1, 1, 8), - RtFormat.R16G16B16X16Float => new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8), - RtFormat.B8G8R8A8Unorm => new FormatInfo(Format.B8G8R8A8Unorm, 1, 1, 4), - RtFormat.B8G8R8A8Srgb => new FormatInfo(Format.B8G8R8A8Srgb, 1, 1, 4), - RtFormat.R10G10B10A2Unorm => new FormatInfo(Format.R10G10B10A2Unorm, 1, 1, 4), - RtFormat.R10G10B10A2Uint => new FormatInfo(Format.R10G10B10A2Uint, 1, 1, 4), - RtFormat.R8G8B8A8Unorm => new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4), - RtFormat.R8G8B8A8Srgb => new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4), - RtFormat.R8G8B8X8Snorm => new FormatInfo(Format.R8G8B8A8Snorm, 1, 1, 4), - RtFormat.R8G8B8X8Sint => new FormatInfo(Format.R8G8B8A8Sint, 1, 1, 4), - RtFormat.R8G8B8X8Uint => new FormatInfo(Format.R8G8B8A8Uint, 1, 1, 4), - RtFormat.R16G16Unorm => new FormatInfo(Format.R16G16Unorm, 1, 1, 4), - RtFormat.R16G16Snorm => new FormatInfo(Format.R16G16Snorm, 1, 1, 4), - RtFormat.R16G16Sint => new FormatInfo(Format.R16G16Sint, 1, 1, 4), - RtFormat.R16G16Uint => new FormatInfo(Format.R16G16Uint, 1, 1, 4), - RtFormat.R16G16Float => new FormatInfo(Format.R16G16Float, 1, 1, 4), - RtFormat.R11G11B10Float => new FormatInfo(Format.R11G11B10Float, 1, 1, 4), - RtFormat.R32Sint => new FormatInfo(Format.R32Sint, 1, 1, 4), - RtFormat.R32Uint => new FormatInfo(Format.R32Uint, 1, 1, 4), - RtFormat.R32Float => new FormatInfo(Format.R32Float, 1, 1, 4), - RtFormat.B8G8R8X8Unorm => new FormatInfo(Format.B8G8R8A8Unorm, 1, 1, 4), - RtFormat.B8G8R8X8Srgb => new FormatInfo(Format.B8G8R8A8Srgb, 1, 1, 4), - RtFormat.B5G6R5Unorm => new FormatInfo(Format.B5G6R5Unorm, 1, 1, 2), - RtFormat.B5G5R5A1Unorm => new FormatInfo(Format.B5G5R5A1Unorm, 1, 1, 2), - RtFormat.R8G8Unorm => new FormatInfo(Format.R8G8Unorm, 1, 1, 2), - RtFormat.R8G8Snorm => new FormatInfo(Format.R8G8Snorm, 1, 1, 2), - RtFormat.R8G8Sint => new FormatInfo(Format.R8G8Sint, 1, 1, 2), - RtFormat.R8G8Uint => new FormatInfo(Format.R8G8Uint, 1, 1, 2), - RtFormat.R16Unorm => new FormatInfo(Format.R16Unorm, 1, 1, 2), - RtFormat.R16Snorm => new FormatInfo(Format.R16Snorm, 1, 1, 2), - RtFormat.R16Sint => new FormatInfo(Format.R16Sint, 1, 1, 2), - RtFormat.R16Uint => new FormatInfo(Format.R16Uint, 1, 1, 2), - RtFormat.R16Float => new FormatInfo(Format.R16Float, 1, 1, 2), - RtFormat.R8Unorm => new FormatInfo(Format.R8Unorm, 1, 1, 1), - RtFormat.R8Snorm => new FormatInfo(Format.R8Snorm, 1, 1, 1), - RtFormat.R8Sint => new FormatInfo(Format.R8Sint, 1, 1, 1), - RtFormat.R8Uint => new FormatInfo(Format.R8Uint, 1, 1, 1), - RtFormat.B5G5R5X1Unorm => new FormatInfo(Format.B5G5R5X1Unorm, 1, 1, 2), - RtFormat.R8G8B8X8Unorm => new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4), - RtFormat.R8G8B8X8Srgb => new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4), + RtFormat.D32Float => new FormatInfo(Format.D32Float, 1, 1, 4, 1), + RtFormat.D16Unorm => new FormatInfo(Format.D16Unorm, 1, 1, 2, 1), + RtFormat.D24UnormS8Uint => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 2), + RtFormat.D24Unorm => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 1), + RtFormat.S8UintD24Unorm => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 2), + RtFormat.S8Uint => new FormatInfo(Format.S8Uint, 1, 1, 1, 1), + RtFormat.D32FloatS8Uint => new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8, 2), + RtFormat.R32G32B32A32Float => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16, 4), + RtFormat.R32G32B32A32Sint => new FormatInfo(Format.R32G32B32A32Sint, 1, 1, 16, 4), + RtFormat.R32G32B32A32Uint => new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16, 4), + RtFormat.R32G32B32X32Float => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16, 4), + RtFormat.R32G32B32X32Sint => new FormatInfo(Format.R32G32B32A32Sint, 1, 1, 16, 4), + RtFormat.R32G32B32X32Uint => new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16, 4), + RtFormat.R16G16B16X16Unorm => new FormatInfo(Format.R16G16B16A16Unorm, 1, 1, 8, 4), + RtFormat.R16G16B16X16Snorm => new FormatInfo(Format.R16G16B16A16Snorm, 1, 1, 8, 4), + RtFormat.R16G16B16X16Sint => new FormatInfo(Format.R16G16B16A16Sint, 1, 1, 8, 4), + RtFormat.R16G16B16X16Uint => new FormatInfo(Format.R16G16B16A16Uint, 1, 1, 8, 4), + RtFormat.R16G16B16A16Float => new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8, 4), + RtFormat.R32G32Float => new FormatInfo(Format.R32G32Float, 1, 1, 8, 2), + RtFormat.R32G32Sint => new FormatInfo(Format.R32G32Sint, 1, 1, 8, 2), + RtFormat.R32G32Uint => new FormatInfo(Format.R32G32Uint, 1, 1, 8, 2), + RtFormat.R16G16B16X16Float => new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8, 4), + RtFormat.B8G8R8A8Unorm => new FormatInfo(Format.B8G8R8A8Unorm, 1, 1, 4, 4), + RtFormat.B8G8R8A8Srgb => new FormatInfo(Format.B8G8R8A8Srgb, 1, 1, 4, 4), + RtFormat.R10G10B10A2Unorm => new FormatInfo(Format.R10G10B10A2Unorm, 1, 1, 4, 4), + RtFormat.R10G10B10A2Uint => new FormatInfo(Format.R10G10B10A2Uint, 1, 1, 4, 4), + RtFormat.R8G8B8A8Unorm => new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4), + RtFormat.R8G8B8A8Srgb => new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4), + RtFormat.R8G8B8X8Snorm => new FormatInfo(Format.R8G8B8A8Snorm, 1, 1, 4, 4), + RtFormat.R8G8B8X8Sint => new FormatInfo(Format.R8G8B8A8Sint, 1, 1, 4, 4), + RtFormat.R8G8B8X8Uint => new FormatInfo(Format.R8G8B8A8Uint, 1, 1, 4, 4), + RtFormat.R16G16Unorm => new FormatInfo(Format.R16G16Unorm, 1, 1, 4, 2), + RtFormat.R16G16Snorm => new FormatInfo(Format.R16G16Snorm, 1, 1, 4, 2), + RtFormat.R16G16Sint => new FormatInfo(Format.R16G16Sint, 1, 1, 4, 2), + RtFormat.R16G16Uint => new FormatInfo(Format.R16G16Uint, 1, 1, 4, 2), + RtFormat.R16G16Float => new FormatInfo(Format.R16G16Float, 1, 1, 4, 2), + RtFormat.R11G11B10Float => new FormatInfo(Format.R11G11B10Float, 1, 1, 4, 3), + RtFormat.R32Sint => new FormatInfo(Format.R32Sint, 1, 1, 4, 1), + RtFormat.R32Uint => new FormatInfo(Format.R32Uint, 1, 1, 4, 1), + RtFormat.R32Float => new FormatInfo(Format.R32Float, 1, 1, 4, 1), + RtFormat.B8G8R8X8Unorm => new FormatInfo(Format.B8G8R8A8Unorm, 1, 1, 4, 4), + RtFormat.B8G8R8X8Srgb => new FormatInfo(Format.B8G8R8A8Srgb, 1, 1, 4, 4), + RtFormat.B5G6R5Unorm => new FormatInfo(Format.B5G6R5Unorm, 1, 1, 2, 3), + RtFormat.B5G5R5A1Unorm => new FormatInfo(Format.B5G5R5A1Unorm, 1, 1, 2, 4), + RtFormat.R8G8Unorm => new FormatInfo(Format.R8G8Unorm, 1, 1, 2, 2), + RtFormat.R8G8Snorm => new FormatInfo(Format.R8G8Snorm, 1, 1, 2, 2), + RtFormat.R8G8Sint => new FormatInfo(Format.R8G8Sint, 1, 1, 2, 2), + RtFormat.R8G8Uint => new FormatInfo(Format.R8G8Uint, 1, 1, 2, 2), + RtFormat.R16Unorm => new FormatInfo(Format.R16Unorm, 1, 1, 2, 1), + RtFormat.R16Snorm => new FormatInfo(Format.R16Snorm, 1, 1, 2, 1), + RtFormat.R16Sint => new FormatInfo(Format.R16Sint, 1, 1, 2, 1), + RtFormat.R16Uint => new FormatInfo(Format.R16Uint, 1, 1, 2, 1), + RtFormat.R16Float => new FormatInfo(Format.R16Float, 1, 1, 2, 1), + RtFormat.R8Unorm => new FormatInfo(Format.R8Unorm, 1, 1, 1, 1), + RtFormat.R8Snorm => new FormatInfo(Format.R8Snorm, 1, 1, 1, 1), + RtFormat.R8Sint => new FormatInfo(Format.R8Sint, 1, 1, 1, 1), + RtFormat.R8Uint => new FormatInfo(Format.R8Uint, 1, 1, 1, 1), + RtFormat.B5G5R5X1Unorm => new FormatInfo(Format.B5G5R5X1Unorm, 1, 1, 2, 4), + RtFormat.R8G8B8X8Unorm => new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4), + RtFormat.R8G8B8X8Srgb => new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4), _ => FormatInfo.Default }; } diff --git a/Ryujinx.Graphics.Gpu/Window.cs b/Ryujinx.Graphics.Gpu/Window.cs index 10ee74bec..cf5c01efc 100644 --- a/Ryujinx.Graphics.Gpu/Window.cs +++ b/Ryujinx.Graphics.Gpu/Window.cs @@ -112,7 +112,7 @@ namespace Ryujinx.Graphics.Gpu Action<object> releaseCallback, object userObj) { - FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel); + FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel, 4); TextureInfo info = new TextureInfo( address,