From 969b7505acd11d0081e9091e2eef5a2bf994390e Mon Sep 17 00:00:00 2001 From: Lander Gallastegi Date: Wed, 16 Oct 2024 11:55:45 +0200 Subject: [PATCH] video_core: Rework clear values (#1381) * Clear color convertion * Add missing formats * Add swap handling * Format bits and offsets * clang-format * Make num_components const * Initialize alpha to 1 * Handle SnormNz as Snorm * Don0t leave accidental nonzero values * parallel3 for linux-qt * Move number_utils to common --- CMakeLists.txt | 7 +- externals/CMakeLists.txt | 8 +- src/common/number_utils.cpp | 161 ++++++++ src/common/number_utils.h | 28 ++ src/video_core/amdgpu/pixel_format.cpp | 36 +- .../renderer_vulkan/liverpool_to_vk.cpp | 383 ++++++++++++++++-- 6 files changed, 561 insertions(+), 62 deletions(-) create mode 100644 src/common/number_utils.cpp create mode 100644 src/common/number_utils.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 781e93e1..ff7717c7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,6 +432,8 @@ set(COMMON src/common/logging/backend.cpp src/common/version.h src/common/ntapi.h src/common/ntapi.cpp + src/common/number_utils.h + src/common/number_utils.cpp src/common/memory_patcher.h src/common/memory_patcher.cpp src/common/scm_rev.cpp @@ -771,7 +773,7 @@ endif() create_target_directory_groups(shadps4) -target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn) +target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half) target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml) target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h") @@ -794,9 +796,6 @@ if (APPLE) # Replacement for std::chrono::time_zone target_link_libraries(shadps4 PRIVATE date::date-tz) - - # Half float conversions for F16C patches - target_link_libraries(shadps4 PRIVATE half) endif() if (NOT ENABLE_QT_GUI) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 2f9336c2..9cae3438 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -141,11 +141,11 @@ if (WIN32) target_compile_options(sirit PUBLIC "-Wno-error=unused-command-line-argument") endif() -if (APPLE) - # half - add_library(half INTERFACE) - target_include_directories(half INTERFACE half/include) +# half +add_library(half INTERFACE) +target_include_directories(half INTERFACE half/include) +if (APPLE) # date if (NOT TARGET date::date-tz) option(BUILD_TZ_LIB "" ON) diff --git a/src/common/number_utils.cpp b/src/common/number_utils.cpp new file mode 100644 index 00000000..af29e5cd --- /dev/null +++ b/src/common/number_utils.cpp @@ -0,0 +1,161 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include + +#include "common/number_utils.h" +#include "video_core/amdgpu/pixel_format.h" +#include "video_core/amdgpu/types.h" + +#define UF11_EXPONENT_SHIFT 6 +#define UF10_EXPONENT_SHIFT 5 + +#define RGB9E5_MANTISSA_BITS 9 +#define RGB9E5_EXP_BIAS 1 + +#define F32_INFINITY 0x7f800000 + +namespace NumberUtils { + +float Uf11ToF32(u16 val) { + union { + float f; + u32 ui; + } f32; + + int exponent = (val & 0x07c0) >> UF11_EXPONENT_SHIFT; + int mantissa = (val & 0x003f); + + f32.f = 0.0; + + if (exponent == 0) { + if (mantissa != 0) { + const float scale = 1.0 / (1 << 20); + f32.f = scale * mantissa; + } + } else if (exponent == 31) { + f32.ui = F32_INFINITY | mantissa; + } else { + float scale, decimal; + exponent -= 15; + if (exponent < 0) { + scale = 1.0f / (1 << -exponent); + } else { + scale = (float)(1 << exponent); + } + decimal = 1.0f + (float)mantissa / 64; + f32.f = scale * decimal; + } + + return f32.f; +} + +float Uf10ToF32(u16 val) { + union { + float f; + u32 ui; + } f32; + + int exponent = (val & 0x03e0) >> UF10_EXPONENT_SHIFT; + int mantissa = (val & 0x001f); + + f32.f = 0.0; + + if (exponent == 0) { + if (mantissa != 0) { + const float scale = 1.0 / (1 << 19); + f32.f = scale * mantissa; + } + } else if (exponent == 31) { + f32.ui = F32_INFINITY | mantissa; + } else { + float scale, decimal; + exponent -= 15; + if (exponent < 0) { + scale = 1.0f / (1 << -exponent); + } else { + scale = (float)(1 << exponent); + } + decimal = 1.0f + (float)mantissa / 32; + f32.f = scale * decimal; + } + + return f32.f; +} + +float Uf16ToF32(u16 val) { + return half_float::half_cast(reinterpret_cast(val)); +} + +float U2ToUnorm(u8 val) { + static constexpr auto c = 1.0f / 3.0f; + return float(val * c); +} + +float S2ToSnorm(s8 val) { + static constexpr auto c = 1.0f / 1.0f; + return float(val * c); +} + +float U4ToUnorm(u8 val) { + static constexpr auto c = 1.0f / 15.0f; + return float(val * c); +} + +float S4ToSnorm(s8 val) { + static constexpr auto c = 1.0f / 7.0f; + return float(val * c); +} + +float U5ToUnorm(u8 val) { + static constexpr auto c = 1.0f / 31.0f; + return float(val * c); +} + +float S5ToSnorm(s8 val) { + static constexpr auto c = 1.0f / 15.0f; + return float(val * c); +} + +float U6ToUnorm(u8 val) { + static constexpr auto c = 1.0f / 63.0f; + return float(val * c); +} + +float S6ToSnorm(s8 val) { + static constexpr auto c = 1.0f / 31.0f; + return float(val * c); +} + +float U8ToUnorm(u8 val) { + static constexpr auto c = 1.0f / 255.0f; + return float(val * c); +} + +float S8ToSnorm(s8 val) { + static constexpr auto c = 1.0f / 127.0f; + return float(val * c); +} + +float U10ToUnorm(u16 val) { + static constexpr auto c = 1.0f / 1023.0f; + return float(val * c); +} + +float S10ToSnorm(s16 val) { + static constexpr auto c = 1.0f / 511.0f; + return float(val * c); +} + +float U16ToUnorm(u16 val) { + static constexpr auto c = 1.0f / 65535.0f; + return float(val * c); +} + +float S16ToSnorm(s16 val) { + static constexpr auto c = 1.0f / 32767.0f; + return float(val * c); +} + +} // namespace NumberUtils \ No newline at end of file diff --git a/src/common/number_utils.h b/src/common/number_utils.h new file mode 100644 index 00000000..05c62a1c --- /dev/null +++ b/src/common/number_utils.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" + +namespace NumberUtils { + +float Uf11ToF32(u16 val); +float Uf10ToF32(u16 val); +float Uf16ToF32(u16 val); +float U2ToUnorm(u8 val); +float S2ToSnorm(s8 val); +float U4ToUnorm(u8 val); +float S4ToSnorm(s8 val); +float U5ToUnorm(u8 val); +float S5ToSnorm(s8 val); +float U6ToUnorm(u8 val); +float S6ToSnorm(s8 val); +float U8ToUnorm(u8 val); +float S8ToSnorm(s8 val); +float U10ToUnorm(u16 val); +float S10ToSnorm(s16 val); +float U16ToUnorm(u16 val); +float S16ToSnorm(s16 val); + +} // namespace NumberUtils diff --git a/src/video_core/amdgpu/pixel_format.cpp b/src/video_core/amdgpu/pixel_format.cpp index 6744891a..b13fc2d1 100644 --- a/src/video_core/amdgpu/pixel_format.cpp +++ b/src/video_core/amdgpu/pixel_format.cpp @@ -144,10 +144,10 @@ static constexpr std::array component_bits = { std::array{8, 8, 0, 0}, // 3 Format8_8 std::array{32, 0, 0, 0}, // 4 Format32 std::array{16, 16, 0, 0}, // 5 Format16_16 - std::array{10, 11, 11, 0}, // 6 Format10_11_11 - std::array{11, 11, 10, 0}, // 7 Format11_11_10 - std::array{10, 10, 10, 2}, // 8 Format10_10_10_2 - std::array{2, 10, 10, 10}, // 9 Format2_10_10_10 + std::array{11, 11, 10, 0}, // 6 Format10_11_11 + std::array{10, 11, 11, 0}, // 7 Format11_11_10 + std::array{2, 10, 10, 10}, // 8 Format10_10_10_2 + std::array{10, 10, 10, 2}, // 9 Format2_10_10_10 std::array{8, 8, 8, 8}, // 10 Format8_8_8_8 std::array{32, 32, 0, 0}, // 11 Format32_32 std::array{16, 16, 16, 16}, // 12 Format16_16_16_16 @@ -155,12 +155,12 @@ static constexpr std::array component_bits = { std::array{32, 32, 32, 32}, // 14 Format32_32_32_32 std::array{0, 0, 0, 0}, // 15 std::array{5, 6, 5, 0}, // 16 Format5_6_5 - std::array{1, 5, 5, 5}, // 17 Format1_5_5_5 - std::array{5, 5, 5, 1}, // 18 Format5_5_5_1 + std::array{5, 5, 5, 1}, // 17 Format1_5_5_5 + std::array{1, 5, 5, 5}, // 18 Format5_5_5_1 std::array{4, 4, 4, 4}, // 19 Format4_4_4_4 - std::array{8, 24, 0, 0}, // 20 Format8_24 - std::array{24, 8, 0, 0}, // 21 Format24_8 - std::array{24, 8, 0, 0}, // 22 FormatX24_8_32 + std::array{24, 8, 0, 0}, // 20 Format8_24 + std::array{8, 24, 0, 0}, // 21 Format24_8 + std::array{8, 24, 0, 0}, // 22 FormatX24_8_32 std::array{0, 0, 0, 0}, // 23 std::array{0, 0, 0, 0}, // 24 std::array{0, 0, 0, 0}, // 25 @@ -197,10 +197,10 @@ static constexpr std::array component_offset = { std::array{0, 8, -1, -1}, // 3 Format8_8 std::array{0, -1, -1, -1}, // 4 Format32 std::array{0, 16, -1, -1}, // 5 Format16_16 - std::array{0, 10, 21, -1}, // 6 Format10_11_11 - std::array{0, 11, 22, -1}, // 7 Format11_11_10 - std::array{0, 10, 20, 30}, // 8 Format10_10_10_2 - std::array{0, 2, 12, 22}, // 9 Format2_10_10_10 + std::array{0, 11, 22, -1}, // 6 Format10_11_11 + std::array{0, 10, 21, -1}, // 7 Format11_11_10 + std::array{0, 2, 12, 22}, // 8 Format10_10_10_2 + std::array{0, 10, 20, 30}, // 9 Format2_10_10_10 std::array{0, 8, 16, 24}, // 10 Format8_8_8_8 std::array{0, 32, -1, -1}, // 11 Format32_32 std::array{0, 16, 32, 48}, // 12 Format16_16_16_16 @@ -208,12 +208,12 @@ static constexpr std::array component_offset = { std::array{0, 32, 64, 96}, // 14 Format32_32_32_32 std::array{-1, -1, -1, -1}, // 15 std::array{0, 5, 11, -1}, // 16 Format5_6_5 - std::array{0, 1, 6, 11}, // 17 Format1_5_5_5 - std::array{0, 5, 10, 15}, // 18 Format5_5_5_1 + std::array{0, 5, 10, 15}, // 17 Format1_5_5_5 + std::array{0, 1, 6, 11}, // 18 Format5_5_5_1 std::array{0, 4, 8, 12}, // 19 Format4_4_4_4 - std::array{0, 8, -1, -1}, // 20 Format8_24 - std::array{0, 24, -1, -1}, // 21 Format24_8 - std::array{0, 24, -1, -1}, // 22 FormatX24_8_32 + std::array{0, 24, -1, -1}, // 20 Format8_24 + std::array{0, 8, -1, -1}, // 21 Format24_8 + std::array{0, 8, -1, -1}, // 22 FormatX24_8_32 std::array{-1, -1, -1, -1}, // 23 std::array{-1, -1, -1, -1}, // 24 std::array{-1, -1, -1, -1}, // 25 diff --git a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp index a68ec1e7..3e43c50e 100644 --- a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp +++ b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp @@ -2,11 +2,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/assert.h" +#include "common/number_utils.h" #include "video_core/amdgpu/pixel_format.h" #include "video_core/renderer_vulkan/liverpool_to_vk.h" #include +#define INVALID_NUMBER_FORMAT_COMBO \ + LOG_ERROR(Render_Vulkan, "Unsupported number type {} for format {}", number_type, format); + namespace Vulkan::LiverpoolToVK { using DepthBuffer = Liverpool::DepthBuffer; @@ -725,55 +729,362 @@ void EmitQuadToTriangleListIndices(u8* out_ptr, u32 num_vertices) { } } -static constexpr float U8ToUnorm(u8 v) { - static constexpr auto c = 1.0f / 255.0f; - return float(v * c); -} - vk::ClearValue ColorBufferClearValue(const AmdGpu::Liverpool::ColorBuffer& color_buffer) { const auto comp_swap = color_buffer.info.comp_swap.Value(); - ASSERT_MSG(comp_swap == Liverpool::ColorBuffer::SwapMode::Standard || - comp_swap == Liverpool::ColorBuffer::SwapMode::Alternate, - "Unsupported component swap mode {}", static_cast(comp_swap)); - - const bool comp_swap_alt = comp_swap == Liverpool::ColorBuffer::SwapMode::Alternate; + const auto format = color_buffer.info.format.Value(); + const auto number_type = color_buffer.info.number_type.Value(); const auto& c0 = color_buffer.clear_word0; const auto& c1 = color_buffer.clear_word1; const auto num_bits = AmdGpu::NumBits(color_buffer.info.format); + const auto num_components = AmdGpu::NumComponents(format); + + const bool comp_swap_alt = + comp_swap == AmdGpu::Liverpool::ColorBuffer::SwapMode::Alternate || + comp_swap == AmdGpu::Liverpool::ColorBuffer::SwapMode::AlternateReverse; + const bool comp_swap_reverse = + comp_swap == AmdGpu::Liverpool::ColorBuffer::SwapMode::StandardReverse || + comp_swap == AmdGpu::Liverpool::ColorBuffer::SwapMode::AlternateReverse; vk::ClearColorValue color{}; - switch (color_buffer.info.number_type) { - case AmdGpu::NumberFormat::Snorm: - [[fallthrough]]; - case AmdGpu::NumberFormat::SnormNz: - [[fallthrough]]; - case AmdGpu::NumberFormat::Unorm: - [[fallthrough]]; - case AmdGpu::NumberFormat::Srgb: { - switch (num_bits) { - case 32: { - color.float32 = std::array{ - U8ToUnorm((c0 >> (comp_swap_alt ? 16 : 0)) & 0xff), - U8ToUnorm((c0 >> 8) & 0xff), - U8ToUnorm((c0 >> (comp_swap_alt ? 0 : 16)) & 0xff), - U8ToUnorm((c0 >> 24) & 0xff), - }; - break; - } - default: { - LOG_ERROR(Render_Vulkan, "Missing clear color conversion for bits {}", num_bits); - break; - } - } + + switch (number_type) { + case AmdGpu::NumberFormat::Uint: + case AmdGpu::NumberFormat::Sint: + color.uint32[3] = 1; + break; + default: + color.float32[3] = 1.0f; break; } - default: { - LOG_ERROR(Render_Vulkan, "Missing clear color conversion for type {}", - color_buffer.info.number_type.Value()); + + switch (format) { + case AmdGpu::DataFormat::Format8: + switch (number_type) { + case AmdGpu::NumberFormat::Unorm: + case AmdGpu::NumberFormat::Srgb: // Should we handle gamma correction here? + color.float32[0] = NumberUtils::U8ToUnorm(c0 & 0xff); + break; + break; + case AmdGpu::NumberFormat::Snorm: + case AmdGpu::NumberFormat::SnormNz: + color.float32[0] = NumberUtils::S8ToSnorm(c0 & 0xff); + break; + case AmdGpu::NumberFormat::Uint: + case AmdGpu::NumberFormat::Sint: + color.uint32[0] = c0; + break; + default: + INVALID_NUMBER_FORMAT_COMBO; + break; + } + break; + case AmdGpu::DataFormat::Format16: + switch (number_type) { + case AmdGpu::NumberFormat::Unorm: + color.float32[0] = NumberUtils::U16ToUnorm(c0 & 0xffff); + break; + case AmdGpu::NumberFormat::Snorm: + case AmdGpu::NumberFormat::SnormNz: + color.float32[0] = NumberUtils::S16ToSnorm(c0 & 0xffff); + break; + case AmdGpu::NumberFormat::Uint: + case AmdGpu::NumberFormat::Sint: + color.uint32[0] = c0; + break; + case AmdGpu::NumberFormat::Float: + color.float32[0] = NumberUtils::Uf16ToF32(c0 & 0xffff); + break; + default: + INVALID_NUMBER_FORMAT_COMBO; + break; + } + break; + case AmdGpu::DataFormat::Format8_8: + switch (number_type) { + case AmdGpu::NumberFormat::Unorm: + case AmdGpu::NumberFormat::Srgb: // Should we handle gamma correction here? + color.float32[0] = NumberUtils::U8ToUnorm(c0 & 0xff); + color.float32[1] = NumberUtils::U8ToUnorm((c0 >> 8) & 0xff); + break; + case AmdGpu::NumberFormat::Snorm: + case AmdGpu::NumberFormat::SnormNz: + color.float32[0] = NumberUtils::S8ToSnorm(c0 & 0xff); + color.float32[1] = NumberUtils::S8ToSnorm((c0 >> 8) & 0xff); + break; + case AmdGpu::NumberFormat::Uint: + case AmdGpu::NumberFormat::Sint: + color.uint32[0] = c0 & 0xff; + color.uint32[1] = (c0 >> 8) & 0xff; + break; + default: + INVALID_NUMBER_FORMAT_COMBO; + break; + } + break; + case AmdGpu::DataFormat::Format32: + switch (number_type) { + case AmdGpu::NumberFormat::Uint: + case AmdGpu::NumberFormat::Sint: + color.uint32[0] = c0; + break; + case AmdGpu::NumberFormat::Float: + color.float32[0] = *(reinterpret_cast(&c0)); + break; + default: + INVALID_NUMBER_FORMAT_COMBO; + break; + } + break; + case AmdGpu::DataFormat::Format16_16: + switch (number_type) { + case AmdGpu::NumberFormat::Unorm: + color.float32[0] = NumberUtils::U16ToUnorm(c0 & 0xffff); + color.float32[1] = NumberUtils::U16ToUnorm((c0 >> 16) & 0xffff); + break; + case AmdGpu::NumberFormat::Snorm: + case AmdGpu::NumberFormat::SnormNz: + color.float32[0] = NumberUtils::S16ToSnorm(c0 & 0xffff); + color.float32[1] = NumberUtils::S16ToSnorm((c0 >> 16) & 0xffff); + break; + case AmdGpu::NumberFormat::Uint: + case AmdGpu::NumberFormat::Sint: + color.uint32[0] = c0 & 0xffff; + color.uint32[1] = (c0 >> 16) & 0xffff; + break; + case AmdGpu::NumberFormat::Float: + color.float32[0] = NumberUtils::Uf16ToF32(c0 & 0xffff); + color.float32[1] = NumberUtils::Uf16ToF32((c0 >> 16) & 0xffff); + break; + default: + INVALID_NUMBER_FORMAT_COMBO; + break; + } + break; + case AmdGpu::DataFormat::Format10_11_11: + color.float32[0] = NumberUtils::Uf11ToF32(c0 & 0x7ff); + color.float32[1] = NumberUtils::Uf11ToF32((c0 >> 11) & 0x7ff); + color.float32[2] = NumberUtils::Uf10ToF32((c0 >> 22) & 0x3ff); + break; + case AmdGpu::DataFormat::Format11_11_10: + color.float32[0] = NumberUtils::Uf10ToF32(c0 & 0x3ff); + color.float32[1] = NumberUtils::Uf11ToF32((c0 >> 10) & 0x7ff); + color.float32[2] = NumberUtils::Uf11ToF32((c0 >> 21) & 0x7ff); + break; + case AmdGpu::DataFormat::Format5_9_9_9: { + int exponent; + union { + float f; + u32 u; + } scale; + + exponent = (c0 >> 27) - 10; + scale.u = (exponent + 127) << 23; + + color.float32[0] = (c0 & 0x1ff) * scale.f; + color.float32[1] = ((c0 >> 9) & 0x1ff) * scale.f; + color.float32[2] = ((c0 >> 18) & 0x1ff) * scale.f; break; } + case AmdGpu::DataFormat::Format10_10_10_2: + switch (number_type) { + case AmdGpu::NumberFormat::Unorm: + color.float32[0] = NumberUtils::U2ToUnorm(c0 & 0x3); + color.float32[1] = NumberUtils::U10ToUnorm((c0 >> 2) & 0x3ff); + color.float32[2] = NumberUtils::U10ToUnorm((c0 >> 12) & 0x3ff); + color.float32[3] = NumberUtils::U10ToUnorm(c0 >> 22); + break; + case AmdGpu::NumberFormat::Snorm: + case AmdGpu::NumberFormat::SnormNz: + color.float32[0] = NumberUtils::S2ToSnorm(c0 & 0x3); + color.float32[1] = NumberUtils::S10ToSnorm((c0 >> 2) & 0x3ff); + color.float32[2] = NumberUtils::S10ToSnorm((c0 >> 12) & 0x3ff); + color.float32[3] = NumberUtils::S2ToSnorm(c0 >> 22); + break; + case AmdGpu::NumberFormat::Uint: + case AmdGpu::NumberFormat::Sint: + color.uint32[0] = c0 & 0x3; + color.uint32[1] = (c0 >> 2) & 0x3ff; + color.uint32[2] = (c0 >> 12) & 0x3ff; + color.uint32[3] = c0 >> 22; + break; + default: + INVALID_NUMBER_FORMAT_COMBO; + break; + } + break; + case AmdGpu::DataFormat::Format2_10_10_10: + switch (number_type) { + case AmdGpu::NumberFormat::Unorm: + color.float32[0] = NumberUtils::U10ToUnorm(c0 & 0x3ff); + color.float32[1] = NumberUtils::U10ToUnorm((c0 >> 10) & 0x3ff); + color.float32[2] = NumberUtils::U10ToUnorm((c0 >> 20) & 0x3ff); + color.float32[3] = NumberUtils::U2ToUnorm(c0 >> 30); + break; + case AmdGpu::NumberFormat::Snorm: + case AmdGpu::NumberFormat::SnormNz: + color.float32[0] = NumberUtils::S10ToSnorm(c0 & 0x3ff); + color.float32[1] = NumberUtils::S10ToSnorm((c0 >> 10) & 0x3ff); + color.float32[2] = NumberUtils::S10ToSnorm((c0 >> 20) & 0x3ff); + color.float32[3] = NumberUtils::S2ToSnorm(c0 >> 30); + break; + case AmdGpu::NumberFormat::Uint: + case AmdGpu::NumberFormat::Sint: + color.uint32[0] = c0 & 0x3ff; + color.uint32[1] = (c0 >> 10) & 0x3ff; + color.uint32[2] = (c0 >> 20) & 0x3ff; + color.uint32[3] = c0 >> 30; + break; + default: + INVALID_NUMBER_FORMAT_COMBO; + break; + } + break; + case AmdGpu::DataFormat::Format8_8_8_8: + switch (number_type) { + case AmdGpu::NumberFormat::Unorm: + case AmdGpu::NumberFormat::Srgb: // Should we handle gamma correction here? + color.float32[0] = NumberUtils::U8ToUnorm(c0 & 0xff); + color.float32[1] = NumberUtils::U8ToUnorm((c0 >> 8) & 0xff); + color.float32[2] = NumberUtils::U8ToUnorm((c0 >> 16) & 0xff); + color.float32[3] = NumberUtils::U8ToUnorm(c0 >> 24); + break; + case AmdGpu::NumberFormat::Snorm: + case AmdGpu::NumberFormat::SnormNz: + color.float32[0] = NumberUtils::S8ToSnorm(c0 & 0xff); + color.float32[1] = NumberUtils::S8ToSnorm((c0 >> 8) & 0xff); + color.float32[2] = NumberUtils::S8ToSnorm((c0 >> 16) & 0xff); + color.float32[3] = NumberUtils::S8ToSnorm(c0 >> 24); + break; + case AmdGpu::NumberFormat::Uint: + case AmdGpu::NumberFormat::Sint: + color.uint32[0] = c0 & 0xff; + color.uint32[1] = (c0 >> 8) & 0xff; + color.uint32[2] = (c0 >> 16) & 0xff; + color.uint32[3] = c0 >> 24; + break; + default: + INVALID_NUMBER_FORMAT_COMBO; + break; + } + break; + case AmdGpu::DataFormat::Format32_32: + switch (number_type) { + case AmdGpu::NumberFormat::Uint: + case AmdGpu::NumberFormat::Sint: + color.uint32[0] = c0; + color.uint32[1] = c1; + break; + case AmdGpu::NumberFormat::Float: + color.float32[0] = *(reinterpret_cast(&c0)); + color.float32[1] = *(reinterpret_cast(&c1)); + break; + default: + INVALID_NUMBER_FORMAT_COMBO; + break; + } + break; + case AmdGpu::DataFormat::Format16_16_16_16: + switch (number_type) { + case AmdGpu::NumberFormat::Unorm: + color.float32[0] = NumberUtils::U16ToUnorm(c0 & 0xffff); + color.float32[1] = NumberUtils::U16ToUnorm((c0 >> 16) & 0xffff); + color.float32[2] = NumberUtils::U16ToUnorm(c1 & 0xffff); + color.float32[3] = NumberUtils::U16ToUnorm((c1 >> 16) & 0xffff); + break; + case AmdGpu::NumberFormat::Snorm: + case AmdGpu::NumberFormat::SnormNz: + color.float32[0] = NumberUtils::S16ToSnorm(c0 & 0xffff); + color.float32[1] = NumberUtils::S16ToSnorm((c0 >> 16) & 0xffff); + color.float32[2] = NumberUtils::S16ToSnorm(c1 & 0xffff); + color.float32[3] = NumberUtils::S16ToSnorm((c1 >> 16) & 0xffff); + break; + case AmdGpu::NumberFormat::Uint: + case AmdGpu::NumberFormat::Sint: + color.uint32[0] = c0 & 0xffff; + color.uint32[1] = (c0 >> 16) & 0xffff; + color.uint32[2] = c1 & 0xffff; + color.uint32[3] = (c1 >> 16) & 0xffff; + break; + case AmdGpu::NumberFormat::Float: + color.float32[0] = NumberUtils::Uf16ToF32(c0 & 0xffff); + color.float32[1] = NumberUtils::Uf16ToF32((c0 >> 16) & 0xffff); + color.float32[2] = NumberUtils::Uf16ToF32(c1 & 0xffff); + color.float32[3] = NumberUtils::Uf16ToF32((c1 >> 16) & 0xffff); + break; + default: + INVALID_NUMBER_FORMAT_COMBO; + break; + } + break; + case AmdGpu::DataFormat::Format32_32_32_32: + switch (number_type) { + case AmdGpu::NumberFormat::Uint: + case AmdGpu::NumberFormat::Sint: + color.uint32[0] = c0; + color.uint32[1] = c0; + color.uint32[2] = c0; + color.uint32[3] = c1; + break; + case AmdGpu::NumberFormat::Float: + color.float32[0] = *(reinterpret_cast(&c0)); + color.float32[1] = *(reinterpret_cast(&c0)); + color.float32[2] = *(reinterpret_cast(&c0)); + color.float32[3] = *(reinterpret_cast(&c1)); + break; + default: + INVALID_NUMBER_FORMAT_COMBO; + break; + } + break; + case AmdGpu::DataFormat::Format5_6_5: + color.float32[0] = NumberUtils::U5ToUnorm(c0 & 0x1f); + color.float32[1] = NumberUtils::U6ToUnorm((c0 >> 5) & 0x3f); + color.float32[2] = NumberUtils::U5ToUnorm(c0 >> 11); + break; + case AmdGpu::DataFormat::Format1_5_5_5: + color.float32[0] = NumberUtils::U5ToUnorm(c0 & 0x1f); + color.float32[1] = NumberUtils::U5ToUnorm((c0 >> 5) & 0x1f); + color.float32[2] = NumberUtils::U5ToUnorm((c0 >> 10) & 0x1f); + color.float32[3] = (c0 >> 15) ? 1.0f : 0.0f; + break; + case AmdGpu::DataFormat::Format5_5_5_1: + color.float32[0] = (c0 & 0x1) ? 1.0f : 0.0f; + color.float32[1] = NumberUtils::U5ToUnorm((c0 >> 1) & 0x1f); + color.float32[2] = NumberUtils::U5ToUnorm((c0 >> 6) & 0x1f); + color.float32[3] = NumberUtils::U5ToUnorm((c0 >> 11) & 0x1f); + break; + case AmdGpu::DataFormat::Format4_4_4_4: + color.float32[0] = NumberUtils::U4ToUnorm(c0 & 0xf); + color.float32[1] = NumberUtils::U4ToUnorm((c0 >> 4) & 0xf); + color.float32[2] = NumberUtils::U4ToUnorm((c0 >> 8) & 0xf); + color.float32[3] = NumberUtils::U4ToUnorm(c0 >> 12); + break; + default: + LOG_ERROR(Render_Vulkan, "Unsupported color buffer format: {}", format); + break; } + + if (num_components == 1) { + if (comp_swap != Liverpool::ColorBuffer::SwapMode::Standard) { + color.float32[static_cast(comp_swap)] = color.float32[0]; + color.float32[0] = 0.0f; + } + } else { + if (comp_swap_alt && num_components == 4) { + std::swap(color.float32[0], color.float32[2]); + } + + if (comp_swap_reverse) { + std::reverse(std::begin(color.float32), std::begin(color.float32) + num_components); + } + + if (comp_swap_alt && num_components != 4) { + color.float32[3] = color.float32[num_components - 1]; + color.float32[num_components - 1] = 0.0f; + } + } + return {.color = color}; }