Vulkan: Add FLOAT to SRGB and Depth24 Conversion
This PR adds support to convert host/device data from floats to GPU_SRGB8_A8 and GPU_DEPTH_COMPONENT24. Pull Request: https://projects.blender.org/blender/blender/pulls/107544
This commit is contained in:
@@ -262,13 +262,11 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R11F_G11F_B10F()
|
||||
GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R11F_G11F_B10F);
|
||||
#endif
|
||||
|
||||
#if RUN_SRGB_UNIMPLEMENTED
|
||||
static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8()
|
||||
{
|
||||
texture_create_upload_read_with_bias<GPU_SRGB8_A8, GPU_DATA_FLOAT>(0.0f);
|
||||
texture_create_upload_read_with_bias<GPU_SRGB8_A8, GPU_DATA_FLOAT>(0.003f);
|
||||
}
|
||||
GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8);
|
||||
#endif
|
||||
|
||||
static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_SNORM()
|
||||
{
|
||||
@@ -405,13 +403,13 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT32F()
|
||||
GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT32F);
|
||||
#endif
|
||||
|
||||
#if RUN_COMPONENT_UNIMPLEMENTED
|
||||
static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT24()
|
||||
{
|
||||
texture_create_upload_read_with_bias<GPU_DEPTH_COMPONENT24, GPU_DATA_FLOAT>(0.0f);
|
||||
texture_create_upload_read_with_bias<GPU_DEPTH_COMPONENT24, GPU_DATA_FLOAT>(0.0000001f);
|
||||
}
|
||||
GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT24);
|
||||
|
||||
#if RUN_COMPONENT_UNIMPLEMENTED
|
||||
static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT16()
|
||||
{
|
||||
texture_create_upload_read_with_bias<GPU_DEPTH_COMPONENT16, GPU_DATA_FLOAT>(0.0f);
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "vk_data_conversion.hh"
|
||||
|
||||
#include "BLI_color.hh"
|
||||
|
||||
#include "Imath/half.h"
|
||||
|
||||
namespace blender::gpu {
|
||||
@@ -47,6 +49,12 @@ enum class ConversionType {
|
||||
HALF_TO_FLOAT,
|
||||
FLOAT_TO_HALF,
|
||||
|
||||
FLOAT_TO_SRGBA8,
|
||||
SRGBA8_TO_FLOAT,
|
||||
|
||||
FLOAT_TO_DEPTH_COMPONENT24,
|
||||
DEPTH_COMPONENT24_TO_FLOAT,
|
||||
|
||||
/**
|
||||
* The requested conversion isn't supported.
|
||||
*/
|
||||
@@ -90,6 +98,12 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format)
|
||||
case GPU_R16_SNORM:
|
||||
return ConversionType::FLOAT_TO_SNORM16;
|
||||
|
||||
case GPU_SRGB8_A8:
|
||||
return ConversionType::FLOAT_TO_SRGBA8;
|
||||
|
||||
case GPU_DEPTH_COMPONENT24:
|
||||
return ConversionType::FLOAT_TO_DEPTH_COMPONENT24;
|
||||
|
||||
case GPU_RGB32F: /* GPU_RGB32F Not supported by vendors. */
|
||||
case GPU_RGBA8UI:
|
||||
case GPU_RGBA8I:
|
||||
@@ -114,7 +128,6 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format)
|
||||
case GPU_R11F_G11F_B10F:
|
||||
case GPU_DEPTH32F_STENCIL8:
|
||||
case GPU_DEPTH24_STENCIL8:
|
||||
case GPU_SRGB8_A8:
|
||||
case GPU_RGB8UI:
|
||||
case GPU_RGB8I:
|
||||
case GPU_RGB8:
|
||||
@@ -131,7 +144,6 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format)
|
||||
case GPU_RGBA8_DXT5:
|
||||
case GPU_SRGB8:
|
||||
case GPU_RGB9_E5:
|
||||
case GPU_DEPTH_COMPONENT24:
|
||||
case GPU_DEPTH_COMPONENT16:
|
||||
return ConversionType::UNSUPPORTED;
|
||||
}
|
||||
@@ -512,6 +524,8 @@ static ConversionType reversed(ConversionType type)
|
||||
CASE_PAIR(UI32, UI8)
|
||||
CASE_PAIR(I32, I8)
|
||||
CASE_PAIR(FLOAT, HALF)
|
||||
CASE_PAIR(FLOAT, SRGBA8)
|
||||
CASE_PAIR(FLOAT, DEPTH_COMPONENT24)
|
||||
|
||||
case ConversionType::UNSUPPORTED:
|
||||
return ConversionType::UNSUPPORTED;
|
||||
@@ -529,6 +543,44 @@ static ConversionType reversed(ConversionType type)
|
||||
/** \name Data Conversion
|
||||
* \{ */
|
||||
|
||||
template<typename InnerType> struct ComponentValue {
|
||||
InnerType value;
|
||||
};
|
||||
template<typename InnerType> struct PixelValue {
|
||||
InnerType value;
|
||||
};
|
||||
|
||||
using UI8 = ComponentValue<uint8_t>;
|
||||
using UI16 = ComponentValue<uint16_t>;
|
||||
using UI32 = ComponentValue<uint32_t>;
|
||||
using I8 = ComponentValue<int8_t>;
|
||||
using I16 = ComponentValue<int16_t>;
|
||||
using I32 = ComponentValue<int32_t>;
|
||||
using F32 = ComponentValue<float>;
|
||||
using F16 = ComponentValue<uint16_t>;
|
||||
using SRGBA8 = PixelValue<ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>>;
|
||||
using FLOAT4 = PixelValue<ColorSceneLinear4f<eAlpha::Premultiplied>>;
|
||||
|
||||
class DepthComponent24 : public ComponentValue<uint32_t> {
|
||||
public:
|
||||
operator uint32_t() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
DepthComponent24 &operator=(uint32_t new_value)
|
||||
{
|
||||
value = new_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Depth component24 are 4 bytes, but 1 isn't used. */
|
||||
static constexpr size_t used_byte_size()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename InnerType> struct SignedNormalized {
|
||||
static_assert(std::is_same<InnerType, uint8_t>() || std::is_same<InnerType, uint16_t>());
|
||||
InnerType value;
|
||||
@@ -550,35 +602,33 @@ template<typename InnerType> struct SignedNormalized {
|
||||
};
|
||||
|
||||
template<typename InnerType> struct UnsignedNormalized {
|
||||
static_assert(std::is_same<InnerType, uint8_t>() || std::is_same<InnerType, uint16_t>());
|
||||
static_assert(std::is_same<InnerType, uint8_t>() || std::is_same<InnerType, uint16_t>() ||
|
||||
std::is_same<InnerType, DepthComponent24>());
|
||||
InnerType value;
|
||||
|
||||
static constexpr size_t used_byte_size()
|
||||
{
|
||||
if constexpr (std::is_same<InnerType, DepthComponent24>()) {
|
||||
return InnerType::used_byte_size();
|
||||
}
|
||||
else {
|
||||
return sizeof(InnerType);
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr int32_t scalar()
|
||||
{
|
||||
return (1 << (sizeof(InnerType) * 8)) - 1;
|
||||
|
||||
return (1 << (used_byte_size() * 8)) - 1;
|
||||
}
|
||||
|
||||
static constexpr int32_t max()
|
||||
{
|
||||
return ((1 << (sizeof(InnerType) * 8)) - 1);
|
||||
return ((1 << (used_byte_size() * 8)) - 1);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename InnerType> struct ComponentValue {
|
||||
InnerType value;
|
||||
};
|
||||
|
||||
using UI8 = ComponentValue<uint8_t>;
|
||||
using UI16 = ComponentValue<uint16_t>;
|
||||
using UI32 = ComponentValue<uint32_t>;
|
||||
using I8 = ComponentValue<int8_t>;
|
||||
using I16 = ComponentValue<int16_t>;
|
||||
using I32 = ComponentValue<int32_t>;
|
||||
using F32 = ComponentValue<float>;
|
||||
using F16 = ComponentValue<uint16_t>;
|
||||
|
||||
template<typename StorageType>
|
||||
void convert_component(SignedNormalized<StorageType> &dst, const F32 &src)
|
||||
template<typename StorageType> void convert(SignedNormalized<StorageType> &dst, const F32 &src)
|
||||
{
|
||||
static constexpr int32_t scalar = SignedNormalized<StorageType>::scalar();
|
||||
static constexpr int32_t delta = SignedNormalized<StorageType>::delta();
|
||||
@@ -586,32 +636,29 @@ void convert_component(SignedNormalized<StorageType> &dst, const F32 &src)
|
||||
dst.value = (clamp_i((src.value * scalar + delta), 0, max));
|
||||
}
|
||||
|
||||
template<typename StorageType>
|
||||
void convert_component(F32 &dst, const SignedNormalized<StorageType> &src)
|
||||
template<typename StorageType> void convert(F32 &dst, const SignedNormalized<StorageType> &src)
|
||||
{
|
||||
static constexpr int32_t scalar = SignedNormalized<StorageType>::scalar();
|
||||
static constexpr int32_t delta = SignedNormalized<StorageType>::delta();
|
||||
dst.value = float(int32_t(src.value) - delta) / scalar;
|
||||
}
|
||||
|
||||
template<typename StorageType>
|
||||
void convert_component(UnsignedNormalized<StorageType> &dst, const F32 &src)
|
||||
template<typename StorageType> void convert(UnsignedNormalized<StorageType> &dst, const F32 &src)
|
||||
{
|
||||
static constexpr int32_t scalar = UnsignedNormalized<StorageType>::scalar();
|
||||
static constexpr int32_t max = scalar;
|
||||
dst.value = (clamp_i((src.value * scalar), 0, max));
|
||||
}
|
||||
|
||||
template<typename StorageType>
|
||||
void convert_component(F32 &dst, const UnsignedNormalized<StorageType> &src)
|
||||
template<typename StorageType> void convert(F32 &dst, const UnsignedNormalized<StorageType> &src)
|
||||
{
|
||||
static constexpr int32_t scalar = UnsignedNormalized<StorageType>::scalar();
|
||||
dst.value = float(src.value) / scalar;
|
||||
dst.value = float(int32_t(src.value)) / scalar;
|
||||
}
|
||||
|
||||
/* Copy the contents of src to dst with out performing any actual conversion. */
|
||||
template<typename DestinationType, typename SourceType>
|
||||
void convert_component(DestinationType &dst, const SourceType &src)
|
||||
void convert(DestinationType &dst, const SourceType &src)
|
||||
{
|
||||
static_assert(std::is_same<DestinationType, UI8>() || std::is_same<DestinationType, UI16>() ||
|
||||
std::is_same<DestinationType, UI32>() || std::is_same<DestinationType, I8>() ||
|
||||
@@ -623,24 +670,34 @@ void convert_component(DestinationType &dst, const SourceType &src)
|
||||
dst.value = src.value;
|
||||
}
|
||||
|
||||
static void convert_component(F16 &dst, const F32 &src)
|
||||
static void convert(F16 &dst, const F32 &src)
|
||||
{
|
||||
dst.value = imath_float_to_half(src.value);
|
||||
}
|
||||
|
||||
static void convert_component(F32 &dst, const F16 &src)
|
||||
static void convert(F32 &dst, const F16 &src)
|
||||
{
|
||||
dst.value = imath_half_to_float(src.value);
|
||||
}
|
||||
|
||||
static void convert(SRGBA8 &dst, const FLOAT4 &src)
|
||||
{
|
||||
dst.value = src.value.encode();
|
||||
}
|
||||
|
||||
static void convert(FLOAT4 &dst, const SRGBA8 &src)
|
||||
{
|
||||
dst.value = src.value.decode();
|
||||
}
|
||||
|
||||
/* \} */
|
||||
|
||||
template<typename DestinationType, typename SourceType>
|
||||
void convert_per_component(MutableSpan<DestinationType> dst, Span<SourceType> src)
|
||||
void convert(MutableSpan<DestinationType> dst, Span<SourceType> src)
|
||||
{
|
||||
BLI_assert(src.size() == dst.size());
|
||||
for (int64_t index : IndexRange(src.size())) {
|
||||
convert_component(dst[index], src[index]);
|
||||
convert(dst[index], src[index]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,7 +712,17 @@ void convert_per_component(void *dst_memory,
|
||||
total_components);
|
||||
MutableSpan<DestinationType> dst = MutableSpan<DestinationType>(
|
||||
static_cast<DestinationType *>(dst_memory), total_components);
|
||||
convert_per_component<DestinationType, SourceType>(dst, src);
|
||||
convert<DestinationType, SourceType>(dst, src);
|
||||
}
|
||||
|
||||
template<typename DestinationType, typename SourceType>
|
||||
void convert_per_pixel(void *dst_memory, const void *src_memory, size_t buffer_size)
|
||||
{
|
||||
Span<SourceType> src = Span<SourceType>(static_cast<const SourceType *>(src_memory),
|
||||
buffer_size);
|
||||
MutableSpan<DestinationType> dst = MutableSpan<DestinationType>(
|
||||
static_cast<DestinationType *>(dst_memory), buffer_size);
|
||||
convert<DestinationType, SourceType>(dst, src);
|
||||
}
|
||||
|
||||
static void convert_buffer(void *dst_memory,
|
||||
@@ -746,6 +813,22 @@ static void convert_buffer(void *dst_memory,
|
||||
case ConversionType::HALF_TO_FLOAT:
|
||||
convert_per_component<F32, F16>(dst_memory, src_memory, buffer_size, device_format);
|
||||
break;
|
||||
|
||||
case ConversionType::FLOAT_TO_SRGBA8:
|
||||
convert_per_pixel<SRGBA8, FLOAT4>(dst_memory, src_memory, buffer_size);
|
||||
break;
|
||||
case ConversionType::SRGBA8_TO_FLOAT:
|
||||
convert_per_pixel<FLOAT4, SRGBA8>(dst_memory, src_memory, buffer_size);
|
||||
break;
|
||||
|
||||
case ConversionType::FLOAT_TO_DEPTH_COMPONENT24:
|
||||
convert_per_component<UnsignedNormalized<DepthComponent24>, F32>(
|
||||
dst_memory, src_memory, buffer_size, device_format);
|
||||
break;
|
||||
case ConversionType::DEPTH_COMPONENT24_TO_FLOAT:
|
||||
convert_per_component<F32, UnsignedNormalized<DepthComponent24>>(
|
||||
dst_memory, src_memory, buffer_size, device_format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user