From cde8661bc17dcbaf98769d44cb71f2cf2b1297d0 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 3 Nov 2024 10:53:39 +0100 Subject: [PATCH] [dxvk] Add helper to compute clear values for compressed formats --- src/dxvk/dxvk_util.h | 100 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/src/dxvk/dxvk_util.h b/src/dxvk/dxvk_util.h index 967458faf..edeb22398 100644 --- a/src/dxvk/dxvk_util.h +++ b/src/dxvk/dxvk_util.h @@ -386,5 +386,103 @@ namespace dxvk::util { bool isDualSourceBlendFactor( VkBlendFactor factor); - + + /** + * \brief Computes unsigned normalized value + * + * Doesn't necessarily do perfect rounding. + * \param [in] float Float value + * \param [in] bits Bit count + * \returns Normalized value + */ + inline uint32_t computeUnorm(float f, uint32_t bits) { + f = std::max(f, 0.0f); + f = std::min(f, 1.0f); + return uint32_t((f * float((1u << bits) - 1u)) + 0.5f); + } + + /** + * \brief Computes signed normalized value + * + * Doesn't necessarily do perfect rounding. + * \param [in] float Float value + * \param [in] bits Bit count + * \returns Normalized value + */ + inline uint32_t computeSnorm(float f, uint32_t bits) { + f = std::max(f, -1.0f); + f = std::min(f, 1.0f); + return int32_t((f * float((1u << (bits - 1u)) - 1u)) + (f < 0.0f ? -0.5f : 0.5f)); + } + + /** + * \brief Computes clear payload for compressed image blocks + * + * Ignores whether the format is sRGB or not. If this is relevant, + * the input color must be converted into the correct space first. + * Does not support BC6H or BC7 formats. + * \param [in] format Image format + * \param [in] color Clear color, as floats + * \returns Block data as unsigned integers + */ + inline VkClearColorValue encodeClearBlockValue( + VkFormat format, + const VkClearColorValue& color) { + VkClearColorValue result = { }; + + switch (format) { + case VK_FORMAT_BC1_RGB_SRGB_BLOCK: + case VK_FORMAT_BC1_RGB_UNORM_BLOCK: + case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: + case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: { + // Encode clear color as color0, table will be all zeroes + result.uint32[0] = (computeUnorm(color.float32[2], 5) << 0) + | (computeUnorm(color.float32[1], 6) << 5) + | (computeUnorm(color.float32[0], 5) << 11); + } return result; + + case VK_FORMAT_BC2_SRGB_BLOCK: + case VK_FORMAT_BC2_UNORM_BLOCK: { + // Alpha is encoded in the first four bytes as four-bit + // values. The color portion is identical to BC1. + uint32_t alpha = 0x11111111u * computeUnorm(color.float32[3], 4); + result.uint32[0] = alpha; + result.uint32[1] = alpha; + result.uint32[2] = (computeUnorm(color.float32[2], 5) << 0) + | (computeUnorm(color.float32[1], 6) << 5) + | (computeUnorm(color.float32[0], 5) << 11); + } return result; + + case VK_FORMAT_BC3_UNORM_BLOCK: + case VK_FORMAT_BC3_SRGB_BLOCK: { + // Encode alpha as alpha0, color portion identical to BC1 + result.uint32[0] = computeUnorm(color.float32[3], 8); + result.uint32[2] = (computeUnorm(color.float32[2], 5) << 0) + | (computeUnorm(color.float32[1], 6) << 5) + | (computeUnorm(color.float32[0], 5) << 11); + } return result; + + case VK_FORMAT_BC4_SNORM_BLOCK: { + result.uint32[0] = computeSnorm(color.float32[0], 8); + } return result; + + case VK_FORMAT_BC4_UNORM_BLOCK: { + result.uint32[0] = computeUnorm(color.float32[0], 8); + } return result; + + case VK_FORMAT_BC5_SNORM_BLOCK: { + result.uint32[0] = computeSnorm(color.float32[0], 8); + result.uint32[2] = computeSnorm(color.float32[1], 8); + } return result; + + case VK_FORMAT_BC5_UNORM_BLOCK: { + result.uint32[0] = computeUnorm(color.float32[0], 8); + result.uint32[2] = computeUnorm(color.float32[1], 8); + } return result; + + default: + return color; + } + } + }