WIP: Vulkan: Workbench #107886
|
@ -863,6 +863,7 @@ if(WITH_GTESTS)
|
||||||
if(WITH_VULKAN_BACKEND)
|
if(WITH_VULKAN_BACKEND)
|
||||||
list(APPEND TEST_SRC
|
list(APPEND TEST_SRC
|
||||||
tests/memory_layout_test.cc
|
tests/memory_layout_test.cc
|
||||||
|
vulkan/vk_data_conversion_test.cc
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -259,7 +259,7 @@ GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB10_A2UI);
|
||||||
|
|
||||||
static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R11F_G11F_B10F()
|
static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R11F_G11F_B10F()
|
||||||
{
|
{
|
||||||
texture_create_upload_read_with_bias<GPU_R11F_G11F_B10F, GPU_DATA_FLOAT>(0.0f);
|
texture_create_upload_read_with_bias<GPU_R11F_G11F_B10F, GPU_DATA_FLOAT>(0.0009);
|
||||||
}
|
}
|
||||||
GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R11F_G11F_B10F);
|
GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R11F_G11F_B10F);
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,8 @@ enum class ConversionType {
|
||||||
FLOAT_TO_DEPTH_COMPONENT24,
|
FLOAT_TO_DEPTH_COMPONENT24,
|
||||||
DEPTH_COMPONENT24_TO_FLOAT,
|
DEPTH_COMPONENT24_TO_FLOAT,
|
||||||
|
|
||||||
FLOAT_TO_R11F_G11F_B10F,
|
FLOAT_TO_B10F_G11F_R11F,
|
||||||
R11F_G11F_B10F_TO_FLOAT,
|
B10F_G11F_R11F_TO_FLOAT,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The requested conversion isn't supported.
|
* The requested conversion isn't supported.
|
||||||
|
@ -108,7 +108,7 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format)
|
||||||
return ConversionType::FLOAT_TO_DEPTH_COMPONENT24;
|
return ConversionType::FLOAT_TO_DEPTH_COMPONENT24;
|
||||||
|
|
||||||
case GPU_R11F_G11F_B10F:
|
case GPU_R11F_G11F_B10F:
|
||||||
return ConversionType::FLOAT_TO_R11F_G11F_B10F;
|
return ConversionType::FLOAT_TO_B10F_G11F_R11F;
|
||||||
|
|
||||||
case GPU_RGB32F: /* GPU_RGB32F Not supported by vendors. */
|
case GPU_RGB32F: /* GPU_RGB32F Not supported by vendors. */
|
||||||
case GPU_RGBA8UI:
|
case GPU_RGBA8UI:
|
||||||
|
@ -531,7 +531,7 @@ static ConversionType reversed(ConversionType type)
|
||||||
CASE_PAIR(FLOAT, HALF)
|
CASE_PAIR(FLOAT, HALF)
|
||||||
CASE_PAIR(FLOAT, SRGBA8)
|
CASE_PAIR(FLOAT, SRGBA8)
|
||||||
CASE_PAIR(FLOAT, DEPTH_COMPONENT24)
|
CASE_PAIR(FLOAT, DEPTH_COMPONENT24)
|
||||||
CASE_PAIR(FLOAT, R11F_G11F_B10F)
|
CASE_PAIR(FLOAT, B10F_G11F_R11F)
|
||||||
|
|
||||||
case ConversionType::UNSUPPORTED:
|
case ConversionType::UNSUPPORTED:
|
||||||
return ConversionType::UNSUPPORTED;
|
return ConversionType::UNSUPPORTED;
|
||||||
|
@ -565,8 +565,10 @@ using I32 = ComponentValue<int32_t>;
|
||||||
using F32 = ComponentValue<float>;
|
using F32 = ComponentValue<float>;
|
||||||
using F16 = ComponentValue<uint16_t>;
|
using F16 = ComponentValue<uint16_t>;
|
||||||
using SRGBA8 = PixelValue<ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>>;
|
using SRGBA8 = PixelValue<ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>>;
|
||||||
|
using FLOAT3 = PixelValue<float3>;
|
||||||
using FLOAT4 = PixelValue<ColorSceneLinear4f<eAlpha::Premultiplied>>;
|
using FLOAT4 = PixelValue<ColorSceneLinear4f<eAlpha::Premultiplied>>;
|
||||||
class R11F_G11F_B10F : public PixelValue<uint32_t> {};
|
/* NOTE: Vulkan stores R11_G11_B10 in reverse component order. */
|
||||||
|
class B10F_G11G_R11F : public PixelValue<uint32_t> {};
|
||||||
|
|
||||||
class DepthComponent24 : public ComponentValue<uint32_t> {
|
class DepthComponent24 : public ComponentValue<uint32_t> {
|
||||||
public:
|
public:
|
||||||
|
@ -697,21 +699,48 @@ static void convert(FLOAT4 &dst, const SRGBA8 &src)
|
||||||
dst.value = src.value.decode();
|
dst.value = src.value.decode();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: These still have to be validated.
|
constexpr uint32_t MASK_10_BITS = 0b1111111111;
|
||||||
static void convert(FLOAT4 &dst, const R11F_G11F_B10F &src)
|
constexpr uint32_t MASK_11_BITS = 0b11111111111;
|
||||||
|
constexpr uint8_t SHIFT_B = 22;
|
||||||
|
constexpr uint8_t SHIFT_G = 11;
|
||||||
|
constexpr uint8_t SHIFT_R = 0;
|
||||||
|
|
||||||
|
static uint32_t float_to_uint32_t(float value)
|
||||||
{
|
{
|
||||||
dst.value.r = float((src.value >> 21) & 0b11111111111) / (0b11111111111);
|
union {
|
||||||
dst.value.g = float((src.value >> 10) & 0b11111111111) / float(0b11111111111);
|
float fl;
|
||||||
dst.value.b = float((src.value) & 0b1111111111) / float(0b1111111111);
|
uint32_t u;
|
||||||
dst.value.a = 1.0f;
|
} float_to_bits;
|
||||||
|
float_to_bits.fl = value;
|
||||||
|
return float_to_bits.u;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void convert(R11F_G11F_B10F &dst, const FLOAT4 &src)
|
static float uint32_t_to_float(uint32_t value)
|
||||||
{
|
{
|
||||||
int32_t r = clamp_f(src.value.r, 0.0f, 1.0f) * 0b11111111111;
|
union {
|
||||||
int32_t g = clamp_f(src.value.g, 0.0f, 1.0f) * 0b11111111111;
|
float fl;
|
||||||
int32_t b = clamp_f(src.value.b, 0.0f, 1.0f) * 0b1111111111;
|
uint32_t u;
|
||||||
dst.value = r << 21 | g << 10 | b;
|
} float_to_bits;
|
||||||
|
float_to_bits.u = value;
|
||||||
|
return float_to_bits.fl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convert(FLOAT3 &dst, const B10F_G11G_R11F &src)
|
||||||
|
{
|
||||||
|
dst.value.x = uint32_t_to_float(
|
||||||
|
convert_float_formats<Format32F, Format11F>((src.value >> SHIFT_R) && MASK_11_BITS));
|
||||||
|
dst.value.y = uint32_t_to_float(
|
||||||
|
convert_float_formats<Format32F, Format11F>((src.value >> SHIFT_G) && MASK_11_BITS));
|
||||||
|
dst.value.z = uint32_t_to_float(
|
||||||
|
convert_float_formats<Format32F, Format11F>((src.value >> SHIFT_B) && MASK_10_BITS));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convert(B10F_G11G_R11F &dst, const FLOAT3 &src)
|
||||||
|
{
|
||||||
|
uint32_t r = convert_float_formats<Format11F, Format32F>(float_to_uint32_t(src.value.x));
|
||||||
|
uint32_t g = convert_float_formats<Format11F, Format32F>(float_to_uint32_t(src.value.y));
|
||||||
|
uint32_t b = convert_float_formats<Format10F, Format32F>(float_to_uint32_t(src.value.z));
|
||||||
|
dst.value = r << SHIFT_R | g << SHIFT_G | b << SHIFT_B;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* \} */
|
/* \} */
|
||||||
|
@ -854,12 +883,12 @@ static void convert_buffer(void *dst_memory,
|
||||||
dst_memory, src_memory, buffer_size, device_format);
|
dst_memory, src_memory, buffer_size, device_format);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ConversionType::FLOAT_TO_R11F_G11F_B10F:
|
case ConversionType::FLOAT_TO_B10F_G11F_R11F:
|
||||||
convert_per_pixel<R11F_G11F_B10F, FLOAT4>(dst_memory, src_memory, buffer_size);
|
convert_per_pixel<B10F_G11G_R11F, FLOAT3>(dst_memory, src_memory, buffer_size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ConversionType::R11F_G11F_B10F_TO_FLOAT:
|
case ConversionType::B10F_G11F_R11F_TO_FLOAT:
|
||||||
convert_per_pixel<FLOAT4, R11F_G11F_B10F>(dst_memory, src_memory, buffer_size);
|
convert_per_pixel<FLOAT3, B10F_G11G_R11F>(dst_memory, src_memory, buffer_size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,4 +96,141 @@ bool conversion_needed(const GPUVertFormat &vertex_format);
|
||||||
*/
|
*/
|
||||||
void convert_in_place(void *data, const GPUVertFormat &vertex_format, const uint vertex_len);
|
void convert_in_place(void *data, const GPUVertFormat &vertex_format, const uint vertex_len);
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Floating point conversions
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
template<bool HasSignBit, uint8_t MantissaBitLen, uint8_t ExponentBitLen>
|
||||||
|
class FloatingPointFormat {
|
||||||
|
public:
|
||||||
|
static constexpr bool HasSign = HasSignBit;
|
||||||
|
static constexpr uint8_t MantissaLen = MantissaBitLen;
|
||||||
|
static constexpr uint8_t MantissaShift = 0;
|
||||||
|
static constexpr uint32_t MantissaMask = (1 << MantissaBitLen) - 1;
|
||||||
|
static constexpr uint8_t ExponentShift = MantissaBitLen;
|
||||||
|
static constexpr uint8_t ExponentLen = ExponentBitLen;
|
||||||
|
static constexpr uint32_t ExponentMask = (1 << ExponentBitLen) - 1;
|
||||||
|
static constexpr uint8_t SignShift = MantissaBitLen + ExponentBitLen;
|
||||||
|
static constexpr uint32_t SignMask = HasSignBit ? 1 : 0;
|
||||||
|
static constexpr uint32_t ExponentBias = (1 << (ExponentBitLen - 1)) - 1;
|
||||||
|
|
||||||
|
uint32_t get_mantissa(uint32_t floating_point_number)
|
||||||
|
{
|
||||||
|
return (floating_point_number >> MantissaShift) & MantissaMask;
|
||||||
|
}
|
||||||
|
uint32_t clear_mantissa(uint32_t floating_point_number)
|
||||||
|
{
|
||||||
|
return floating_point_number & ~(MantissaMask << MantissaShift);
|
||||||
|
}
|
||||||
|
uint32_t set_mantissa(uint32_t mantissa, uint32_t floating_point_number)
|
||||||
|
{
|
||||||
|
uint32_t result = clear_mantissa(floating_point_number);
|
||||||
|
result |= mantissa << MantissaShift;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t get_exponent(uint32_t floating_point_number)
|
||||||
|
{
|
||||||
|
return ((floating_point_number >> ExponentShift) & ExponentMask);
|
||||||
|
}
|
||||||
|
uint32_t clear_exponent(uint32_t floating_point_number)
|
||||||
|
{
|
||||||
|
return floating_point_number & ~(ExponentMask << ExponentShift);
|
||||||
|
}
|
||||||
|
uint32_t set_exponent(uint32_t exponent, uint32_t floating_point_number)
|
||||||
|
{
|
||||||
|
uint32_t result = clear_exponent(floating_point_number);
|
||||||
|
result |= (exponent) << ExponentShift;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_signed(uint32_t floating_point_number)
|
||||||
|
{
|
||||||
|
if constexpr (HasSignBit) {
|
||||||
|
return (floating_point_number >> SignShift) & SignMask;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32_t clear_sign(uint32_t floating_point_number)
|
||||||
|
{
|
||||||
|
return floating_point_number & ~(1 << SignShift);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t set_sign(bool sign, uint32_t floating_point_number)
|
||||||
|
{
|
||||||
|
if constexpr (HasSignBit) {
|
||||||
|
return floating_point_number;
|
||||||
|
}
|
||||||
|
uint32_t result = clear_sign(floating_point_number);
|
||||||
|
result |= uint32_t(sign) << SignShift;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using Format32F = FloatingPointFormat<true, 23, 8>;
|
||||||
|
using Format16F = FloatingPointFormat<true, 10, 5>;
|
||||||
|
using Format11F = FloatingPointFormat<false, 6, 5>;
|
||||||
|
using Format10F = FloatingPointFormat<false, 5, 5>;
|
||||||
|
|
||||||
|
template<typename DestinationFormat, typename SourceFormat>
|
||||||
|
uint32_t convert_float_formats(uint32_t value)
|
||||||
|
{
|
||||||
|
SourceFormat src_format;
|
||||||
|
DestinationFormat dst_format;
|
||||||
|
/*
|
||||||
|
printf("Source MS:%d MM:%x ES:%d EM:%x EB:%x\n",
|
||||||
|
SourceFormat::MantissaShift,
|
||||||
|
SourceFormat::MantissaMask,
|
||||||
|
SourceFormat::ExponentShift,
|
||||||
|
SourceFormat::ExponentMask,
|
||||||
|
SourceFormat::ExponentBias);
|
||||||
|
printf("Destination MS:%d MM:%x ES:%d EM:%x EB:%x\n",
|
||||||
|
DestinationFormat::MantissaShift,
|
||||||
|
DestinationFormat::MantissaMask,
|
||||||
|
DestinationFormat::ExponentShift,
|
||||||
|
DestinationFormat::ExponentMask,
|
||||||
|
DestinationFormat::ExponentBias);
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool is_signed = src_format.is_signed(value);
|
||||||
|
uint32_t mantissa = src_format.get_mantissa(value);
|
||||||
|
int32_t exponent = src_format.get_exponent(value);
|
||||||
|
printf("src:%x S:%d, M:%x E:%x\n", value, is_signed, mantissa, exponent);
|
||||||
|
/* Sign conversion */
|
||||||
|
if (is_signed && !DestinationFormat::HasSign) {
|
||||||
|
// NOTE: we clamp to zero.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mantissa conversion */
|
||||||
|
if constexpr (SourceFormat::MantissaLen > DestinationFormat::MantissaLen) {
|
||||||
|
mantissa = mantissa >> (SourceFormat::MantissaLen - DestinationFormat::MantissaLen);
|
||||||
|
}
|
||||||
|
else if constexpr (SourceFormat::MantissaLen < DestinationFormat::MantissaLen) {
|
||||||
|
mantissa = mantissa << (DestinationFormat::MantissaLen - SourceFormat::MantissaLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exponent conversion */
|
||||||
|
const bool is_denormalized = exponent == 0;
|
||||||
|
if (!is_denormalized) {
|
||||||
|
exponent -= SourceFormat::ExponentBias;
|
||||||
|
if constexpr (SourceFormat::ExponentLen > DestinationFormat::ExponentLen) {
|
||||||
|
exponent = exponent >> (SourceFormat::ExponentLen - DestinationFormat::ExponentLen);
|
||||||
|
}
|
||||||
|
else if constexpr (SourceFormat::ExponentLen < DestinationFormat::ExponentLen) {
|
||||||
|
exponent = exponent << (DestinationFormat::ExponentLen - SourceFormat::ExponentLen);
|
||||||
|
}
|
||||||
|
exponent += DestinationFormat::ExponentBias;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t result = 0;
|
||||||
|
result = dst_format.set_sign(is_signed, result);
|
||||||
|
result = dst_format.set_exponent(exponent, result);
|
||||||
|
result = dst_format.set_mantissa(mantissa, result);
|
||||||
|
printf("dst:%x S:%d, M:%x E:%x\n", result, is_signed, mantissa, exponent);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* \} */
|
||||||
|
|
||||||
}; // namespace blender::gpu
|
}; // namespace blender::gpu
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
#include "vk_data_conversion.hh"
|
||||||
|
|
||||||
|
namespace blender::gpu::tests {
|
||||||
|
TEST(VulkanDataConversion, ConvertF32F16)
|
||||||
|
{
|
||||||
|
uint32_t f32_2 = 0b01000000000000000000000000000000;
|
||||||
|
uint32_t f16_2_expected = 0b0100000000000000;
|
||||||
|
uint32_t f16_2 = convert_float_formats<Format16F, Format32F>(f32_2);
|
||||||
|
EXPECT_EQ(f16_2, f16_2_expected);
|
||||||
|
}
|
||||||
|
} // namespace blender::gpu::tests
|
Loading…
Reference in New Issue