Rework swizzle infrastructure to support arbritary format swizzles

This is required to support R4G4B4A4 which has no directly corresponding Vulkan format.

Co-authored-by: Lunar-Pixel <lunarn452@gmail.com>
This commit is contained in:
Billy Laws 2022-04-12 17:04:46 +01:00 committed by PixelyIon
parent 6f85a66151
commit 3f3acc31d8
4 changed files with 42 additions and 30 deletions

View File

@ -1951,22 +1951,17 @@ namespace skyline::gpu::interconnect {
#undef TIC_FORMAT_CASE_NORM_INT_FLOAT #undef TIC_FORMAT_CASE_NORM_INT_FLOAT
} }
/** vk::ComponentMapping ConvertTicSwizzleMapping(TextureImageControl::FormatWord format, vk::ComponentMapping swizzleMapping) {
* @tparam ConvGR Converts all green component auto convertComponentSwizzle{[swizzleMapping](TextureImageControl::ImageSwizzle swizzle) {
* @tparam SwapBR Swaps blue and red components
*/
template<bool ConvGR, bool SwapBR>
vk::ComponentMapping ConvertTicSwizzleMapping(TextureImageControl::FormatWord format) {
auto convertComponentSwizzle{[](TextureImageControl::ImageSwizzle swizzle) {
switch (swizzle) { switch (swizzle) {
case TextureImageControl::ImageSwizzle::R: case TextureImageControl::ImageSwizzle::R:
return SwapBR ? vk::ComponentSwizzle::eB : vk::ComponentSwizzle::eR; return swizzleMapping.r;
case TextureImageControl::ImageSwizzle::G: case TextureImageControl::ImageSwizzle::G:
return ConvGR ? vk::ComponentSwizzle::eR : vk::ComponentSwizzle::eG; return swizzleMapping.g;
case TextureImageControl::ImageSwizzle::B: case TextureImageControl::ImageSwizzle::B:
return SwapBR ? vk::ComponentSwizzle::eR : vk::ComponentSwizzle::eB; return swizzleMapping.b;
case TextureImageControl::ImageSwizzle::A: case TextureImageControl::ImageSwizzle::A:
return vk::ComponentSwizzle::eA; return swizzleMapping.a;
case TextureImageControl::ImageSwizzle::Zero: case TextureImageControl::ImageSwizzle::Zero:
return vk::ComponentSwizzle::eZero; return vk::ComponentSwizzle::eZero;
case TextureImageControl::ImageSwizzle::OneFloat: case TextureImageControl::ImageSwizzle::OneFloat:
@ -2006,13 +2001,7 @@ namespace skyline::gpu::interconnect {
auto &guest{poolTexture.guest}; auto &guest{poolTexture.guest};
guest.format = ConvertTicFormat(textureControl.formatWord, textureControl.isSrgb); guest.format = ConvertTicFormat(textureControl.formatWord, textureControl.isSrgb);
guest.aspect = guest.format->Aspect(textureControl.formatWord.swizzleX == TextureImageControl::ImageSwizzle::R); guest.aspect = guest.format->Aspect(textureControl.formatWord.swizzleX == TextureImageControl::ImageSwizzle::R);
guest.swizzle = ConvertTicSwizzleMapping(textureControl.formatWord, guest.format->swizzleMapping);
if (guest.format->IsDepthOrStencil()) // G/R are equivalent for depth/stencil
guest.swizzle = ConvertTicSwizzleMapping<true, false>(textureControl.formatWord);
else if (guest.format->swapRedBlue)
guest.swizzle = ConvertTicSwizzleMapping<false, true>(textureControl.formatWord);
else
guest.swizzle = ConvertTicSwizzleMapping<false, false>(textureControl.formatWord);
constexpr size_t CubeFaceCount{6}; //!< The amount of faces of a cube constexpr size_t CubeFaceCount{6}; //!< The amount of faces of a cube

View File

@ -121,7 +121,7 @@ namespace skyline::gpu {
throw exception("Cannot update swapchain to accomodate image extent: {}x{} ({}x{}-{}x{})", extent.width, extent.height, capabilities.minImageExtent.width, capabilities.minImageExtent.height, capabilities.maxImageExtent.width, capabilities.maxImageExtent.height); throw exception("Cannot update swapchain to accomodate image extent: {}x{} ({}x{}-{}x{})", extent.width, extent.height, capabilities.minImageExtent.width, capabilities.minImageExtent.height, capabilities.maxImageExtent.width, capabilities.maxImageExtent.height);
vk::Format vkFormat{*format}; vk::Format vkFormat{*format};
if (vkFormat == vk::Format::eB5G6R5UnormPack16 && format->swapRedBlue) if (format == gpu::format::R5G6B5Unorm)
// B5G6R5 isn't generally supported by the swapchain and the format is used for R5G6B5 with swapped R/B channels to avoid aliasing so we reverse that by using R5G6B5 as the underlying Vulkan format for the swapchain which should be automatically handled by the driver for any copies from B5G6R5 textures and the data representation should be the same as B5G6R5 with swapped R/B channels so not reporting the correct texture::Format should be fine // B5G6R5 isn't generally supported by the swapchain and the format is used for R5G6B5 with swapped R/B channels to avoid aliasing so we reverse that by using R5G6B5 as the underlying Vulkan format for the swapchain which should be automatically handled by the driver for any copies from B5G6R5 textures and the data representation should be the same as B5G6R5 with swapped R/B channels so not reporting the correct texture::Format should be fine
vkFormat = vk::Format::eR5G6B5UnormPack16; vkFormat = vk::Format::eR5G6B5UnormPack16;

View File

@ -64,10 +64,21 @@ namespace skyline::gpu::format {
FORMAT_NORM_INT_FLOAT(R16, 16, eR16); FORMAT_NORM_INT_FLOAT(R16, 16, eR16);
FORMAT_NORM_INT_SRGB(R8G8, 16, eR8G8); FORMAT_NORM_INT_SRGB(R8G8, 16, eR8G8);
FORMAT(B5G6R5Unorm, 16, eB5G6R5UnormPack16); FORMAT(B5G6R5Unorm, 16, eB5G6R5UnormPack16);
FORMAT(R5G6B5Unorm, 16, eB5G6R5UnormPack16, .swapRedBlue = true); // Used by SurfaceFlinger FORMAT(R5G6B5Unorm, 16, eB5G6R5UnormPack16, .swizzleMapping = {
FORMAT(R4G4B4A4Unorm, 16, eR4G4B4A4UnormPack16); .r = vk::ComponentSwizzle::eB,
.b = vk::ComponentSwizzle::eR
}); // Used by SurfaceFlinger
FORMAT(R4G4B4A4Unorm, 16, eR4G4B4A4UnormPack16, .swizzleMapping = {
.r = vk::ComponentSwizzle::eA,
.g = vk::ComponentSwizzle::eB,
.b = vk::ComponentSwizzle::eG,
.a = vk::ComponentSwizzle::eR
});
FORMAT(B5G5R5A1Unorm, 16, eB5G5R5A1UnormPack16); FORMAT(B5G5R5A1Unorm, 16, eB5G5R5A1UnormPack16);
FORMAT(A1B5G5R5Unorm, 16, eA1R5G5B5UnormPack16, .swapRedBlue = true); FORMAT(A1B5G5R5Unorm, 16, eA1R5G5B5UnormPack16, .swizzleMapping = {
.r = vk::ComponentSwizzle::eB,
.b = vk::ComponentSwizzle::eR
});
FORMAT_INT_FLOAT(R32, 32, eR32); FORMAT_INT_FLOAT(R32, 32, eR32);
FORMAT_NORM_INT_FLOAT(R16G16, 32, eR16G16); FORMAT_NORM_INT_FLOAT(R16G16, 32, eR16G16);
@ -132,18 +143,29 @@ namespace skyline::gpu::format {
); );
// Depth/Stencil Formats // Depth/Stencil Formats
FORMAT(D16Unorm, 16, eD16Unorm, vka::eDepth); // All of these have a G->R swizzle
FORMAT(D16Unorm, 16, eD16Unorm, vka::eDepth, .swizzleMapping = {
.g = vk::ComponentSwizzle::eR
});
FORMAT(D32Float, 32, eD32Sfloat, vka::eDepth); FORMAT(D32Float, 32, eD32Sfloat, vka::eDepth, .swizzleMapping = {
.g = vk::ComponentSwizzle::eR
});
FORMAT(D24UnormS8Uint, 32, eD24UnormS8Uint, .vkAspect = { FORMAT(D24UnormS8Uint, 32, eD24UnormS8Uint, .vkAspect = {
vka::eStencil | vka::eDepth vka::eStencil | vka::eDepth
}, .swizzleMapping = {
.g = vk::ComponentSwizzle::eR
}); });
FORMAT(D32FloatS8Uint, 32, eD32SfloatS8Uint, .vkAspect = { FORMAT(D32FloatS8Uint, 32, eD32SfloatS8Uint, .vkAspect = {
vka::eStencil | vka::eDepth vka::eStencil | vka::eDepth
}, .swizzleMapping = {
.g = vk::ComponentSwizzle::eR
}); });
FORMAT(S8UintD24Unorm, 32, eD24UnormS8Uint, .vkAspect = { FORMAT(S8UintD24Unorm, 32, eD24UnormS8Uint, .vkAspect = {
vka::eStencil | vka::eDepth vka::eStencil | vka::eDepth
}, .stencilFirst = true); // TODO: Swizzle Depth/Stencil }, .swizzleMapping = {
.g = vk::ComponentSwizzle::eR
});
#undef FORMAT #undef FORMAT

View File

@ -68,7 +68,12 @@ namespace skyline::gpu {
vk::ImageAspectFlags vkAspect{vk::ImageAspectFlagBits::eColor}; vk::ImageAspectFlags vkAspect{vk::ImageAspectFlagBits::eColor};
u16 blockHeight{1}; //!< The height of a block in pixels u16 blockHeight{1}; //!< The height of a block in pixels
u16 blockWidth{1}; //!< The width of a block in pixels u16 blockWidth{1}; //!< The width of a block in pixels
bool swapRedBlue{}; //!< Swap the red and blue channels, ignored on depth formats vk::ComponentMapping swizzleMapping{
.r = vk::ComponentSwizzle::eR,
.g = vk::ComponentSwizzle::eG,
.b = vk::ComponentSwizzle::eB,
.a = vk::ComponentSwizzle::eA
};
bool stencilFirst{}; //!< If the stencil channel is the first channel in the format bool stencilFirst{}; //!< If the stencil channel is the first channel in the format
constexpr bool IsCompressed() const { constexpr bool IsCompressed() const {
@ -115,10 +120,6 @@ namespace skyline::gpu {
return bpb == other.bpb && blockHeight == other.blockHeight && blockWidth == other.blockWidth; return bpb == other.bpb && blockHeight == other.blockHeight && blockWidth == other.blockWidth;
} }
constexpr bool IsDepthOrStencil() const {
return bool{vkAspect & (vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil)};
}
/** /**
* @brief Determines the image aspect to use based off of the format and the first swizzle component * @brief Determines the image aspect to use based off of the format and the first swizzle component
*/ */