From 815f1f4067fcffeb3b470e6788d39efeb06a642d Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Mon, 11 Apr 2022 16:17:06 +0100 Subject: [PATCH] Add support for sRGB TIC textures Without this sRGB textures would be interpreted as RGB leading to colours being slighly off. The sRGB flag isn't stored as part of format word so we reuse the _pad_ field of it to store the flag for the switch case. --- .../gpu/interconnect/graphics_context.h | 36 ++++++++++++++----- .../cpp/skyline/gpu/interconnect/types/tic.h | 6 ++-- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index f426e3a8..ddd92f91 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -1803,24 +1803,35 @@ namespace skyline::gpu::interconnect { } private: - texture::Format ConvertTicFormat(TextureImageControl::FormatWord format) { + texture::Format ConvertTicFormat(TextureImageControl::FormatWord format, bool srgb) { using TIC = TextureImageControl; - #define TIC_FORMAT(format, componentR, componentG, componentB, componentA) \ - TIC::FormatWord{TIC::ImageFormat::format, \ - TIC::ImageComponent::componentR, TIC::ImageComponent::componentG, TIC::ImageComponent::componentB, TIC::ImageComponent::componentA}.Raw() + #define TIC_FORMAT(fmt, compR, compG, compB, compA, srgb) \ + TIC::FormatWord{ .format = TIC::ImageFormat::fmt, \ + .componentR = TIC::ImageComponent::compR, \ + .componentG = TIC::ImageComponent::compG, \ + .componentB = TIC::ImageComponent::compB, \ + .componentA = TIC::ImageComponent::compA, \ + ._pad_ = srgb }.Raw() // Reuse _pad_ to store if the texture is sRGB // For formats where all components are of the same type #define TIC_FORMAT_ST(format, component) \ - TIC_FORMAT(format, component, component, component, component) + TIC_FORMAT(format, component, component, component, component, false) + + #define TIC_FORMAT_ST_SRGB(format, component) \ + TIC_FORMAT(format, component, component, component, component, true) #define TIC_FORMAT_CASE(ticFormat, skFormat, componentR, componentG, componentB, componentA) \ - case TIC_FORMAT(ticFormat, componentR, componentG, componentB, componentA): \ + case TIC_FORMAT(ticFormat, componentR, componentG, componentB, componentA, false): \ return format::skFormat #define TIC_FORMAT_CASE_ST(ticFormat, skFormat, component) \ case TIC_FORMAT_ST(ticFormat, component): \ return format::skFormat ## component + #define TIC_FORMAT_CASE_ST_SRGB(ticFormat, skFormat, component) \ + case TIC_FORMAT_ST_SRGB(ticFormat, component): \ + return format::skFormat ## Srgb + #define TIC_FORMAT_CASE_NORM(ticFormat, skFormat) \ TIC_FORMAT_CASE_ST(ticFormat, skFormat, Unorm); \ TIC_FORMAT_CASE_ST(ticFormat, skFormat, Snorm) @@ -1842,7 +1853,8 @@ namespace skyline::gpu::interconnect { TIC_FORMAT_CASE_ST(ticFormat, skFormat, Float) // Ignore the swizzle components of the format word - switch (format.Raw() & TextureImageControl::FormatWord::FormatColorComponentMask) { + format._pad_ = srgb; // Reuse the _pad_ field to store the srgb flag + switch ((format.Raw() & TextureImageControl::FormatWord::FormatColorComponentPadMask)) { TIC_FORMAT_CASE_NORM_INT(R8, R8); TIC_FORMAT_CASE_NORM_INT_FLOAT(R16, R16); @@ -1860,10 +1872,12 @@ namespace skyline::gpu::interconnect { TIC_FORMAT_CASE(S8D24, D24UnormS8Uint, Uint, Unorm, Unorm, Unorm); TIC_FORMAT_CASE_ST(B10G11R11, B10G11R11, Float); TIC_FORMAT_CASE_NORM_INT(A8B8G8R8, A8B8G8R8); + TIC_FORMAT_CASE_ST_SRGB(A8B8G8R8, A8B8G8R8, Unorm); TIC_FORMAT_CASE_NORM_INT(A2B10G10R10, A2B10G10R10); TIC_FORMAT_CASE_ST(E5B9G9R9, E5B9G9R9, Float); TIC_FORMAT_CASE_ST(BC1, BC1, Unorm); + TIC_FORMAT_CASE_ST_SRGB(BC1, BC1, Unorm); TIC_FORMAT_CASE_NORM(BC4, BC4); TIC_FORMAT_CASE_INT_FLOAT(R32G32, R32G32); TIC_FORMAT_CASE(D32S8, D32FloatS8Uint, Float, Uint, Uint, Unorm); @@ -1871,14 +1885,20 @@ namespace skyline::gpu::interconnect { TIC_FORMAT_CASE_NORM_INT_FLOAT(R16G16B16A16, R16G16B16A16); TIC_FORMAT_CASE_ST(Astc4x4, Astc4x4, Unorm); + TIC_FORMAT_CASE_ST_SRGB(Astc4x4, Astc4x4, Unorm); TIC_FORMAT_CASE_ST(Astc6x6, Astc6x6, Unorm); + TIC_FORMAT_CASE_ST_SRGB(Astc6x6, Astc6x6, Unorm); TIC_FORMAT_CASE_ST(Astc8x8, Astc8x8, Unorm); + TIC_FORMAT_CASE_ST_SRGB(Astc8x8, Astc8x8, Unorm); TIC_FORMAT_CASE_ST(BC2, BC2, Unorm); + TIC_FORMAT_CASE_ST_SRGB(BC2, BC2, Unorm); TIC_FORMAT_CASE_ST(BC3, BC3, Unorm); + TIC_FORMAT_CASE_ST_SRGB(BC3, BC3, Unorm); TIC_FORMAT_CASE_NORM(BC5, BC5); TIC_FORMAT_CASE(Bc6HUfloat, Bc6HUfloat, Float, Float, Float, Float); TIC_FORMAT_CASE(Bc6HSfloat, Bc6HSfloat, Float, Float, Float, Float); TIC_FORMAT_CASE_ST(BC7, BC7, Unorm); + TIC_FORMAT_CASE_ST_SRGB(BC7, BC7, Unorm); TIC_FORMAT_CASE_INT_FLOAT(R32G32B32A32, R32G32B32A32); default: @@ -1943,7 +1963,7 @@ namespace skyline::gpu::interconnect { if (textureIt.second) { // If the entry didn't exist prior then we need to convert the TIC to a GuestTexture auto &guest{poolTexture.guest}; - guest.format = ConvertTicFormat(textureControl.formatWord); + guest.format = ConvertTicFormat(textureControl.formatWord, textureControl.isSrgb); if (guest.format->IsDepthOrStencil()) // G/R are equivalent for depth/stencil guest.swizzle = ConvertTicSwizzleMapping(textureControl.formatWord); diff --git a/app/src/main/cpp/skyline/gpu/interconnect/types/tic.h b/app/src/main/cpp/skyline/gpu/interconnect/types/tic.h index b83614fa..fd00bf1f 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/types/tic.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/types/tic.h @@ -202,7 +202,7 @@ namespace skyline::gpu::interconnect { // 0x00 struct FormatWord { - static constexpr u32 FormatColorComponentMask{0b111'111'111'111'1111111}; //!< Mask for the format and component fields + static constexpr u32 FormatColorComponentPadMask{(1U << 31) | 0b111'111'111'111'1111111U}; //!< Mask for the format, component and pad fields ImageFormat format : 7; ImageComponent componentR : 3; @@ -219,8 +219,8 @@ namespace skyline::gpu::interconnect { constexpr u32 Raw() const { if (std::is_constant_evaluated()) { - u32 raw{}; - raw <<= 1; + u32 raw{_pad_}; + raw <<= 3; raw |= static_cast(swizzleW); raw <<= 3; raw |= static_cast(swizzleZ);