From fea1967037744125fb26e4f093cc36fd4691cd8a Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 14 Mar 2023 13:57:33 +0100 Subject: [PATCH 01/15] Add initial data conversion. --- source/blender/gpu/CMakeLists.txt | 2 + .../blender/gpu/vulkan/vk_command_buffer.cc | 13 + .../blender/gpu/vulkan/vk_command_buffer.hh | 7 + .../blender/gpu/vulkan/vk_data_conversion.cc | 416 ++++++++++++++++++ .../blender/gpu/vulkan/vk_data_conversion.hh | 56 +++ source/blender/gpu/vulkan/vk_texture.cc | 73 ++- 6 files changed, 560 insertions(+), 7 deletions(-) create mode 100644 source/blender/gpu/vulkan/vk_data_conversion.cc create mode 100644 source/blender/gpu/vulkan/vk_data_conversion.hh diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 102b1b1a57b..31a85e61ec5 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -195,6 +195,7 @@ set(VULKAN_SRC vulkan/vk_command_buffer.cc vulkan/vk_common.cc vulkan/vk_context.cc + vulkan/vk_data_conversion.cc vulkan/vk_descriptor_pools.cc vulkan/vk_descriptor_set.cc vulkan/vk_drawlist.cc @@ -222,6 +223,7 @@ set(VULKAN_SRC vulkan/vk_command_buffer.hh vulkan/vk_common.hh vulkan/vk_context.hh + vulkan/vk_data_conversion.hh vulkan/vk_descriptor_pools.hh vulkan/vk_descriptor_set.hh vulkan/vk_drawlist.hh diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index b4526df6aba..9a5463bf890 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -98,6 +98,19 @@ void VKCommandBuffer::copy(VKBuffer &dst_buffer, regions.data()); } +void VKCommandBuffer::clear(VkImage vk_image, + VkImageLayout vk_image_layout, + const VkClearColorValue &vk_clear_color, + Span ranges) +{ + vkCmdClearColorImage(vk_command_buffer_, + vk_image, + vk_image_layout, + &vk_clear_color, + ranges.size(), + ranges.data()); +} + void VKCommandBuffer::pipeline_barrier(VkPipelineStageFlags source_stages, VkPipelineStageFlags destination_stages) { diff --git a/source/blender/gpu/vulkan/vk_command_buffer.hh b/source/blender/gpu/vulkan/vk_command_buffer.hh index 0f5f47a423a..0a52c66af52 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.hh +++ b/source/blender/gpu/vulkan/vk_command_buffer.hh @@ -51,6 +51,13 @@ class VKCommandBuffer : NonCopyable, NonMovable { void pipeline_barrier(VkPipelineStageFlags source_stages, VkPipelineStageFlags destination_stages); void pipeline_barrier(Span image_memory_barriers); + /** + * Clear color image resource. + */ + void clear(VkImage vk_image, + VkImageLayout vk_image_layout, + const VkClearColorValue &vk_clear_color, + Span ranges); /** * Stop recording commands, encode + send the recordings to Vulkan, wait for the until the diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc new file mode 100644 index 00000000000..51edfe71628 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -0,0 +1,416 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_data_conversion.hh" + +namespace blender::gpu { +static ConversionType type_of_conversion_float(eGPUTextureFormat device_format) +{ + switch (device_format) { + case GPU_RGBA32F: + case GPU_RG32F: + case GPU_R32F: + case GPU_RGB32F: + case GPU_DEPTH_COMPONENT32F: + return ConversionType::UNMODIFIED; + + case GPU_RGBA16F: + case GPU_RG16F: + case GPU_R16F: + case GPU_RGB16F: + return ConversionType::FLOAT_TO_HALF; + + case GPU_RGBA8UI: + case GPU_RGBA8I: + case GPU_RGBA8: + case GPU_RGBA16UI: + case GPU_RGBA16I: + case GPU_RGBA16: + case GPU_RGBA32UI: + case GPU_RGBA32I: + case GPU_RG8UI: + case GPU_RG8I: + case GPU_RG8: + case GPU_RG16UI: + case GPU_RG16I: + case GPU_RG16: + case GPU_RG32UI: + case GPU_RG32I: + case GPU_R8UI: + case GPU_R8I: + case GPU_R8: + case GPU_R16UI: + case GPU_R16I: + case GPU_R16: + case GPU_R32UI: + case GPU_R32I: + case GPU_RGB10_A2: + case GPU_RGB10_A2UI: + case GPU_R11F_G11F_B10F: + case GPU_DEPTH32F_STENCIL8: + case GPU_DEPTH24_STENCIL8: + case GPU_SRGB8_A8: + case GPU_RGBA8_SNORM: + case GPU_RGBA16_SNORM: + case GPU_RGB8UI: + case GPU_RGB8I: + case GPU_RGB8: + case GPU_RGB8_SNORM: + case GPU_RGB16UI: + case GPU_RGB16I: + case GPU_RGB16: + case GPU_RGB16_SNORM: + case GPU_RGB32UI: + case GPU_RGB32I: + case GPU_RG8_SNORM: + case GPU_RG16_SNORM: + case GPU_R8_SNORM: + case GPU_R16_SNORM: + case GPU_SRGB8_A8_DXT1: + case GPU_SRGB8_A8_DXT3: + case GPU_SRGB8_A8_DXT5: + case GPU_RGBA8_DXT1: + case GPU_RGBA8_DXT3: + case GPU_RGBA8_DXT5: + case GPU_SRGB8: + case GPU_RGB9_E5: + case GPU_DEPTH_COMPONENT24: + case GPU_DEPTH_COMPONENT16: + return ConversionType::UNSUPPORTED; + } + return ConversionType::UNSUPPORTED; +} + +static ConversionType type_of_conversion_int(eGPUTextureFormat device_format) +{ + switch (device_format) { + case GPU_RGBA8UI: + case GPU_RGBA8I: + case GPU_RGBA8: + case GPU_RGBA16UI: + case GPU_RGBA16I: + case GPU_RGBA16F: + case GPU_RGBA16: + case GPU_RGBA32UI: + case GPU_RGBA32I: + case GPU_RGBA32F: + case GPU_RG8UI: + case GPU_RG8I: + case GPU_RG8: + case GPU_RG16UI: + case GPU_RG16I: + case GPU_RG16F: + case GPU_RG16: + case GPU_RG32UI: + case GPU_RG32I: + case GPU_RG32F: + case GPU_R8UI: + case GPU_R8I: + case GPU_R8: + case GPU_R16UI: + case GPU_R16I: + case GPU_R16F: + case GPU_R16: + case GPU_R32UI: + case GPU_R32I: + case GPU_R32F: + case GPU_RGB10_A2: + case GPU_RGB10_A2UI: + case GPU_R11F_G11F_B10F: + case GPU_DEPTH32F_STENCIL8: + case GPU_DEPTH24_STENCIL8: + case GPU_SRGB8_A8: + case GPU_RGBA8_SNORM: + case GPU_RGBA16_SNORM: + case GPU_RGB8UI: + case GPU_RGB8I: + case GPU_RGB8: + case GPU_RGB8_SNORM: + case GPU_RGB16UI: + case GPU_RGB16I: + case GPU_RGB16F: + case GPU_RGB16: + case GPU_RGB16_SNORM: + case GPU_RGB32UI: + case GPU_RGB32I: + case GPU_RGB32F: + case GPU_RG8_SNORM: + case GPU_RG16_SNORM: + case GPU_R8_SNORM: + case GPU_R16_SNORM: + case GPU_SRGB8_A8_DXT1: + case GPU_SRGB8_A8_DXT3: + case GPU_SRGB8_A8_DXT5: + case GPU_RGBA8_DXT1: + case GPU_RGBA8_DXT3: + case GPU_RGBA8_DXT5: + case GPU_SRGB8: + case GPU_RGB9_E5: + case GPU_DEPTH_COMPONENT32F: + case GPU_DEPTH_COMPONENT24: + case GPU_DEPTH_COMPONENT16: + return ConversionType::UNSUPPORTED; + } + return ConversionType::UNSUPPORTED; +} + +static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format) +{ + switch (device_format) { + case GPU_RGBA32UI: + case GPU_RG32UI: + case GPU_R32UI: + case GPU_RGB32UI: + return ConversionType::UNMODIFIED; + + case GPU_RGBA16UI: + case GPU_RG16UI: + case GPU_R16UI: + case GPU_RGB16UI: + return ConversionType::UI32_TO_UI16; + + case GPU_RGBA8UI: + case GPU_RGBA8I: + case GPU_RGBA8: + case GPU_RGBA16I: + case GPU_RGBA16F: + case GPU_RGBA16: + case GPU_RGBA32I: + case GPU_RGBA32F: + case GPU_RG8UI: + case GPU_RG8I: + case GPU_RG8: + case GPU_RG16I: + case GPU_RG16F: + case GPU_RG16: + case GPU_RG32I: + case GPU_RG32F: + case GPU_R8UI: + case GPU_R8I: + case GPU_R8: + case GPU_R16I: + case GPU_R16F: + case GPU_R16: + case GPU_R32I: + case GPU_R32F: + case GPU_RGB10_A2: + case GPU_RGB10_A2UI: + case GPU_R11F_G11F_B10F: + case GPU_DEPTH32F_STENCIL8: + case GPU_DEPTH24_STENCIL8: + case GPU_SRGB8_A8: + case GPU_RGBA8_SNORM: + case GPU_RGBA16_SNORM: + case GPU_RGB8UI: + case GPU_RGB8I: + case GPU_RGB8: + case GPU_RGB8_SNORM: + case GPU_RGB16I: + case GPU_RGB16F: + case GPU_RGB16: + case GPU_RGB16_SNORM: + case GPU_RGB32I: + case GPU_RGB32F: + case GPU_RG8_SNORM: + case GPU_RG16_SNORM: + case GPU_R8_SNORM: + case GPU_R16_SNORM: + case GPU_SRGB8_A8_DXT1: + case GPU_SRGB8_A8_DXT3: + case GPU_SRGB8_A8_DXT5: + case GPU_RGBA8_DXT1: + case GPU_RGBA8_DXT3: + case GPU_RGBA8_DXT5: + case GPU_SRGB8: + case GPU_RGB9_E5: + case GPU_DEPTH_COMPONENT32F: + case GPU_DEPTH_COMPONENT24: + case GPU_DEPTH_COMPONENT16: + return ConversionType::UNSUPPORTED; + } + return ConversionType::UNSUPPORTED; +} + +static ConversionType type_of_conversion_half(eGPUTextureFormat device_format) +{ + switch (device_format) { + case GPU_RGBA8UI: + case GPU_RGBA8I: + case GPU_RGBA8: + case GPU_RGBA16UI: + case GPU_RGBA16I: + case GPU_RGBA16F: + case GPU_RGBA16: + case GPU_RGBA32UI: + case GPU_RGBA32I: + case GPU_RGBA32F: + case GPU_RG8UI: + case GPU_RG8I: + case GPU_RG8: + case GPU_RG16UI: + case GPU_RG16I: + case GPU_RG16F: + case GPU_RG16: + case GPU_RG32UI: + case GPU_RG32I: + case GPU_RG32F: + case GPU_R8UI: + case GPU_R8I: + case GPU_R8: + case GPU_R16UI: + case GPU_R16I: + case GPU_R16F: + case GPU_R16: + case GPU_R32UI: + case GPU_R32I: + case GPU_R32F: + case GPU_RGB10_A2: + case GPU_RGB10_A2UI: + case GPU_R11F_G11F_B10F: + case GPU_DEPTH32F_STENCIL8: + case GPU_DEPTH24_STENCIL8: + case GPU_SRGB8_A8: + case GPU_RGBA8_SNORM: + case GPU_RGBA16_SNORM: + case GPU_RGB8UI: + case GPU_RGB8I: + case GPU_RGB8: + case GPU_RGB8_SNORM: + case GPU_RGB16UI: + case GPU_RGB16I: + case GPU_RGB16F: + case GPU_RGB16: + case GPU_RGB16_SNORM: + case GPU_RGB32UI: + case GPU_RGB32I: + case GPU_RGB32F: + case GPU_RG8_SNORM: + case GPU_RG16_SNORM: + case GPU_R8_SNORM: + case GPU_R16_SNORM: + case GPU_SRGB8_A8_DXT1: + case GPU_SRGB8_A8_DXT3: + case GPU_SRGB8_A8_DXT5: + case GPU_RGBA8_DXT1: + case GPU_RGBA8_DXT3: + case GPU_RGBA8_DXT5: + case GPU_SRGB8: + case GPU_RGB9_E5: + case GPU_DEPTH_COMPONENT32F: + case GPU_DEPTH_COMPONENT24: + case GPU_DEPTH_COMPONENT16: + return ConversionType::UNSUPPORTED; + } + return ConversionType::UNSUPPORTED; +} + +ConversionType conversion_type_for_update(eGPUDataFormat host_format, + eGPUTextureFormat device_format) +{ + BLI_assert(validate_data_format(device_format, host_format)); + + switch (host_format) { + case GPU_DATA_FLOAT: + return type_of_conversion_float(device_format); + case GPU_DATA_UINT: + return type_of_conversion_uint(device_format); + case GPU_DATA_INT: + return type_of_conversion_int(device_format); + case GPU_DATA_HALF_FLOAT: + return type_of_conversion_half(device_format); + + case GPU_DATA_UBYTE: + case GPU_DATA_UINT_24_8: + case GPU_DATA_10_11_11_REV: + case GPU_DATA_2_10_10_10_REV: + return ConversionType::UNSUPPORTED; + } + + return ConversionType::UNSUPPORTED; +} + +static ConversionType invert(ConversionType type) +{ + switch (type) { + case ConversionType::UNMODIFIED: + return ConversionType::UNMODIFIED; + + case ConversionType::UI16_TO_UI32: + return ConversionType::UI32_TO_UI16; + case ConversionType::UI32_TO_UI16: + return ConversionType::UI16_TO_UI32; + + case ConversionType::FLOAT_TO_HALF: + return ConversionType::HALF_TO_FLOAT; + case ConversionType::HALF_TO_FLOAT: + return ConversionType::FLOAT_TO_HALF; + + case ConversionType::UNSUPPORTED: + return ConversionType::UNSUPPORTED; + } + + return ConversionType::UNSUPPORTED; +} + +ConversionType conversion_type_for_read(eGPUDataFormat host_format, + eGPUTextureFormat device_format) +{ + return invert(conversion_type_for_update(host_format, device_format)); +} + +/* Copy the contents of src to dst with out performing any actual conversion. */ +template +void copy_unchecked(MutableSpan dst, Span src) +{ + BLI_assert(src.size() == dst.size()); + for (SourceType index : IndexRange(src.size())) { + dst[index] = src[index]; + } +} + +void convert(ConversionType type, + eGPUTextureFormat device_format, + size_t sample_len, + void *dst_memory, + const void *src_memory) +{ + switch (type) { + case ConversionType::UNSUPPORTED: + return; + + case ConversionType::UNMODIFIED: + memcpy(dst_memory, src_memory, sample_len * to_bytesize(device_format)); + return; + + case ConversionType::UI16_TO_UI32: { + size_t component_len = to_component_len(device_format) * sample_len; + Span src = Span(static_cast(src_memory), + component_len); + MutableSpan dst = MutableSpan(static_cast(dst_memory), + component_len); + copy_unchecked(dst, src); + break; + } + + case ConversionType::UI32_TO_UI16: { + size_t component_len = to_component_len(device_format) * sample_len; + Span src = Span(static_cast(src_memory), + component_len); + MutableSpan dst = MutableSpan(static_cast(dst_memory), + component_len); + copy_unchecked(dst, src); + break; + } + + case ConversionType::FLOAT_TO_HALF: + case ConversionType::HALF_TO_FLOAT: + BLI_assert_unreachable(); + return; + } +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_data_conversion.hh b/source/blender/gpu/vulkan/vk_data_conversion.hh new file mode 100644 index 00000000000..32ad6dff55d --- /dev/null +++ b/source/blender/gpu/vulkan/vk_data_conversion.hh @@ -0,0 +1,56 @@ + +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_texture_private.hh" + +namespace blender::gpu { + +enum class ConversionType { + /** No conversion needed, result can be directly read back to host memory. */ + UNMODIFIED, + + UI16_TO_UI32, + UI32_TO_UI16, + + /* + UI8_TO_UI32, + I16_TO_I32, + I8_TO_I32, + UI8_TO_I32, + UI8_TO_FLOAT, + UI8_TO_UBYTE, + */ + + /** Convert device 16F to floats. */ + HALF_TO_FLOAT, + FLOAT_TO_HALF, + + /** + * The requested conversion isn't supported. + */ + UNSUPPORTED, +}; + +/** + * Determine the type of conversion that is needed to read back data from GPU device to host + * memory. + */ +ConversionType conversion_type_for_read(eGPUDataFormat host_format, + eGPUTextureFormat device_format); +ConversionType conversion_type_for_update(eGPUDataFormat host_format, + eGPUTextureFormat device_format); + +void convert(ConversionType type, + eGPUTextureFormat device_format, + size_t sample_len, + void *dst_memory, + const void *src_memory); + +}; // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index 1732d54a949..37ff2f72fa1 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -9,10 +9,13 @@ #include "vk_buffer.hh" #include "vk_context.hh" +#include "vk_data_conversion.hh" #include "vk_memory.hh" #include "vk_shader.hh" #include "vk_shader_interface.hh" +#include "BLI_math_vector.hh" + #include "BKE_global.h" namespace blender::gpu { @@ -34,8 +37,64 @@ void VKTexture::copy_to(Texture * /*tex*/) { } -void VKTexture::clear(eGPUDataFormat /*format*/, const void * /*data*/) +template void copy_color(T dst[4], const T *src) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} + +static VkClearColorValue to_vk_clear_color_value(eGPUDataFormat format, const void *data) +{ + VkClearColorValue result = {0.0f}; + switch (format) { + case GPU_DATA_FLOAT: { + const float *float_data = static_cast(data); + copy_color(result.float32, float_data); + break; + } + + case GPU_DATA_INT: { + const int32_t *int_data = static_cast(data); + copy_color(result.int32, int_data); + break; + } + + case GPU_DATA_UINT: { + const uint32_t *uint_data = static_cast(data); + copy_color(result.uint32, uint_data); + break; + } + + case GPU_DATA_HALF_FLOAT: + case GPU_DATA_UBYTE: + case GPU_DATA_UINT_24_8: + case GPU_DATA_10_11_11_REV: + case GPU_DATA_2_10_10_10_REV: { + BLI_assert_unreachable(); + break; + } + } + return result; +} + +void VKTexture::clear(eGPUDataFormat format, const void *data) +{ + if (!is_allocated()) { + allocate(); + } + + VKContext &context = *VKContext::get(); + VKCommandBuffer &command_buffer = context.command_buffer_get(); + VkClearColorValue clear_color = to_vk_clear_color_value(format, data); + VkImageSubresourceRange range = {0}; + range.aspectMask = to_vk_image_aspect_flag_bits(format_); + range.levelCount = VK_REMAINING_MIP_LEVELS; + range.layerCount = VK_REMAINING_ARRAY_LAYERS; + + command_buffer.clear( + vk_image_, VK_IMAGE_LAYOUT_GENERAL, clear_color, Span(&range, 1)); } void VKTexture::swizzle_set(const char /*swizzle_mask*/[4]) @@ -80,11 +139,11 @@ void *VKTexture::read(int mip, eGPUDataFormat format) void *data = MEM_mallocN(host_memory_size, __func__); - /* TODO: add conversion when data format is different. */ - BLI_assert_msg(device_memory_size == host_memory_size, + /* Convert data from device to host memory. */ + ConversionType conversion_type = conversion_type_for_read(format, format_); + BLI_assert_msg(conversion_type != ConversionType::UNSUPPORTED, "Memory data conversions not implemented yet"); - - staging_buffer.read(data); + convert(conversion_type, format_, sample_len, data, staging_buffer.mapped_memory_get()); return data; } @@ -152,8 +211,8 @@ bool VKTexture::allocate() image_info.format = to_vk_format(format_); image_info.tiling = VK_IMAGE_TILING_LINEAR; image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_STORAGE_BIT; + image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT; image_info.samples = VK_SAMPLE_COUNT_1_BIT; VkResult result; -- 2.30.2 From 0f30f7591b83c6b1031c2ccf15bef3b91c0c29ce Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 14 Mar 2023 15:55:48 +0100 Subject: [PATCH 02/15] Added roundtrip test cases. --- source/blender/gpu/intern/gpu_texture.cc | 3 +- source/blender/gpu/tests/texture_test.cc | 192 ++++++++++++++++++ .../blender/gpu/vulkan/vk_command_buffer.cc | 11 + .../blender/gpu/vulkan/vk_command_buffer.hh | 1 + .../blender/gpu/vulkan/vk_data_conversion.cc | 12 +- source/blender/gpu/vulkan/vk_texture.cc | 38 +++- 6 files changed, 246 insertions(+), 11 deletions(-) diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index bfe495c7378..a4db4350c54 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -213,7 +213,8 @@ void Texture::detach_from(FrameBuffer *fb) void Texture::update(eGPUDataFormat format, const void *data) { int mip = 0; - int extent[3], offset[3] = {0, 0, 0}; + int extent[3] = {1, 1, 1}; + int offset[3] = {0, 0, 0}; this->mip_size_get(mip, extent); this->update_sub(mip, offset, extent, format, data); } diff --git a/source/blender/gpu/tests/texture_test.cc b/source/blender/gpu/tests/texture_test.cc index c453e9eb2d2..57e8d7c2160 100644 --- a/source/blender/gpu/tests/texture_test.cc +++ b/source/blender/gpu/tests/texture_test.cc @@ -46,4 +46,196 @@ static void test_texture_read() } GPU_TEST(texture_read) +/* -------------------------------------------------------------------- */ +/** \name Roundtrip testing 32F + * \{ */ + +static float *generate_test_data_float(size_t data_len) +{ + float *data = static_cast(MEM_mallocN(data_len * sizeof(float), __func__)); + for (int i : IndexRange(data_len)) { + data[i] = 8.0 / max_ff(i % 8, 0.5f); + } + return data; +} + +template +static void texture_create_upload_read_float() +{ + size_t data_len = Size * Size * ComponentLen; + float *data = generate_test_data_float(data_len); + + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; + GPUTexture *texture = GPU_texture_create_2d("texture", Size, Size, 1, DeviceFormat, usage, data); + EXPECT_NE(texture, nullptr); + + float *read_data = (float *)GPU_texture_read(texture, GPU_DATA_FLOAT, 0); + for (int i : IndexRange(data_len)) { + EXPECT_EQ(read_data[i], data[i]); + } + MEM_freeN(read_data); + + GPU_texture_free(texture); + MEM_freeN(data); +} + +static void test_texture_roundtrip_FLOAT_RGBA32F() +{ + texture_create_upload_read_float(); +} +GPU_TEST(texture_roundtrip_FLOAT_RGBA32F) + +#if 0 +/* Isn't supported natively on NVidia/Vulkan. */ +static void test_texture_roundtrip_FLOAT_RGBA32F() +{ + texture_create_upload_read_float(); +} +GPU_TEST(texture_roundtrip_FLOAT_RGBA32F) +#endif + +static void test_texture_roundtrip_FLOAT_RG32F() +{ + texture_create_upload_read_float(); +} +GPU_TEST(texture_roundtrip_FLOAT_RG32F) + +static void test_texture_roundtrip_FLOAT_R32F() +{ + texture_create_upload_read_float(); +} +GPU_TEST(texture_roundtrip_FLOAT_R32F) + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Roundtrip testing 32UI + * \{ */ + +static uint32_t *generate_test_data_uint(size_t data_len) +{ + uint32_t *data = static_cast(MEM_mallocN(data_len * sizeof(uint32_t), __func__)); + for (int i : IndexRange(data_len)) { + data[i] = 8 / max_ii(i % 8, 1); + } + return data; +} + +template +static void texture_create_upload_read_uint() +{ + + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; + GPUTexture *texture = GPU_texture_create_2d( + "texture", Size, Size, 1, DeviceFormat, usage, nullptr); + EXPECT_NE(texture, nullptr); + + size_t data_len = Size * Size * ComponentLen; + uint32_t *data = generate_test_data_uint(data_len); + GPU_texture_update(texture, GPU_DATA_UINT, data); + + uint32_t *read_data = (uint32_t *)GPU_texture_read(texture, GPU_DATA_UINT, 0); + for (int i : IndexRange(data_len)) { + EXPECT_EQ(read_data[i], data[i]); + } + MEM_freeN(read_data); + + GPU_texture_free(texture); + MEM_freeN(data); +} + +static void test_texture_roundtrip_UINT_RGBA32UI() +{ + texture_create_upload_read_uint(); +} +GPU_TEST(texture_roundtrip_UINT_RGBA32UI) + +#if 0 +/* Isn't supported natively on NVidia/Vulkan. */ +static void test_texture_roundtrip_UINT_RGB32UI() +{ + texture_create_upload_read_uint(); +} +GPU_TEST(texture_roundtrip_UINT_RGB32UI) +#endif + +static void test_texture_roundtrip_UINT_RG32UI() +{ + texture_create_upload_read_uint(); +} +GPU_TEST(texture_roundtrip_UINT_RG32UI) + +static void test_texture_roundtrip_UINT_R32UI() +{ + texture_create_upload_read_uint(); +} +GPU_TEST(texture_roundtrip_UINT_R32UI) + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Roundtrip testing 32I + * \{ */ + +static int32_t *generate_test_data_int(size_t data_len) +{ + int32_t *data = static_cast(MEM_mallocN(data_len * sizeof(int32_t), __func__)); + for (int i : IndexRange(data_len)) { + data[i] = 8 / max_ii(i % 8, 1); + } + return data; +} + +template +static void texture_create_upload_read_int() +{ + + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; + GPUTexture *texture = GPU_texture_create_2d( + "texture", Size, Size, 1, DeviceFormat, usage, nullptr); + EXPECT_NE(texture, nullptr); + + size_t data_len = Size * Size * ComponentLen; + int32_t *data = generate_test_data_int(data_len); + GPU_texture_update(texture, GPU_DATA_INT, data); + + uint32_t *read_data = (uint32_t *)GPU_texture_read(texture, GPU_DATA_INT, 0); + for (int i : IndexRange(data_len)) { + EXPECT_EQ(read_data[i], data[i]); + } + MEM_freeN(read_data); + + GPU_texture_free(texture); + MEM_freeN(data); +} + +static void test_texture_roundtrip_INT_RGBA32I() +{ + texture_create_upload_read_int(); +} +GPU_TEST(texture_roundtrip_INT_RGBA32I) + +#if 0 +/* Isn't supported natively on NVidia/Vulkan. */ +static void test_texture_roundtrip_INT_RGB32I() +{ + texture_create_upload_read_int(); +} +GPU_TEST(texture_roundtrip_INT_RGB32I) +#endif + +static void test_texture_roundtrip_INT_RG32I() +{ + texture_create_upload_read_int(); +} +GPU_TEST(texture_roundtrip_INT_RG32I) + +static void test_texture_roundtrip_INT_R32I() +{ + texture_create_upload_read_int(); +} +GPU_TEST(texture_roundtrip_INT_R32I) + +/** \} */ + } // namespace blender::gpu::tests \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index 9a5463bf890..b59976a23cd 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -97,6 +97,17 @@ void VKCommandBuffer::copy(VKBuffer &dst_buffer, regions.size(), regions.data()); } +void VKCommandBuffer::copy(VKTexture &dst_texture, + VKBuffer &src_buffer, + Span regions) +{ + vkCmdCopyBufferToImage(vk_command_buffer_, + src_buffer.vk_handle(), + dst_texture.vk_image_handle(), + VK_IMAGE_LAYOUT_GENERAL, + regions.size(), + regions.data()); +} void VKCommandBuffer::clear(VkImage vk_image, VkImageLayout vk_image_layout, diff --git a/source/blender/gpu/vulkan/vk_command_buffer.hh b/source/blender/gpu/vulkan/vk_command_buffer.hh index 0a52c66af52..d8f8543eb70 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.hh +++ b/source/blender/gpu/vulkan/vk_command_buffer.hh @@ -48,6 +48,7 @@ class VKCommandBuffer : NonCopyable, NonMovable { void dispatch(int groups_x_len, int groups_y_len, int groups_z_len); /** Copy the contents of a texture MIP level to the dst buffer. */ void copy(VKBuffer &dst_buffer, VKTexture &src_texture, Span regions); + void copy(VKTexture &dst_texture, VKBuffer &src_buffer, Span regions); void pipeline_barrier(VkPipelineStageFlags source_stages, VkPipelineStageFlags destination_stages); void pipeline_barrier(Span image_memory_barriers); diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc index 51edfe71628..bb573649a0a 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.cc +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -14,7 +14,6 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format) case GPU_RGBA32F: case GPU_RG32F: case GPU_R32F: - case GPU_RGB32F: case GPU_DEPTH_COMPONENT32F: return ConversionType::UNMODIFIED; @@ -24,6 +23,7 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format) case GPU_RGB16F: return ConversionType::FLOAT_TO_HALF; + case GPU_RGB32F: /* GPU_RGB32F Not supported by vendors. */ case GPU_RGBA8UI: case GPU_RGBA8I: case GPU_RGBA8: @@ -88,6 +88,11 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format) static ConversionType type_of_conversion_int(eGPUTextureFormat device_format) { switch (device_format) { + case GPU_RGBA32I: + case GPU_RG32I: + case GPU_R32I: + return ConversionType::UNMODIFIED; + case GPU_RGBA8UI: case GPU_RGBA8I: case GPU_RGBA8: @@ -96,7 +101,6 @@ static ConversionType type_of_conversion_int(eGPUTextureFormat device_format) case GPU_RGBA16F: case GPU_RGBA16: case GPU_RGBA32UI: - case GPU_RGBA32I: case GPU_RGBA32F: case GPU_RG8UI: case GPU_RG8I: @@ -106,7 +110,6 @@ static ConversionType type_of_conversion_int(eGPUTextureFormat device_format) case GPU_RG16F: case GPU_RG16: case GPU_RG32UI: - case GPU_RG32I: case GPU_RG32F: case GPU_R8UI: case GPU_R8I: @@ -116,7 +119,6 @@ static ConversionType type_of_conversion_int(eGPUTextureFormat device_format) case GPU_R16F: case GPU_R16: case GPU_R32UI: - case GPU_R32I: case GPU_R32F: case GPU_RGB10_A2: case GPU_RGB10_A2UI: @@ -164,7 +166,6 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format) case GPU_RGBA32UI: case GPU_RG32UI: case GPU_R32UI: - case GPU_RGB32UI: return ConversionType::UNMODIFIED; case GPU_RGBA16UI: @@ -213,6 +214,7 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format) case GPU_RGB16F: case GPU_RGB16: case GPU_RGB16_SNORM: + case GPU_RGB32UI: case GPU_RGB32I: case GPU_RGB32F: case GPU_RG8_SNORM: diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index 37ff2f72fa1..ba403a49426 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -148,12 +148,40 @@ void *VKTexture::read(int mip, eGPUDataFormat format) return data; } -void VKTexture::update_sub(int /*mip*/, - int /*offset*/[3], - int /*extent*/[3], - eGPUDataFormat /*format*/, - const void * /*data*/) +void VKTexture::update_sub( + int mip, int /*offset*/[3], int extent[3], eGPUDataFormat format, const void *data) { + if (!is_allocated()) { + allocate(); + } + + /* Vulkan images cannot be directly mapped to host memory and requires a staging buffer. */ + VKContext &context = *VKContext::get(); + VKBuffer staging_buffer; + size_t sample_len = extent[0] * extent[1] * extent[2]; + size_t device_memory_size = sample_len * to_bytesize(format_); + + staging_buffer.create( + context, device_memory_size, GPU_USAGE_DEVICE_ONLY, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + + ConversionType conversion_type = conversion_type_for_update(format, format_); + BLI_assert_msg(conversion_type != ConversionType::UNSUPPORTED, + "Memory data conversions not implemented yet"); + convert(conversion_type, format_, sample_len, staging_buffer.mapped_memory_get(), data); + + VkBufferImageCopy region = {}; + region.imageExtent.width = extent[0]; + region.imageExtent.height = extent[1]; + region.imageExtent.depth = extent[2]; + region.imageSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_); + region.imageSubresource.mipLevel = mip; + region.imageSubresource.layerCount = 1; + + VKCommandBuffer &command_buffer = context.command_buffer_get(); + command_buffer.copy(*this, staging_buffer, Span(®ion, 1)); + command_buffer.submit(); + + /* TODO: add support for offset. */ } void VKTexture::update_sub(int /*offset*/[3], -- 2.30.2 From b0864d4a167ab80f729d21375c078596f677b2f9 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 14 Mar 2023 15:57:29 +0100 Subject: [PATCH 03/15] Renamed unmodified to pass_through. --- source/blender/gpu/vulkan/vk_data_conversion.cc | 12 ++++++------ source/blender/gpu/vulkan/vk_data_conversion.hh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc index bb573649a0a..a1cba618c6f 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.cc +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -15,7 +15,7 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format) case GPU_RG32F: case GPU_R32F: case GPU_DEPTH_COMPONENT32F: - return ConversionType::UNMODIFIED; + return ConversionType::PASS_THROUGH; case GPU_RGBA16F: case GPU_RG16F: @@ -91,7 +91,7 @@ static ConversionType type_of_conversion_int(eGPUTextureFormat device_format) case GPU_RGBA32I: case GPU_RG32I: case GPU_R32I: - return ConversionType::UNMODIFIED; + return ConversionType::PASS_THROUGH; case GPU_RGBA8UI: case GPU_RGBA8I: @@ -166,7 +166,7 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format) case GPU_RGBA32UI: case GPU_RG32UI: case GPU_R32UI: - return ConversionType::UNMODIFIED; + return ConversionType::PASS_THROUGH; case GPU_RGBA16UI: case GPU_RG16UI: @@ -338,8 +338,8 @@ ConversionType conversion_type_for_update(eGPUDataFormat host_format, static ConversionType invert(ConversionType type) { switch (type) { - case ConversionType::UNMODIFIED: - return ConversionType::UNMODIFIED; + case ConversionType::PASS_THROUGH: + return ConversionType::PASS_THROUGH; case ConversionType::UI16_TO_UI32: return ConversionType::UI32_TO_UI16; @@ -384,7 +384,7 @@ void convert(ConversionType type, case ConversionType::UNSUPPORTED: return; - case ConversionType::UNMODIFIED: + case ConversionType::PASS_THROUGH: memcpy(dst_memory, src_memory, sample_len * to_bytesize(device_format)); return; diff --git a/source/blender/gpu/vulkan/vk_data_conversion.hh b/source/blender/gpu/vulkan/vk_data_conversion.hh index 32ad6dff55d..9406823f7b0 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.hh +++ b/source/blender/gpu/vulkan/vk_data_conversion.hh @@ -14,7 +14,7 @@ namespace blender::gpu { enum class ConversionType { /** No conversion needed, result can be directly read back to host memory. */ - UNMODIFIED, + PASS_THROUGH, UI16_TO_UI32, UI32_TO_UI16, -- 2.30.2 From bc1aa48ae9e2670bc65837a4fec6f75a305ef9e1 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 16 Mar 2023 15:59:05 +0100 Subject: [PATCH 04/15] Added all test cases for data conversion. --- .../blender/gpu/intern/gpu_texture_private.hh | 3 +- source/blender/gpu/tests/texture_test.cc | 875 +++++++++++++++--- .../blender/gpu/vulkan/vk_data_conversion.cc | 363 +++++++- .../blender/gpu/vulkan/vk_data_conversion.hh | 20 +- source/blender/gpu/vulkan/vk_texture.cc | 9 +- 5 files changed, 1066 insertions(+), 204 deletions(-) diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh index 798a410eaae..2b4244221dc 100644 --- a/source/blender/gpu/intern/gpu_texture_private.hh +++ b/source/blender/gpu/intern/gpu_texture_private.hh @@ -759,7 +759,8 @@ inline size_t to_bytesize(eGPUTextureFormat tex_format, eGPUDataFormat data_form } /* Definitely not complete, edit according to the gl specification. */ -inline bool validate_data_format(eGPUTextureFormat tex_format, eGPUDataFormat data_format) +constexpr inline bool validate_data_format(eGPUTextureFormat tex_format, + eGPUDataFormat data_format) { switch (tex_format) { /* Formats texture & render-buffer */ diff --git a/source/blender/gpu/tests/texture_test.cc b/source/blender/gpu/tests/texture_test.cc index 57e8d7c2160..90460ef2eca 100644 --- a/source/blender/gpu/tests/texture_test.cc +++ b/source/blender/gpu/tests/texture_test.cc @@ -3,10 +3,13 @@ #include "MEM_guardedalloc.h" #include "BLI_math_vector.hh" +#include "BLI_vector.hh" #include "GPU_context.h" #include "GPU_texture.h" +#include "gpu_texture_private.hh" + namespace blender::gpu::tests { static void test_texture_read() @@ -46,196 +49,772 @@ static void test_texture_read() } GPU_TEST(texture_read) -/* -------------------------------------------------------------------- */ -/** \name Roundtrip testing 32F - * \{ */ - -static float *generate_test_data_float(size_t data_len) +template static DataType *generate_test_data(size_t data_len) { - float *data = static_cast(MEM_mallocN(data_len * sizeof(float), __func__)); + DataType *data = static_cast(MEM_mallocN(data_len * sizeof(DataType), __func__)); for (int i : IndexRange(data_len)) { - data[i] = 8.0 / max_ff(i % 8, 0.5f); + data[i] = (DataType)(i % 8); } return data; } -template -static void texture_create_upload_read_float() +template +static void texture_create_upload_read() { - size_t data_len = Size * Size * ComponentLen; - float *data = generate_test_data_float(data_len); - - eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; - GPUTexture *texture = GPU_texture_create_2d("texture", Size, Size, 1, DeviceFormat, usage, data); - EXPECT_NE(texture, nullptr); - - float *read_data = (float *)GPU_texture_read(texture, GPU_DATA_FLOAT, 0); - for (int i : IndexRange(data_len)) { - EXPECT_EQ(read_data[i], data[i]); - } - MEM_freeN(read_data); - - GPU_texture_free(texture); - MEM_freeN(data); -} - -static void test_texture_roundtrip_FLOAT_RGBA32F() -{ - texture_create_upload_read_float(); -} -GPU_TEST(texture_roundtrip_FLOAT_RGBA32F) - -#if 0 -/* Isn't supported natively on NVidia/Vulkan. */ -static void test_texture_roundtrip_FLOAT_RGBA32F() -{ - texture_create_upload_read_float(); -} -GPU_TEST(texture_roundtrip_FLOAT_RGBA32F) -#endif - -static void test_texture_roundtrip_FLOAT_RG32F() -{ - texture_create_upload_read_float(); -} -GPU_TEST(texture_roundtrip_FLOAT_RG32F) - -static void test_texture_roundtrip_FLOAT_R32F() -{ - texture_create_upload_read_float(); -} -GPU_TEST(texture_roundtrip_FLOAT_R32F) - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Roundtrip testing 32UI - * \{ */ - -static uint32_t *generate_test_data_uint(size_t data_len) -{ - uint32_t *data = static_cast(MEM_mallocN(data_len * sizeof(uint32_t), __func__)); - for (int i : IndexRange(data_len)) { - data[i] = 8 / max_ii(i % 8, 1); - } - return data; -} - -template -static void texture_create_upload_read_uint() -{ - + static_assert(validate_data_format(DeviceFormat, HostFormat)); eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; GPUTexture *texture = GPU_texture_create_2d( "texture", Size, Size, 1, DeviceFormat, usage, nullptr); EXPECT_NE(texture, nullptr); - size_t data_len = Size * Size * ComponentLen; - uint32_t *data = generate_test_data_uint(data_len); - GPU_texture_update(texture, GPU_DATA_UINT, data); + size_t data_len = Size * Size * to_component_len(DeviceFormat); + DataType *data = static_cast(generate_test_data(data_len)); + GPU_texture_update(texture, HostFormat, data); - uint32_t *read_data = (uint32_t *)GPU_texture_read(texture, GPU_DATA_UINT, 0); + DataType *read_data = static_cast(GPU_texture_read(texture, HostFormat, 0)); for (int i : IndexRange(data_len)) { EXPECT_EQ(read_data[i], data[i]); } MEM_freeN(read_data); + MEM_freeN(data); GPU_texture_free(texture); - MEM_freeN(data); } -static void test_texture_roundtrip_UINT_RGBA32UI() -{ - texture_create_upload_read_uint(); -} -GPU_TEST(texture_roundtrip_UINT_RGBA32UI) - -#if 0 -/* Isn't supported natively on NVidia/Vulkan. */ -static void test_texture_roundtrip_UINT_RGB32UI() -{ - texture_create_upload_read_uint(); -} -GPU_TEST(texture_roundtrip_UINT_RGB32UI) -#endif - -static void test_texture_roundtrip_UINT_RG32UI() -{ - texture_create_upload_read_uint(); -} -GPU_TEST(texture_roundtrip_UINT_RG32UI) - -static void test_texture_roundtrip_UINT_R32UI() -{ - texture_create_upload_read_uint(); -} -GPU_TEST(texture_roundtrip_UINT_R32UI) - -/** \} */ - /* -------------------------------------------------------------------- */ -/** \name Roundtrip testing 32I +/** \name Roundtrip testing GPU_DATA_FLOAT * \{ */ - -static int32_t *generate_test_data_int(size_t data_len) +#if 1 +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8() { - int32_t *data = static_cast(MEM_mallocN(data_len * sizeof(int32_t), __func__)); - for (int i : IndexRange(data_len)) { - data[i] = 8 / max_ii(i % 8, 1); - } - return data; + texture_create_upload_read(); } +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8); -template -static void texture_create_upload_read_int() +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16F() { - - eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; - GPUTexture *texture = GPU_texture_create_2d( - "texture", Size, Size, 1, DeviceFormat, usage, nullptr); - EXPECT_NE(texture, nullptr); - - size_t data_len = Size * Size * ComponentLen; - int32_t *data = generate_test_data_int(data_len); - GPU_texture_update(texture, GPU_DATA_INT, data); - - uint32_t *read_data = (uint32_t *)GPU_texture_read(texture, GPU_DATA_INT, 0); - for (int i : IndexRange(data_len)) { - EXPECT_EQ(read_data[i], data[i]); - } - MEM_freeN(read_data); - - GPU_texture_free(texture); - MEM_freeN(data); + texture_create_upload_read(); } +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16F); -static void test_texture_roundtrip_INT_RGBA32I() +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16() { - texture_create_upload_read_int(); + texture_create_upload_read(); } -GPU_TEST(texture_roundtrip_INT_RGBA32I) +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16); -#if 0 -/* Isn't supported natively on NVidia/Vulkan. */ -static void test_texture_roundtrip_INT_RGB32I() +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA32F() { - texture_create_upload_read_int(); + texture_create_upload_read(); } -GPU_TEST(texture_roundtrip_INT_RGB32I) +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA32F); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16F() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16F); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG32F() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG32F); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R8); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R16F() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R16F); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R16() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R16); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R32F() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R32F); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB10_A2() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB10_A2); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB10_A2UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB10_A2UI); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R11F_G11F_B10F() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R11F_G11F_B10F); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_SNORM() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_SNORM); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16_SNORM() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16_SNORM); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB8); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB8_SNORM() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB8_SNORM); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16F() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16F); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16_SNORM() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16_SNORM); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB32F() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB32F); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8_SNORM() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8_SNORM); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16_SNORM() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16_SNORM); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R8_SNORM() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R8_SNORM); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R16_SNORM() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R16_SNORM); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT1() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT1); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT3() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT3); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT5() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT5); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT1() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT1); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT3() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT3); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT5() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT5); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB9_E5() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB9_E5); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT32F() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT32F); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT24() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT24); + +static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT16() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT16); #endif +/* \} */ -static void test_texture_roundtrip_INT_RG32I() +/* -------------------------------------------------------------------- */ +/** \name Roundtrip testing GPU_DATA_HALF_FLOAT + * \{ */ +#if 0 +static void test_texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RGBA16F() { - texture_create_upload_read_int(); + texture_create_upload_read(); } -GPU_TEST(texture_roundtrip_INT_RG32I) +GPU_TEST(texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RGBA16F); -static void test_texture_roundtrip_INT_R32I() +static void test_texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RG16F() { - texture_create_upload_read_int(); + texture_create_upload_read(); } -GPU_TEST(texture_roundtrip_INT_R32I) +GPU_TEST(texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RG16F); +static void test_texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_R16F() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_R16F); + +static void test_texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RGB16F() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RGB16F); +#endif +/* \} */ + +/* -------------------------------------------------------------------- */ +/** \name Roundtrip testing GPU_DATA_INT + * \{ */ +#if 0 +static void test_texture_roundtrip__GPU_DATA_INT__GPU_RGBA8I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RGBA8I); + +static void test_texture_roundtrip__GPU_DATA_INT__GPU_RGBA16I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RGBA16I); + +static void test_texture_roundtrip__GPU_DATA_INT__GPU_RGBA32I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RGBA32I); + +static void test_texture_roundtrip__GPU_DATA_INT__GPU_RG8I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RG8I); + +static void test_texture_roundtrip__GPU_DATA_INT__GPU_RG16I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RG16I); + +static void test_texture_roundtrip__GPU_DATA_INT__GPU_RG32I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RG32I); + +static void test_texture_roundtrip__GPU_DATA_INT__GPU_R8I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_R8I); + +static void test_texture_roundtrip__GPU_DATA_INT__GPU_R16I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_R16I); + +static void test_texture_roundtrip__GPU_DATA_INT__GPU_R32I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_R32I); + +static void test_texture_roundtrip__GPU_DATA_INT__GPU_RGB8I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RGB8I); + +static void test_texture_roundtrip__GPU_DATA_INT__GPU_RGB16I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RGB16I); + +static void test_texture_roundtrip__GPU_DATA_INT__GPU_RGB32I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RGB32I); +#endif +/* \} */ + +/* -------------------------------------------------------------------- */ +/** \name Roundtrip testing GPU_DATA_UINT + * \{ */ +#if 0 +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGBA8UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_RGBA8UI); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGBA16UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_RGBA16UI); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGBA32UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_RGBA32UI); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RG8UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_RG8UI); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RG16UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_RG16UI); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RG32UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_RG32UI); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_R8UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_R8UI); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_R16UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_R16UI); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_R32UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_R32UI); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH32F_STENCIL8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH32F_STENCIL8); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH24_STENCIL8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH24_STENCIL8); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGB8UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_RGB8UI); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGB16UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_RGB16UI); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGB32UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_RGB32UI); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT32F() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT32F); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT24() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT24); + +static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT16() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT16); +#endif +/* \} */ + +/* -------------------------------------------------------------------- */ +/** \name Roundtrip testing GPU_DATA_UBYTE + * \{ */ +#if 0 +static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_RGBA8UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_RGBA8UI); + +static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_RGBA8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_RGBA8); + +static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_RG8UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_RG8UI); + +static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_RG8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_RG8); + +static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_R8UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_R8UI); + +static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_R8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_R8); + +static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8_A8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8_A8); + +static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_RGB8I() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_RGB8I); + +static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_RGB8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_RGB8); + +static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8); +#endif +/* \} */ + +/* -------------------------------------------------------------------- */ +/** \name Roundtrip testing GPU_DATA_UINT_24_8 + * \{ */ +#if 0 +static void test_texture_roundtrip__GPU_DATA_UINT_24_8__GPU_DEPTH32F_STENCIL8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT_24_8__GPU_DEPTH32F_STENCIL8); + +static void test_texture_roundtrip__GPU_DATA_UINT_24_8__GPU_DEPTH24_STENCIL8() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_UINT_24_8__GPU_DEPTH24_STENCIL8); +#endif +/* \} */ + +/* -------------------------------------------------------------------- */ +/** \name Roundtrip testing GPU_DATA_10_11_11_REV + * \{ */ +#if 0 +static void test_texture_roundtrip__GPU_DATA_10_11_11_REV__GPU_R11F_G11F_B10F() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_10_11_11_REV__GPU_R11F_G11F_B10F); +#endif +/* \} */ + +/* -------------------------------------------------------------------- */ +/** \name Roundtrip testing GPU_DATA_2_10_10_10_REV + * \{ */ +#if 0 +static void test_texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2); +static void test_texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2UI() +{ + texture_create_upload_read(); +} +GPU_TEST(texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2UI); +#endif +/* \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generate test cases. + * + * Next section is kept for convenience to regenerate test cases. + * + * \{ */ +#if 0 + static std::string to_prim_type_string(eGPUDataFormat host_format) + { + switch (host_format) { + case GPU_DATA_FLOAT: + return std::string("float"); + + case GPU_DATA_HALF_FLOAT: + return std::string("half"); + case GPU_DATA_INT: + return std::string("int32_t"); + case GPU_DATA_UINT: + return std::string("uint32_t"); + case GPU_DATA_UBYTE: + return std::string("uint8_t"); + case GPU_DATA_UINT_24_8: + case GPU_DATA_10_11_11_REV: + case GPU_DATA_2_10_10_10_REV: + return std::string("void"); + } + return std::string("UNKNOWN"); + } + static std::string to_string(eGPUDataFormat host_format) + { + switch (host_format) { + case GPU_DATA_FLOAT: + return std::string("GPU_DATA_FLOAT"); + + case GPU_DATA_HALF_FLOAT: + return std::string("GPU_DATA_HALF_FLOAT"); + case GPU_DATA_INT: + return std::string("GPU_DATA_INT"); + case GPU_DATA_UINT: + return std::string("GPU_DATA_UINT"); + case GPU_DATA_UBYTE: + return std::string("GPU_DATA_UBYTE"); + case GPU_DATA_UINT_24_8: + return std::string("GPU_DATA_UINT_24_8"); + case GPU_DATA_10_11_11_REV: + return std::string("GPU_DATA_10_11_11_REV"); + case GPU_DATA_2_10_10_10_REV: + return std::string("GPU_DATA_2_10_10_10_REV"); + } + return std::string("UNKNOWN"); + } + + static std::string to_string(eGPUTextureFormat texture_format) + { + return std::string("GPU_") + std::string(GPU_texture_format_name(texture_format)); + } + + TEST(gpu_util, generate_test_cases) + { + Vector host_formats; + host_formats.append(GPU_DATA_FLOAT); + host_formats.append(GPU_DATA_HALF_FLOAT); + host_formats.append(GPU_DATA_INT); + host_formats.append(GPU_DATA_UINT); + host_formats.append(GPU_DATA_UBYTE); + host_formats.append(GPU_DATA_UINT_24_8); + host_formats.append(GPU_DATA_10_11_11_REV); + host_formats.append(GPU_DATA_2_10_10_10_REV); + + Vector texture_formats; + texture_formats.append(GPU_RGBA8UI); + texture_formats.append(GPU_RGBA8I); + texture_formats.append(GPU_RGBA8); + texture_formats.append(GPU_RGBA16UI); + texture_formats.append(GPU_RGBA16I); + texture_formats.append(GPU_RGBA16F); + texture_formats.append(GPU_RGBA16); + texture_formats.append(GPU_RGBA32UI); + texture_formats.append(GPU_RGBA32I); + texture_formats.append(GPU_RGBA32F); + texture_formats.append(GPU_RG8UI); + texture_formats.append(GPU_RG8I); + texture_formats.append(GPU_RG8); + texture_formats.append(GPU_RG16UI); + texture_formats.append(GPU_RG16I); + texture_formats.append(GPU_RG16F); + texture_formats.append(GPU_RG16); + texture_formats.append(GPU_RG32UI); + texture_formats.append(GPU_RG32I); + texture_formats.append(GPU_RG32F); + texture_formats.append(GPU_R8UI); + texture_formats.append(GPU_R8I); + texture_formats.append(GPU_R8); + texture_formats.append(GPU_R16UI); + texture_formats.append(GPU_R16I); + texture_formats.append(GPU_R16F); + texture_formats.append(GPU_R16); + texture_formats.append(GPU_R32UI); + texture_formats.append(GPU_R32I); + texture_formats.append(GPU_R32F); + texture_formats.append(GPU_RGB10_A2); + texture_formats.append(GPU_RGB10_A2UI); + texture_formats.append(GPU_R11F_G11F_B10F); + texture_formats.append(GPU_DEPTH32F_STENCIL8); + texture_formats.append(GPU_DEPTH24_STENCIL8); + texture_formats.append(GPU_SRGB8_A8); + texture_formats.append(GPU_RGBA8_SNORM); + texture_formats.append(GPU_RGBA16_SNORM); + texture_formats.append(GPU_RGB8UI); + texture_formats.append(GPU_RGB8I); + texture_formats.append(GPU_RGB8); + texture_formats.append(GPU_RGB8_SNORM); + texture_formats.append(GPU_RGB16UI); + texture_formats.append(GPU_RGB16I); + texture_formats.append(GPU_RGB16F); + texture_formats.append(GPU_RGB16); + texture_formats.append(GPU_RGB16_SNORM); + texture_formats.append(GPU_RGB32UI); + texture_formats.append(GPU_RGB32I); + texture_formats.append(GPU_RGB32F); + texture_formats.append(GPU_RG8_SNORM); + texture_formats.append(GPU_RG16_SNORM); + texture_formats.append(GPU_R8_SNORM); + texture_formats.append(GPU_R16_SNORM); + texture_formats.append(GPU_SRGB8_A8_DXT1); + texture_formats.append(GPU_SRGB8_A8_DXT3); + texture_formats.append(GPU_SRGB8_A8_DXT5); + texture_formats.append(GPU_RGBA8_DXT1); + texture_formats.append(GPU_RGBA8_DXT3); + texture_formats.append(GPU_RGBA8_DXT5); + texture_formats.append(GPU_SRGB8); + texture_formats.append(GPU_RGB9_E5); + texture_formats.append(GPU_DEPTH_COMPONENT32F); + texture_formats.append(GPU_DEPTH_COMPONENT24); + texture_formats.append(GPU_DEPTH_COMPONENT16); + + for (eGPUDataFormat host_format : host_formats) { + std::cout << "/* -------------------------------------------------------------------- */\n"; + std::cout << "/** \\name Roundtrip testing " << to_string(host_format) << "\n"; + std::cout << " * \\{ */\n\n"; + + for (eGPUTextureFormat texture_format : texture_formats) { + if (!validate_data_format(texture_format, host_format)) { + continue; + } + + std::cout << "static void test_texture_roundtrip__" << to_string(host_format) << "__" + << to_string(texture_format) << "()\n"; + std::cout << "{\n"; + + std::cout << " texture_create_upload_read<" << to_string(texture_format) << ", " + << to_string(host_format) << ", " << to_prim_type_string(host_format) + << ">();\n"; + + std::cout << "}\n"; + std::cout << "GPU_TEST(texture_roundtrip__" << to_string(host_format) << "__" + << to_string(texture_format) << ");\n\n"; + } + std::cout << "/* \\} */\n\n"; + } + } +#endif /** \} */ } // namespace blender::gpu::tests \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc index a1cba618c6f..21348a0e5a5 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.cc +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -23,10 +23,20 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format) case GPU_RGB16F: return ConversionType::FLOAT_TO_HALF; + case GPU_RGBA8: + case GPU_RG8: + case GPU_R8: + return ConversionType::FLOAT_TO_UNORM8; + + case GPU_RGBA8_SNORM: + case GPU_RGB8_SNORM: + case GPU_RG8_SNORM: + case GPU_R8_SNORM: + return ConversionType::FLOAT_TO_SNORM8; + case GPU_RGB32F: /* GPU_RGB32F Not supported by vendors. */ case GPU_RGBA8UI: case GPU_RGBA8I: - case GPU_RGBA8: case GPU_RGBA16UI: case GPU_RGBA16I: case GPU_RGBA16: @@ -34,7 +44,6 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format) case GPU_RGBA32I: case GPU_RG8UI: case GPU_RG8I: - case GPU_RG8: case GPU_RG16UI: case GPU_RG16I: case GPU_RG16: @@ -42,7 +51,6 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format) case GPU_RG32I: case GPU_R8UI: case GPU_R8I: - case GPU_R8: case GPU_R16UI: case GPU_R16I: case GPU_R16: @@ -54,21 +62,17 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format) case GPU_DEPTH32F_STENCIL8: case GPU_DEPTH24_STENCIL8: case GPU_SRGB8_A8: - case GPU_RGBA8_SNORM: case GPU_RGBA16_SNORM: case GPU_RGB8UI: case GPU_RGB8I: case GPU_RGB8: - case GPU_RGB8_SNORM: case GPU_RGB16UI: case GPU_RGB16I: case GPU_RGB16: case GPU_RGB16_SNORM: case GPU_RGB32UI: case GPU_RGB32I: - case GPU_RG8_SNORM: case GPU_RG16_SNORM: - case GPU_R8_SNORM: case GPU_R16_SNORM: case GPU_SRGB8_A8_DXT1: case GPU_SRGB8_A8_DXT3: @@ -93,29 +97,33 @@ static ConversionType type_of_conversion_int(eGPUTextureFormat device_format) case GPU_R32I: return ConversionType::PASS_THROUGH; - case GPU_RGBA8UI: + case GPU_RGBA16I: + case GPU_RG16I: + case GPU_R16I: + return ConversionType::I32_TO_I16; + case GPU_RGBA8I: + case GPU_RG8I: + case GPU_R8I: + return ConversionType::I32_TO_I8; + + case GPU_RGBA8UI: case GPU_RGBA8: case GPU_RGBA16UI: - case GPU_RGBA16I: case GPU_RGBA16F: case GPU_RGBA16: case GPU_RGBA32UI: case GPU_RGBA32F: case GPU_RG8UI: - case GPU_RG8I: case GPU_RG8: case GPU_RG16UI: - case GPU_RG16I: case GPU_RG16F: - case GPU_RG16: case GPU_RG32UI: case GPU_RG32F: + case GPU_RG16: case GPU_R8UI: - case GPU_R8I: case GPU_R8: case GPU_R16UI: - case GPU_R16I: case GPU_R16F: case GPU_R16: case GPU_R32UI: @@ -175,6 +183,10 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format) return ConversionType::UI32_TO_UI16; case GPU_RGBA8UI: + case GPU_RG8UI: + case GPU_R8UI: + return ConversionType::UI32_TO_UI8; + case GPU_RGBA8I: case GPU_RGBA8: case GPU_RGBA16I: @@ -182,7 +194,6 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format) case GPU_RGBA16: case GPU_RGBA32I: case GPU_RGBA32F: - case GPU_RG8UI: case GPU_RG8I: case GPU_RG8: case GPU_RG16I: @@ -190,7 +201,6 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format) case GPU_RG16: case GPU_RG32I: case GPU_RG32F: - case GPU_R8UI: case GPU_R8I: case GPU_R8: case GPU_R16I: @@ -310,6 +320,81 @@ static ConversionType type_of_conversion_half(eGPUTextureFormat device_format) return ConversionType::UNSUPPORTED; } +static ConversionType type_of_conversion_ubyte(eGPUTextureFormat device_format) +{ + switch (device_format) { + case GPU_RGBA8UI: + case GPU_RG8UI: + case GPU_R8UI: + return ConversionType::PASS_THROUGH; + + case GPU_RGBA8I: + case GPU_RGBA8: + case GPU_RGBA16UI: + case GPU_RGBA16I: + case GPU_RGBA16F: + case GPU_RGBA16: + case GPU_RGBA32UI: + case GPU_RGBA32I: + case GPU_RGBA32F: + case GPU_RG8I: + case GPU_RG8: + case GPU_RG16UI: + case GPU_RG16I: + case GPU_RG16F: + case GPU_RG16: + case GPU_RG32UI: + case GPU_RG32I: + case GPU_RG32F: + case GPU_R8I: + case GPU_R8: + case GPU_R16UI: + case GPU_R16I: + case GPU_R16F: + case GPU_R16: + case GPU_R32UI: + case GPU_R32I: + case GPU_R32F: + case GPU_RGB10_A2: + case GPU_RGB10_A2UI: + case GPU_R11F_G11F_B10F: + case GPU_DEPTH32F_STENCIL8: + case GPU_DEPTH24_STENCIL8: + case GPU_SRGB8_A8: + case GPU_RGBA8_SNORM: + case GPU_RGBA16_SNORM: + case GPU_RGB8UI: + case GPU_RGB8I: + case GPU_RGB8: + case GPU_RGB8_SNORM: + case GPU_RGB16UI: + case GPU_RGB16I: + case GPU_RGB16F: + case GPU_RGB16: + case GPU_RGB16_SNORM: + case GPU_RGB32UI: + case GPU_RGB32I: + case GPU_RGB32F: + case GPU_RG8_SNORM: + case GPU_RG16_SNORM: + case GPU_R8_SNORM: + case GPU_R16_SNORM: + case GPU_SRGB8_A8_DXT1: + case GPU_SRGB8_A8_DXT3: + case GPU_SRGB8_A8_DXT5: + case GPU_RGBA8_DXT1: + case GPU_RGBA8_DXT3: + case GPU_RGBA8_DXT5: + case GPU_SRGB8: + case GPU_RGB9_E5: + case GPU_DEPTH_COMPONENT32F: + case GPU_DEPTH_COMPONENT24: + case GPU_DEPTH_COMPONENT16: + return ConversionType::UNSUPPORTED; + } + return ConversionType::UNSUPPORTED; +} + ConversionType conversion_type_for_update(eGPUDataFormat host_format, eGPUTextureFormat device_format) { @@ -324,8 +409,9 @@ ConversionType conversion_type_for_update(eGPUDataFormat host_format, return type_of_conversion_int(device_format); case GPU_DATA_HALF_FLOAT: return type_of_conversion_half(device_format); - case GPU_DATA_UBYTE: + return type_of_conversion_ubyte(device_format); + case GPU_DATA_UINT_24_8: case GPU_DATA_10_11_11_REV: case GPU_DATA_2_10_10_10_REV: @@ -337,24 +423,33 @@ ConversionType conversion_type_for_update(eGPUDataFormat host_format, static ConversionType invert(ConversionType type) { +#define CASE_SINGLE(a, b) \ + case ConversionType::a##_TO_##b: \ + return ConversionType::b##_TO_##a; + +#define CASE_PAIR(a, b) \ + CASE_SINGLE(a, b) \ + CASE_SINGLE(b, a) + switch (type) { case ConversionType::PASS_THROUGH: return ConversionType::PASS_THROUGH; - case ConversionType::UI16_TO_UI32: - return ConversionType::UI32_TO_UI16; - case ConversionType::UI32_TO_UI16: - return ConversionType::UI16_TO_UI32; - - case ConversionType::FLOAT_TO_HALF: - return ConversionType::HALF_TO_FLOAT; - case ConversionType::HALF_TO_FLOAT: - return ConversionType::FLOAT_TO_HALF; + CASE_PAIR(FLOAT, UNORM8) + CASE_PAIR(FLOAT, SNORM8) + CASE_PAIR(UI32, UI16) + CASE_PAIR(I32, I16) + CASE_PAIR(UI32, UI8) + CASE_PAIR(I32, I8) + CASE_PAIR(FLOAT, HALF) case ConversionType::UNSUPPORTED: return ConversionType::UNSUPPORTED; } +#undef CASE_PAIR +#undef CASE_SINGLE + return ConversionType::UNSUPPORTED; } @@ -365,15 +460,169 @@ ConversionType conversion_type_for_read(eGPUDataFormat host_format, } /* Copy the contents of src to dst with out performing any actual conversion. */ -template +template void copy_unchecked(MutableSpan dst, Span src) { BLI_assert(src.size() == dst.size()); - for (SourceType index : IndexRange(src.size())) { + for (int64_t index : IndexRange(src.size())) { dst[index] = src[index]; } } +template +void copy_unchecked(void *dst_memory, + const void *src_memory, + eGPUTextureFormat device_format, + size_t sample_len) +{ + size_t total_components = to_component_len(device_format) * sample_len; + Span src = Span(static_cast(src_memory), + total_components); + MutableSpan dst = MutableSpan( + static_cast(dst_memory), total_components); + copy_unchecked(dst, src); +} + +/* Float <=> unsigned normalized */ +static uint8_t clamp_unorm(int32_t unclamped) +{ + if (unclamped < 0.0f) { + return 0; + } + if (unclamped > 255.0f) { + return 255; + } + return uint8_t(unclamped); +} + +template +static DestinationType to_unorm(SourceType value) +{ + return (clamp_unorm((value * 255.0f))); +} + +template +static DestinationType from_unorm(SourceType value) +{ + return DestinationType(value / 255.0f); +} + +template +void float_to_unorm(MutableSpan dst, Span src) +{ + BLI_assert(src.size() == dst.size()); + for (int64_t index : IndexRange(src.size())) { + dst[index] = to_unorm(src[index]); + } +} + +template +void float_to_unorm(void *dst_memory, + const void *src_memory, + eGPUTextureFormat device_format, + size_t sample_len) +{ + size_t total_components = to_component_len(device_format) * sample_len; + Span src = Span(static_cast(src_memory), + total_components); + MutableSpan dst = MutableSpan( + static_cast(dst_memory), total_components); + float_to_unorm(dst, src); +} + +template +void unorm_to_float(MutableSpan dst, Span src) +{ + BLI_assert(src.size() == dst.size()); + for (int64_t index : IndexRange(src.size())) { + dst[index] = from_unorm(src[index]); + } +} + +template +void unorm_to_float(void *dst_memory, + const void *src_memory, + eGPUTextureFormat device_format, + size_t sample_len) +{ + size_t total_components = to_component_len(device_format) * sample_len; + Span src = Span(static_cast(src_memory), + total_components); + MutableSpan dst = MutableSpan( + static_cast(dst_memory), total_components); + unorm_to_float(dst, src); +} + +/* Float <=> signed normalized */ +static int8_t clamp_snorm(int32_t unclamped) +{ + if (unclamped < -127) { + return 0; + } + if (unclamped > 128) { + return 128; + } + return int8_t(unclamped); +} + +template +static DestinationType to_snorm(SourceType value) +{ + return (clamp_snorm((value * 128.0f))); +} + +template +static DestinationType from_snorm(SourceType value) +{ + return DestinationType(value / 128.0f); +} + +template +void float_to_snorm(MutableSpan dst, Span src) +{ + BLI_assert(src.size() == dst.size()); + for (int64_t index : IndexRange(src.size())) { + dst[index] = to_snorm(src[index]); + } +} + +template +void float_to_snorm(void *dst_memory, + const void *src_memory, + eGPUTextureFormat device_format, + size_t sample_len) +{ + size_t total_components = to_component_len(device_format) * sample_len; + Span src = Span(static_cast(src_memory), + total_components); + MutableSpan dst = MutableSpan( + static_cast(dst_memory), total_components); + float_to_snorm(dst, src); +} + +template +void snorm_to_float(MutableSpan dst, Span src) +{ + BLI_assert(src.size() == dst.size()); + for (int64_t index : IndexRange(src.size())) { + dst[index] = from_snorm(src[index]); + } +} + +template +void snorm_to_float(void *dst_memory, + const void *src_memory, + eGPUTextureFormat device_format, + size_t sample_len) +{ + size_t total_components = to_component_len(device_format) * sample_len; + Span src = Span(static_cast(src_memory), + total_components); + MutableSpan dst = MutableSpan( + static_cast(dst_memory), total_components); + snorm_to_float(dst, src); +} + void convert(ConversionType type, eGPUTextureFormat device_format, size_t sample_len, @@ -388,25 +637,51 @@ void convert(ConversionType type, memcpy(dst_memory, src_memory, sample_len * to_bytesize(device_format)); return; - case ConversionType::UI16_TO_UI32: { - size_t component_len = to_component_len(device_format) * sample_len; - Span src = Span(static_cast(src_memory), - component_len); - MutableSpan dst = MutableSpan(static_cast(dst_memory), - component_len); - copy_unchecked(dst, src); + case ConversionType::UI32_TO_UI16: + copy_unchecked(dst_memory, src_memory, device_format, sample_len); break; - } - case ConversionType::UI32_TO_UI16: { - size_t component_len = to_component_len(device_format) * sample_len; - Span src = Span(static_cast(src_memory), - component_len); - MutableSpan dst = MutableSpan(static_cast(dst_memory), - component_len); - copy_unchecked(dst, src); + case ConversionType::UI16_TO_UI32: + copy_unchecked(dst_memory, src_memory, device_format, sample_len); + break; + + case ConversionType::UI32_TO_UI8: + copy_unchecked(dst_memory, src_memory, device_format, sample_len); + break; + + case ConversionType::UI8_TO_UI32: + copy_unchecked(dst_memory, src_memory, device_format, sample_len); + break; + + case ConversionType::I32_TO_I16: + copy_unchecked(dst_memory, src_memory, device_format, sample_len); + break; + + case ConversionType::I16_TO_I32: + copy_unchecked(dst_memory, src_memory, device_format, sample_len); + break; + + case ConversionType::I32_TO_I8: + copy_unchecked(dst_memory, src_memory, device_format, sample_len); + break; + + case ConversionType::I8_TO_I32: + copy_unchecked(dst_memory, src_memory, device_format, sample_len); + break; + + case ConversionType::FLOAT_TO_UNORM8: + float_to_unorm(dst_memory, src_memory, device_format, sample_len); + break; + case ConversionType::UNORM8_TO_FLOAT: + unorm_to_float(dst_memory, src_memory, device_format, sample_len); + break; + + case ConversionType::FLOAT_TO_SNORM8: + float_to_snorm(dst_memory, src_memory, device_format, sample_len); + break; + case ConversionType::SNORM8_TO_FLOAT: + snorm_to_float(dst_memory, src_memory, device_format, sample_len); break; - } case ConversionType::FLOAT_TO_HALF: case ConversionType::HALF_TO_FLOAT: diff --git a/source/blender/gpu/vulkan/vk_data_conversion.hh b/source/blender/gpu/vulkan/vk_data_conversion.hh index 9406823f7b0..879572c2b68 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.hh +++ b/source/blender/gpu/vulkan/vk_data_conversion.hh @@ -16,17 +16,23 @@ enum class ConversionType { /** No conversion needed, result can be directly read back to host memory. */ PASS_THROUGH, - UI16_TO_UI32, - UI32_TO_UI16, + FLOAT_TO_UNORM8, + UNORM8_TO_FLOAT, - /* + FLOAT_TO_SNORM8, + SNORM8_TO_FLOAT, + + UI32_TO_UI16, + UI16_TO_UI32, + + UI32_TO_UI8, UI8_TO_UI32, + + I32_TO_I16, I16_TO_I32, + + I32_TO_I8, I8_TO_I32, - UI8_TO_I32, - UI8_TO_FLOAT, - UI8_TO_UBYTE, - */ /** Convert device 16F to floats. */ HALF_TO_FLOAT, diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index ba403a49426..ef8c903f839 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -149,7 +149,7 @@ void *VKTexture::read(int mip, eGPUDataFormat format) } void VKTexture::update_sub( - int mip, int /*offset*/[3], int extent[3], eGPUDataFormat format, const void *data) + int mip, int offset[3], int extent[3], eGPUDataFormat format, const void *data) { if (!is_allocated()) { allocate(); @@ -173,6 +173,9 @@ void VKTexture::update_sub( region.imageExtent.width = extent[0]; region.imageExtent.height = extent[1]; region.imageExtent.depth = extent[2]; + region.imageOffset.x = offset[0]; + region.imageOffset.y = offset[1]; + region.imageOffset.z = offset[2]; region.imageSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_); region.imageSubresource.mipLevel = mip; region.imageSubresource.layerCount = 1; @@ -180,8 +183,6 @@ void VKTexture::update_sub( VKCommandBuffer &command_buffer = context.command_buffer_get(); command_buffer.copy(*this, staging_buffer, Span(®ion, 1)); command_buffer.submit(); - - /* TODO: add support for offset. */ } void VKTexture::update_sub(int /*offset*/[3], @@ -244,7 +245,7 @@ bool VKTexture::allocate() image_info.samples = VK_SAMPLE_COUNT_1_BIT; VkResult result; - if (G.debug &= G_DEBUG_GPU) { + if (G.debug & G_DEBUG_GPU) { VkImageFormatProperties image_format = {}; result = vkGetPhysicalDeviceImageFormatProperties(context.physical_device_get(), image_info.format, -- 2.30.2 From 755a67776543b76bbe6e39540783df9fc252de4b Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 16 Mar 2023 18:01:00 +0100 Subject: [PATCH 05/15] Fixed SNORM/UNORM (precision and conversion) --- source/blender/gpu/tests/gpu_testing.cc | 2 +- source/blender/gpu/tests/texture_test.cc | 51 +++++++++- .../blender/gpu/vulkan/vk_data_conversion.cc | 97 ++++++++++++------- .../blender/gpu/vulkan/vk_data_conversion.hh | 6 ++ source/blender/gpu/vulkan/vk_texture.cc | 2 + 5 files changed, 119 insertions(+), 39 deletions(-) diff --git a/source/blender/gpu/tests/gpu_testing.cc b/source/blender/gpu/tests/gpu_testing.cc index fd28a18a24b..82c0154c148 100644 --- a/source/blender/gpu/tests/gpu_testing.cc +++ b/source/blender/gpu/tests/gpu_testing.cc @@ -17,7 +17,7 @@ void GPUTest::SetUp() GPU_backend_type_selection_set(gpu_backend_type); GHOST_GLSettings glSettings = {}; glSettings.context_type = draw_context_type; - glSettings.flags = GHOST_glDebugContext; + //glSettings.flags = GHOST_glDebugContext; CLG_init(); ghost_system = GHOST_CreateSystem(); ghost_context = GHOST_CreateOpenGLContext(ghost_system, glSettings); diff --git a/source/blender/gpu/tests/texture_test.cc b/source/blender/gpu/tests/texture_test.cc index 90460ef2eca..ad16801b320 100644 --- a/source/blender/gpu/tests/texture_test.cc +++ b/source/blender/gpu/tests/texture_test.cc @@ -10,6 +10,15 @@ #include "gpu_texture_private.hh" +/* Not all texture types are supported by all platforms. This define safe guards them until we have + * a working workaround or decided to remove support for those texture types. */ +#define RUN_UNSUPPORTED false +/* Skip tests that haven't been developed yet due to non standard data types. */ +#define RUN_16F_UNIMPLEMENTED false +#define RUN_SRGB_UNIMPLEMENTED false +#define RUN_NON_STANDARD_UNIMPLEMENTED false +#define RUN_COMPONENT_UNIMPLEMENTED false + namespace blender::gpu::tests { static void test_texture_read() @@ -53,7 +62,12 @@ template static DataType *generate_test_data(size_t data_len) { DataType *data = static_cast(MEM_mallocN(data_len * sizeof(DataType), __func__)); for (int i : IndexRange(data_len)) { - data[i] = (DataType)(i % 8); + if (std::is_same()) { + data[i] = (DataType)(i % 8) / 8.0f; + } + else { + data[i] = (DataType)(i % 8); + } } return data; } @@ -75,9 +89,14 @@ static void texture_create_upload_read() GPU_texture_update(texture, HostFormat, data); DataType *read_data = static_cast(GPU_texture_read(texture, HostFormat, 0)); + bool failed = false; for (int i : IndexRange(data_len)) { - EXPECT_EQ(read_data[i], data[i]); + bool ok = abs(read_data[i] - data[i]) < 0.01; + failed |= !ok; + //EXPECT_EQ(read_data[i], data[i]); } + EXPECT_FALSE(failed); + MEM_freeN(read_data); MEM_freeN(data); @@ -87,18 +106,19 @@ static void texture_create_upload_read() /* -------------------------------------------------------------------- */ /** \name Roundtrip testing GPU_DATA_FLOAT * \{ */ -#if 1 static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8() { texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8); +#if RUN_16F_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16F() { texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16F); +#endif static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16() { @@ -118,11 +138,13 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8() } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8); +#if RUN_16F_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16F() { texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16F); +#endif static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16() { @@ -142,11 +164,13 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R8() } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R8); +#if RUN_16F_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R16F() { texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R16F); +#endif static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R16() { @@ -160,6 +184,7 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R32F() } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R32F); +#if RUN_NON_STANDARD_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB10_A2() { texture_create_upload_read(); @@ -177,12 +202,15 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R11F_G11F_B10F() texture_create_upload_read(); } 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(); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8); +#endif static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_SNORM() { @@ -196,6 +224,7 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16_SNORM() } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16_SNORM); +#if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB8() { texture_create_upload_read(); @@ -207,19 +236,21 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB8_SNORM() texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB8_SNORM); +#endif +#if RUN_16F_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16F() { texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16F); - +#endif +#if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16() { texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16); - static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16_SNORM() { texture_create_upload_read(); @@ -231,6 +262,7 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB32F() texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB32F); +#endif static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8_SNORM() { @@ -256,6 +288,7 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R16_SNORM() } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R16_SNORM); +#if RUN_NON_STANDARD_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT1() { texture_create_upload_read(); @@ -291,25 +324,33 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT5() texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT5); +#endif +#if RUN_SRGB_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8() { texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8); +#endif +#if RUN_NON_STANDARD_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB9_E5() { texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB9_E5); +#endif +#if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT32F() { texture_create_upload_read(); } 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(); diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc index 21348a0e5a5..cda01b2c80e 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.cc +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -34,26 +34,34 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format) case GPU_R8_SNORM: return ConversionType::FLOAT_TO_SNORM8; + case GPU_RGBA16: + case GPU_RG16: + case GPU_R16: + return ConversionType::FLOAT_TO_UNORM16; + + case GPU_RGBA16_SNORM: + case GPU_RGB16_SNORM: + case GPU_RG16_SNORM: + case GPU_R16_SNORM: + return ConversionType::FLOAT_TO_SNORM16; + case GPU_RGB32F: /* GPU_RGB32F Not supported by vendors. */ case GPU_RGBA8UI: case GPU_RGBA8I: case GPU_RGBA16UI: case GPU_RGBA16I: - case GPU_RGBA16: case GPU_RGBA32UI: case GPU_RGBA32I: case GPU_RG8UI: case GPU_RG8I: case GPU_RG16UI: case GPU_RG16I: - case GPU_RG16: case GPU_RG32UI: case GPU_RG32I: case GPU_R8UI: case GPU_R8I: case GPU_R16UI: case GPU_R16I: - case GPU_R16: case GPU_R32UI: case GPU_R32I: case GPU_RGB10_A2: @@ -62,18 +70,14 @@ static ConversionType type_of_conversion_float(eGPUTextureFormat device_format) case GPU_DEPTH32F_STENCIL8: case GPU_DEPTH24_STENCIL8: case GPU_SRGB8_A8: - case GPU_RGBA16_SNORM: case GPU_RGB8UI: case GPU_RGB8I: case GPU_RGB8: case GPU_RGB16UI: case GPU_RGB16I: case GPU_RGB16: - case GPU_RGB16_SNORM: case GPU_RGB32UI: case GPU_RGB32I: - case GPU_RG16_SNORM: - case GPU_R16_SNORM: case GPU_SRGB8_A8_DXT1: case GPU_SRGB8_A8_DXT3: case GPU_SRGB8_A8_DXT5: @@ -437,6 +441,8 @@ static ConversionType invert(ConversionType type) CASE_PAIR(FLOAT, UNORM8) CASE_PAIR(FLOAT, SNORM8) + CASE_PAIR(FLOAT, UNORM16) + CASE_PAIR(FLOAT, SNORM16) CASE_PAIR(UI32, UI16) CASE_PAIR(I32, I16) CASE_PAIR(UI32, UI8) @@ -484,27 +490,38 @@ void copy_unchecked(void *dst_memory, } /* Float <=> unsigned normalized */ -static uint8_t clamp_unorm(int32_t unclamped) +template constexpr int32_t unorm_scalar() { - if (unclamped < 0.0f) { - return 0; - } - if (unclamped > 255.0f) { - return 255; - } - return uint8_t(unclamped); + return ((1 << (sizeof(Type) * 8)) - 1); +} +template constexpr int32_t snorm_scalar() +{ + return (1 << (sizeof(Type) * 8 - 1)); +} +template constexpr int32_t snorm_max() +{ + return ((1 << (sizeof(Type) * 8)) - 1); +} +template constexpr int32_t snorm_delta() +{ + return (1 << (sizeof(Type) * 8 - 1)) - 1; } template static DestinationType to_unorm(SourceType value) { - return (clamp_unorm((value * 255.0f))); + static constexpr int32_t Multiplier = unorm_scalar(); + static constexpr int32_t Max = Multiplier; + + int32_t before_clamping = value * Multiplier; + return clamp_i(before_clamping, 0, Max); } template static DestinationType from_unorm(SourceType value) { - return DestinationType(value / 255.0f); + static constexpr int32_t Multiplier = unorm_scalar(); + return DestinationType(value) / Multiplier; } template @@ -554,27 +571,23 @@ void unorm_to_float(void *dst_memory, } /* Float <=> signed normalized */ -static int8_t clamp_snorm(int32_t unclamped) -{ - if (unclamped < -127) { - return 0; - } - if (unclamped > 128) { - return 128; - } - return int8_t(unclamped); -} +/* TODO: SNORM needs to be shifted...*/ template static DestinationType to_snorm(SourceType value) { - return (clamp_snorm((value * 128.0f))); + static constexpr int32_t Multiplier = snorm_scalar(); + static constexpr int32_t Max = snorm_max(); + static constexpr int32_t Delta = snorm_delta(); + return (clamp_i((value * Multiplier + Delta), 0, Max)); } template static DestinationType from_snorm(SourceType value) { - return DestinationType(value / 128.0f); + static constexpr int32_t Multiplier = snorm_scalar(); + static constexpr int32_t Delta = snorm_delta(); + return DestinationType(int32_t(value) - Delta) / Multiplier; } template @@ -582,7 +595,9 @@ void float_to_snorm(MutableSpan dst, Span src) { BLI_assert(src.size() == dst.size()); for (int64_t index : IndexRange(src.size())) { - dst[index] = to_snorm(src[index]); + const SourceType src_value = src[index]; + const DestinationType dst_value = to_snorm(src_value); + dst[index] = dst_value; } } @@ -605,7 +620,9 @@ void snorm_to_float(MutableSpan dst, Span src) { BLI_assert(src.size() == dst.size()); for (int64_t index : IndexRange(src.size())) { - dst[index] = from_snorm(src[index]); + const SourceType src_value = src[index]; + const DestinationType dst_value = from_snorm(src_value); + dst[index] = dst_value; } } @@ -677,10 +694,24 @@ void convert(ConversionType type, break; case ConversionType::FLOAT_TO_SNORM8: - float_to_snorm(dst_memory, src_memory, device_format, sample_len); + float_to_snorm(dst_memory, src_memory, device_format, sample_len); break; case ConversionType::SNORM8_TO_FLOAT: - snorm_to_float(dst_memory, src_memory, device_format, sample_len); + snorm_to_float(dst_memory, src_memory, device_format, sample_len); + break; + + case ConversionType::FLOAT_TO_UNORM16: + float_to_unorm(dst_memory, src_memory, device_format, sample_len); + break; + case ConversionType::UNORM16_TO_FLOAT: + unorm_to_float(dst_memory, src_memory, device_format, sample_len); + break; + + case ConversionType::FLOAT_TO_SNORM16: + float_to_snorm(dst_memory, src_memory, device_format, sample_len); + break; + case ConversionType::SNORM16_TO_FLOAT: + snorm_to_float(dst_memory, src_memory, device_format, sample_len); break; case ConversionType::FLOAT_TO_HALF: diff --git a/source/blender/gpu/vulkan/vk_data_conversion.hh b/source/blender/gpu/vulkan/vk_data_conversion.hh index 879572c2b68..f02a5a3468b 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.hh +++ b/source/blender/gpu/vulkan/vk_data_conversion.hh @@ -22,6 +22,12 @@ enum class ConversionType { FLOAT_TO_SNORM8, SNORM8_TO_FLOAT, + FLOAT_TO_UNORM16, + UNORM16_TO_FLOAT, + + FLOAT_TO_SNORM16, + SNORM16_TO_FLOAT, + UI32_TO_UI16, UI16_TO_UI32, diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index ef8c903f839..69ec9acb917 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -203,6 +203,8 @@ bool VKTexture::init_internal() /* Initialization can only happen after the usage is known. By the current API this isn't set * at this moment, so we cannot initialize here. The initialization is postponed until the * allocation of the texture on the device. */ + + /* TODO: return false when texture format isn't supported. */ return true; } -- 2.30.2 From 42420b3d8c4694be6042f181704aa1c7181e8c91 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Mar 2023 08:17:34 +0100 Subject: [PATCH 06/15] Enabled half_float tests. --- source/blender/gpu/tests/texture_test.cc | 22 ++++++++++--------- .../blender/gpu/vulkan/vk_data_conversion.cc | 8 ++++--- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/source/blender/gpu/tests/texture_test.cc b/source/blender/gpu/tests/texture_test.cc index ad16801b320..8eb11182c97 100644 --- a/source/blender/gpu/tests/texture_test.cc +++ b/source/blender/gpu/tests/texture_test.cc @@ -93,7 +93,7 @@ static void texture_create_upload_read() for (int i : IndexRange(data_len)) { bool ok = abs(read_data[i] - data[i]) < 0.01; failed |= !ok; - //EXPECT_EQ(read_data[i], data[i]); + // EXPECT_EQ(read_data[i], data[i]); } EXPECT_FALSE(failed); @@ -245,6 +245,7 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16F() } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16F); #endif + #if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16() { @@ -363,36 +364,39 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT16() } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT16); #endif + /* \} */ /* -------------------------------------------------------------------- */ /** \name Roundtrip testing GPU_DATA_HALF_FLOAT * \{ */ -#if 0 + static void test_texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RGBA16F() { - texture_create_upload_read(); + texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RGBA16F); static void test_texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RG16F() { - texture_create_upload_read(); + texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RG16F); static void test_texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_R16F() { - texture_create_upload_read(); + texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_R16F); +#if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RGB16F() { - texture_create_upload_read(); + texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RGB16F); #endif + /* \} */ /* -------------------------------------------------------------------- */ @@ -433,9 +437,7 @@ static void test_texture_roundtrip__GPU_DATA_INT__GPU_RG32I() { texture_create_upload_read(); } -GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RG32I); - -static void test_texture_roundtrip__GPU_DATA_INT__GPU_R8I() +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RG32I);test_texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8_A8 { texture_create_upload_read(); } @@ -708,7 +710,7 @@ GPU_TEST(texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2UI); return std::string("float"); case GPU_DATA_HALF_FLOAT: - return std::string("half"); + return std::string("uint16_t"); case GPU_DATA_INT: return std::string("int32_t"); case GPU_DATA_UINT: diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc index cda01b2c80e..575e7693df4 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.cc +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -254,12 +254,16 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format) static ConversionType type_of_conversion_half(eGPUTextureFormat device_format) { switch (device_format) { + case GPU_RGBA16F: + case GPU_RG16F: + case GPU_R16F: + return ConversionType::PASS_THROUGH; + case GPU_RGBA8UI: case GPU_RGBA8I: case GPU_RGBA8: case GPU_RGBA16UI: case GPU_RGBA16I: - case GPU_RGBA16F: case GPU_RGBA16: case GPU_RGBA32UI: case GPU_RGBA32I: @@ -269,7 +273,6 @@ static ConversionType type_of_conversion_half(eGPUTextureFormat device_format) case GPU_RG8: case GPU_RG16UI: case GPU_RG16I: - case GPU_RG16F: case GPU_RG16: case GPU_RG32UI: case GPU_RG32I: @@ -279,7 +282,6 @@ static ConversionType type_of_conversion_half(eGPUTextureFormat device_format) case GPU_R8: case GPU_R16UI: case GPU_R16I: - case GPU_R16F: case GPU_R16: case GPU_R32UI: case GPU_R32I: -- 2.30.2 From 12a6b1914d944fb35bb27fd90a621d0426ad45cb Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Mar 2023 08:49:41 +0100 Subject: [PATCH 07/15] Hide internals of data conversion for quicker development. --- .../blender/gpu/vulkan/vk_data_conversion.cc | 145 +++++++++++++----- .../blender/gpu/vulkan/vk_data_conversion.hh | 85 +++++----- source/blender/gpu/vulkan/vk_texture.cc | 14 +- 3 files changed, 142 insertions(+), 102 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc index 575e7693df4..a86783e50fb 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.cc +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -8,6 +8,48 @@ #include "vk_data_conversion.hh" namespace blender::gpu { + +/* -------------------------------------------------------------------- */ +/** \name Conversion types + * \{ */ +enum class ConversionType { + /** No conversion needed, result can be directly read back to host memory. */ + PASS_THROUGH, + + FLOAT_TO_UNORM8, + UNORM8_TO_FLOAT, + + FLOAT_TO_SNORM8, + SNORM8_TO_FLOAT, + + FLOAT_TO_UNORM16, + UNORM16_TO_FLOAT, + + FLOAT_TO_SNORM16, + SNORM16_TO_FLOAT, + + UI32_TO_UI16, + UI16_TO_UI32, + + UI32_TO_UI8, + UI8_TO_UI32, + + I32_TO_I16, + I16_TO_I32, + + I32_TO_I8, + I8_TO_I32, + + /** Convert device 16F to floats. */ + HALF_TO_FLOAT, + FLOAT_TO_HALF, + + /** + * The requested conversion isn't supported. + */ + UNSUPPORTED, +}; + static ConversionType type_of_conversion_float(eGPUTextureFormat device_format) { switch (device_format) { @@ -401,8 +443,7 @@ static ConversionType type_of_conversion_ubyte(eGPUTextureFormat device_format) return ConversionType::UNSUPPORTED; } -ConversionType conversion_type_for_update(eGPUDataFormat host_format, - eGPUTextureFormat device_format) +static ConversionType host_to_device(eGPUDataFormat host_format, eGPUTextureFormat device_format) { BLI_assert(validate_data_format(device_format, host_format)); @@ -427,7 +468,7 @@ ConversionType conversion_type_for_update(eGPUDataFormat host_format, return ConversionType::UNSUPPORTED; } -static ConversionType invert(ConversionType type) +static ConversionType reversed(ConversionType type) { #define CASE_SINGLE(a, b) \ case ConversionType::a##_TO_##b: \ @@ -461,11 +502,7 @@ static ConversionType invert(ConversionType type) return ConversionType::UNSUPPORTED; } -ConversionType conversion_type_for_read(eGPUDataFormat host_format, - eGPUTextureFormat device_format) -{ - return invert(conversion_type_for_update(host_format, device_format)); -} +/* \} */ /* Copy the contents of src to dst with out performing any actual conversion. */ template @@ -481,9 +518,9 @@ template void copy_unchecked(void *dst_memory, const void *src_memory, eGPUTextureFormat device_format, - size_t sample_len) + size_t buffer_size) { - size_t total_components = to_component_len(device_format) * sample_len; + size_t total_components = to_component_len(device_format) * buffer_size; Span src = Span(static_cast(src_memory), total_components); MutableSpan dst = MutableSpan( @@ -539,9 +576,9 @@ template void float_to_unorm(void *dst_memory, const void *src_memory, eGPUTextureFormat device_format, - size_t sample_len) + size_t buffer_size) { - size_t total_components = to_component_len(device_format) * sample_len; + size_t total_components = to_component_len(device_format) * buffer_size; Span src = Span(static_cast(src_memory), total_components); MutableSpan dst = MutableSpan( @@ -562,9 +599,9 @@ template void unorm_to_float(void *dst_memory, const void *src_memory, eGPUTextureFormat device_format, - size_t sample_len) + size_t buffer_size) { - size_t total_components = to_component_len(device_format) * sample_len; + size_t total_components = to_component_len(device_format) * buffer_size; Span src = Span(static_cast(src_memory), total_components); MutableSpan dst = MutableSpan( @@ -607,9 +644,9 @@ template void float_to_snorm(void *dst_memory, const void *src_memory, eGPUTextureFormat device_format, - size_t sample_len) + size_t buffer_size) { - size_t total_components = to_component_len(device_format) * sample_len; + size_t total_components = to_component_len(device_format) * buffer_size; Span src = Span(static_cast(src_memory), total_components); MutableSpan dst = MutableSpan( @@ -632,9 +669,9 @@ template void snorm_to_float(void *dst_memory, const void *src_memory, eGPUTextureFormat device_format, - size_t sample_len) + size_t buffer_size) { - size_t total_components = to_component_len(device_format) * sample_len; + size_t total_components = to_component_len(device_format) * buffer_size; Span src = Span(static_cast(src_memory), total_components); MutableSpan dst = MutableSpan( @@ -642,78 +679,78 @@ void snorm_to_float(void *dst_memory, snorm_to_float(dst, src); } -void convert(ConversionType type, - eGPUTextureFormat device_format, - size_t sample_len, - void *dst_memory, - const void *src_memory) +static void convert_buffer(void *dst_memory, + const void *src_memory, + size_t buffer_size, + eGPUTextureFormat device_format, + ConversionType type) { switch (type) { case ConversionType::UNSUPPORTED: return; case ConversionType::PASS_THROUGH: - memcpy(dst_memory, src_memory, sample_len * to_bytesize(device_format)); + memcpy(dst_memory, src_memory, buffer_size * to_bytesize(device_format)); return; case ConversionType::UI32_TO_UI16: - copy_unchecked(dst_memory, src_memory, device_format, sample_len); + copy_unchecked(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::UI16_TO_UI32: - copy_unchecked(dst_memory, src_memory, device_format, sample_len); + copy_unchecked(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::UI32_TO_UI8: - copy_unchecked(dst_memory, src_memory, device_format, sample_len); + copy_unchecked(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::UI8_TO_UI32: - copy_unchecked(dst_memory, src_memory, device_format, sample_len); + copy_unchecked(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::I32_TO_I16: - copy_unchecked(dst_memory, src_memory, device_format, sample_len); + copy_unchecked(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::I16_TO_I32: - copy_unchecked(dst_memory, src_memory, device_format, sample_len); + copy_unchecked(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::I32_TO_I8: - copy_unchecked(dst_memory, src_memory, device_format, sample_len); + copy_unchecked(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::I8_TO_I32: - copy_unchecked(dst_memory, src_memory, device_format, sample_len); + copy_unchecked(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::FLOAT_TO_UNORM8: - float_to_unorm(dst_memory, src_memory, device_format, sample_len); + float_to_unorm(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::UNORM8_TO_FLOAT: - unorm_to_float(dst_memory, src_memory, device_format, sample_len); + unorm_to_float(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::FLOAT_TO_SNORM8: - float_to_snorm(dst_memory, src_memory, device_format, sample_len); + float_to_snorm(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::SNORM8_TO_FLOAT: - snorm_to_float(dst_memory, src_memory, device_format, sample_len); + snorm_to_float(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::FLOAT_TO_UNORM16: - float_to_unorm(dst_memory, src_memory, device_format, sample_len); + float_to_unorm(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::UNORM16_TO_FLOAT: - unorm_to_float(dst_memory, src_memory, device_format, sample_len); + unorm_to_float(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::FLOAT_TO_SNORM16: - float_to_snorm(dst_memory, src_memory, device_format, sample_len); + float_to_snorm(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::SNORM16_TO_FLOAT: - snorm_to_float(dst_memory, src_memory, device_format, sample_len); + snorm_to_float(dst_memory, src_memory, device_format, buffer_size); break; case ConversionType::FLOAT_TO_HALF: @@ -723,4 +760,32 @@ void convert(ConversionType type, } } +/* -------------------------------------------------------------------- */ +/** \name API + * \{ */ + +void convert_host_to_device(void *dst_buffer, + const void *src_buffer, + size_t buffer_size, + eGPUDataFormat host_format, + eGPUTextureFormat device_format) +{ + ConversionType conversion_type = host_to_device(host_format, device_format); + BLI_assert(conversion_type != ConversionType::UNSUPPORTED); + convert_buffer(dst_buffer, src_buffer, buffer_size, device_format, conversion_type); +} + +void convert_device_to_host(void *dst_buffer, + const void *src_buffer, + size_t buffer_size, + eGPUDataFormat host_format, + eGPUTextureFormat device_format) +{ + ConversionType conversion_type = reversed(host_to_device(host_format, device_format)); + BLI_assert(conversion_type != ConversionType::UNSUPPORTED); + convert_buffer(dst_buffer, src_buffer, buffer_size, device_format, conversion_type); +} + +/* \} */ + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_data_conversion.hh b/source/blender/gpu/vulkan/vk_data_conversion.hh index f02a5a3468b..800389ff44e 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.hh +++ b/source/blender/gpu/vulkan/vk_data_conversion.hh @@ -12,57 +12,42 @@ namespace blender::gpu { -enum class ConversionType { - /** No conversion needed, result can be directly read back to host memory. */ - PASS_THROUGH, - - FLOAT_TO_UNORM8, - UNORM8_TO_FLOAT, - - FLOAT_TO_SNORM8, - SNORM8_TO_FLOAT, - - FLOAT_TO_UNORM16, - UNORM16_TO_FLOAT, - - FLOAT_TO_SNORM16, - SNORM16_TO_FLOAT, - - UI32_TO_UI16, - UI16_TO_UI32, - - UI32_TO_UI8, - UI8_TO_UI32, - - I32_TO_I16, - I16_TO_I32, - - I32_TO_I8, - I8_TO_I32, - - /** Convert device 16F to floats. */ - HALF_TO_FLOAT, - FLOAT_TO_HALF, - - /** - * The requested conversion isn't supported. - */ - UNSUPPORTED, -}; +/** + * Convert host buffer to device buffer. + * + * \param dst_buffer: device buffer. + * \param src_buffer: host buffer. + * \param buffer_size: number of pixels to convert from the start of the given buffer. + * \param host_format: format of the host buffer + * \param device_format: format of the device buffer. + * + * \note Will assert when the host_format/device_format combination isn't valid + * (#validate_data_format) or supported. Some combinations aren't supported in Vulkan due to + * platform incompatibility. + */ +void convert_host_to_device(void *dst_buffer, + const void *src_buffer, + size_t buffer_size, + eGPUDataFormat host_format, + eGPUTextureFormat device_format); /** - * Determine the type of conversion that is needed to read back data from GPU device to host - * memory. + * Convert device buffer to host buffer. + * + * \param dst_buffer: host buffer + * \param src_buffer: device buffer. + * \param buffer_size: number of pixels to convert from the start of the given buffer. + * \param host_format: format of the host buffer + * \param device_format: format of the device buffer. + * + * \note Will assert when the host_format/device_format combination isn't valid + * (#validate_data_format) or supported. Some combinations aren't supported in Vulkan due to + * platform incompatibility. */ -ConversionType conversion_type_for_read(eGPUDataFormat host_format, - eGPUTextureFormat device_format); -ConversionType conversion_type_for_update(eGPUDataFormat host_format, - eGPUTextureFormat device_format); +void convert_device_to_host(void *dst_buffer, + const void *src_buffer, + size_t buffer_size, + eGPUDataFormat host_format, + eGPUTextureFormat device_format); -void convert(ConversionType type, - eGPUTextureFormat device_format, - size_t sample_len, - void *dst_memory, - const void *src_memory); - -}; // namespace blender::gpu +}; // namespace blender::gpu \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index 69ec9acb917..e7cbf9c7183 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -138,13 +138,7 @@ void *VKTexture::read(int mip, eGPUDataFormat format) command_buffer.submit(); void *data = MEM_mallocN(host_memory_size, __func__); - - /* Convert data from device to host memory. */ - ConversionType conversion_type = conversion_type_for_read(format, format_); - BLI_assert_msg(conversion_type != ConversionType::UNSUPPORTED, - "Memory data conversions not implemented yet"); - convert(conversion_type, format_, sample_len, data, staging_buffer.mapped_memory_get()); - + convert_device_to_host(data, staging_buffer.mapped_memory_get(), sample_len, format, format_); return data; } @@ -163,11 +157,7 @@ void VKTexture::update_sub( staging_buffer.create( context, device_memory_size, GPU_USAGE_DEVICE_ONLY, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); - - ConversionType conversion_type = conversion_type_for_update(format, format_); - BLI_assert_msg(conversion_type != ConversionType::UNSUPPORTED, - "Memory data conversions not implemented yet"); - convert(conversion_type, format_, sample_len, staging_buffer.mapped_memory_get(), data); + convert_host_to_device(staging_buffer.mapped_memory_get(), data, sample_len, format, format_); VkBufferImageCopy region = {}; region.imageExtent.width = extent[0]; -- 2.30.2 From e7ae0a5dfc07a40380c41988cbaba06f0251ab8a Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Mar 2023 10:27:00 +0100 Subject: [PATCH 08/15] Reduce complexity by introducing data types. --- .../blender/gpu/vulkan/vk_data_conversion.cc | 326 ++++++++---------- 1 file changed, 141 insertions(+), 185 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc index a86783e50fb..de4b02cc55a 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.cc +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -12,6 +12,7 @@ namespace blender::gpu { /* -------------------------------------------------------------------- */ /** \name Conversion types * \{ */ + enum class ConversionType { /** No conversion needed, result can be directly read back to host memory. */ PASS_THROUGH, @@ -504,179 +505,126 @@ static ConversionType reversed(ConversionType type) /* \} */ -/* Copy the contents of src to dst with out performing any actual conversion. */ +/* -------------------------------------------------------------------- */ +/** \name Data Conversion + * \{ */ + +template struct SignedNormalized { + static_assert(std::is_same() || std::is_same()); + InnerType value; + + static constexpr int32_t scalar() + { + return (1 << (sizeof(InnerType) * 8 - 1)); + } + + static constexpr int32_t delta() + { + return (1 << (sizeof(InnerType) * 8 - 1)) - 1; + } + + static constexpr int32_t max() + { + return ((1 << (sizeof(InnerType) * 8)) - 1); + } +}; + +template struct UnsignedNormalized { + static_assert(std::is_same() || std::is_same()); + InnerType value; + + static constexpr int32_t scalar() + { + return (1 << (sizeof(InnerType) * 8)) - 1; + } + + static constexpr int32_t max() + { + return ((1 << (sizeof(InnerType) * 8)) - 1); + } +}; + +template struct ComponentValue { + InnerType value; +}; + +using F32 = ComponentValue; +using UI8 = ComponentValue; +using UI16 = ComponentValue; +using UI32 = ComponentValue; +using I8 = ComponentValue; +using I16 = ComponentValue; +using I32 = ComponentValue; + +template +void convert_component(SignedNormalized &dst, const F32 &src) +{ + static constexpr int32_t scalar = SignedNormalized::scalar(); + static constexpr int32_t delta = SignedNormalized::delta(); + static constexpr int32_t max = SignedNormalized::max(); + dst.value = (clamp_i((src.value * scalar + delta), 0, max)); +} + +template +void convert_component(F32 &dst, const SignedNormalized &src) +{ + static constexpr int32_t scalar = SignedNormalized::scalar(); + static constexpr int32_t delta = SignedNormalized::delta(); + dst.value = float(int32_t(src.value) - delta) / scalar; +} + +template +void convert_component(UnsignedNormalized &dst, const F32 &src) +{ + static constexpr int32_t scalar = UnsignedNormalized::scalar(); + static constexpr int32_t max = scalar; + dst.value = (clamp_i((src.value * scalar), 0, max)); +} + +template +void convert_component(F32 &dst, const UnsignedNormalized &src) +{ + static constexpr int32_t scalar = UnsignedNormalized::scalar(); + dst.value = float(src.value) / scalar; +} + +/* Copy the contents of src to dst with out performing any actual conversion.*/ template -void copy_unchecked(MutableSpan dst, Span src) +void convert_component(DestinationType &dst, const SourceType &src) +{ + static_assert(std::is_same() || std::is_same() || + std::is_same() || std::is_same() || + std::is_same() || std::is_same()); + static_assert(std::is_same() || std::is_same() || + std::is_same() || std::is_same() || + std::is_same() || std::is_same()); + static_assert(!std::is_same()); + dst.value = src.value; +} + +/* \} */ + +template +void convert_per_component(MutableSpan dst, Span src) { BLI_assert(src.size() == dst.size()); for (int64_t index : IndexRange(src.size())) { - dst[index] = src[index]; + convert_component(dst[index], src[index]); } } template -void copy_unchecked(void *dst_memory, - const void *src_memory, - eGPUTextureFormat device_format, - size_t buffer_size) +void convert_per_component(void *dst_memory, + const void *src_memory, + size_t buffer_size, + eGPUTextureFormat device_format) { size_t total_components = to_component_len(device_format) * buffer_size; Span src = Span(static_cast(src_memory), total_components); MutableSpan dst = MutableSpan( static_cast(dst_memory), total_components); - copy_unchecked(dst, src); -} - -/* Float <=> unsigned normalized */ -template constexpr int32_t unorm_scalar() -{ - return ((1 << (sizeof(Type) * 8)) - 1); -} -template constexpr int32_t snorm_scalar() -{ - return (1 << (sizeof(Type) * 8 - 1)); -} -template constexpr int32_t snorm_max() -{ - return ((1 << (sizeof(Type) * 8)) - 1); -} -template constexpr int32_t snorm_delta() -{ - return (1 << (sizeof(Type) * 8 - 1)) - 1; -} - -template -static DestinationType to_unorm(SourceType value) -{ - static constexpr int32_t Multiplier = unorm_scalar(); - static constexpr int32_t Max = Multiplier; - - int32_t before_clamping = value * Multiplier; - return clamp_i(before_clamping, 0, Max); -} - -template -static DestinationType from_unorm(SourceType value) -{ - static constexpr int32_t Multiplier = unorm_scalar(); - return DestinationType(value) / Multiplier; -} - -template -void float_to_unorm(MutableSpan dst, Span src) -{ - BLI_assert(src.size() == dst.size()); - for (int64_t index : IndexRange(src.size())) { - dst[index] = to_unorm(src[index]); - } -} - -template -void float_to_unorm(void *dst_memory, - const void *src_memory, - eGPUTextureFormat device_format, - size_t buffer_size) -{ - size_t total_components = to_component_len(device_format) * buffer_size; - Span src = Span(static_cast(src_memory), - total_components); - MutableSpan dst = MutableSpan( - static_cast(dst_memory), total_components); - float_to_unorm(dst, src); -} - -template -void unorm_to_float(MutableSpan dst, Span src) -{ - BLI_assert(src.size() == dst.size()); - for (int64_t index : IndexRange(src.size())) { - dst[index] = from_unorm(src[index]); - } -} - -template -void unorm_to_float(void *dst_memory, - const void *src_memory, - eGPUTextureFormat device_format, - size_t buffer_size) -{ - size_t total_components = to_component_len(device_format) * buffer_size; - Span src = Span(static_cast(src_memory), - total_components); - MutableSpan dst = MutableSpan( - static_cast(dst_memory), total_components); - unorm_to_float(dst, src); -} - -/* Float <=> signed normalized */ - -/* TODO: SNORM needs to be shifted...*/ -template -static DestinationType to_snorm(SourceType value) -{ - static constexpr int32_t Multiplier = snorm_scalar(); - static constexpr int32_t Max = snorm_max(); - static constexpr int32_t Delta = snorm_delta(); - return (clamp_i((value * Multiplier + Delta), 0, Max)); -} - -template -static DestinationType from_snorm(SourceType value) -{ - static constexpr int32_t Multiplier = snorm_scalar(); - static constexpr int32_t Delta = snorm_delta(); - return DestinationType(int32_t(value) - Delta) / Multiplier; -} - -template -void float_to_snorm(MutableSpan dst, Span src) -{ - BLI_assert(src.size() == dst.size()); - for (int64_t index : IndexRange(src.size())) { - const SourceType src_value = src[index]; - const DestinationType dst_value = to_snorm(src_value); - dst[index] = dst_value; - } -} - -template -void float_to_snorm(void *dst_memory, - const void *src_memory, - eGPUTextureFormat device_format, - size_t buffer_size) -{ - size_t total_components = to_component_len(device_format) * buffer_size; - Span src = Span(static_cast(src_memory), - total_components); - MutableSpan dst = MutableSpan( - static_cast(dst_memory), total_components); - float_to_snorm(dst, src); -} - -template -void snorm_to_float(MutableSpan dst, Span src) -{ - BLI_assert(src.size() == dst.size()); - for (int64_t index : IndexRange(src.size())) { - const SourceType src_value = src[index]; - const DestinationType dst_value = from_snorm(src_value); - dst[index] = dst_value; - } -} - -template -void snorm_to_float(void *dst_memory, - const void *src_memory, - eGPUTextureFormat device_format, - size_t buffer_size) -{ - size_t total_components = to_component_len(device_format) * buffer_size; - Span src = Span(static_cast(src_memory), - total_components); - MutableSpan dst = MutableSpan( - static_cast(dst_memory), total_components); - snorm_to_float(dst, src); + convert_per_component(dst, src); } static void convert_buffer(void *dst_memory, @@ -694,63 +642,71 @@ static void convert_buffer(void *dst_memory, return; case ConversionType::UI32_TO_UI16: - copy_unchecked(dst_memory, src_memory, device_format, buffer_size); + convert_per_component(dst_memory, src_memory, buffer_size, device_format); break; case ConversionType::UI16_TO_UI32: - copy_unchecked(dst_memory, src_memory, device_format, buffer_size); + convert_per_component(dst_memory, src_memory, buffer_size, device_format); break; case ConversionType::UI32_TO_UI8: - copy_unchecked(dst_memory, src_memory, device_format, buffer_size); + convert_per_component(dst_memory, src_memory, buffer_size, device_format); break; case ConversionType::UI8_TO_UI32: - copy_unchecked(dst_memory, src_memory, device_format, buffer_size); + convert_per_component(dst_memory, src_memory, buffer_size, device_format); break; case ConversionType::I32_TO_I16: - copy_unchecked(dst_memory, src_memory, device_format, buffer_size); + convert_per_component(dst_memory, src_memory, buffer_size, device_format); break; case ConversionType::I16_TO_I32: - copy_unchecked(dst_memory, src_memory, device_format, buffer_size); + convert_per_component(dst_memory, src_memory, buffer_size, device_format); break; case ConversionType::I32_TO_I8: - copy_unchecked(dst_memory, src_memory, device_format, buffer_size); + convert_per_component(dst_memory, src_memory, buffer_size, device_format); break; case ConversionType::I8_TO_I32: - copy_unchecked(dst_memory, src_memory, device_format, buffer_size); - break; - - case ConversionType::FLOAT_TO_UNORM8: - float_to_unorm(dst_memory, src_memory, device_format, buffer_size); - break; - case ConversionType::UNORM8_TO_FLOAT: - unorm_to_float(dst_memory, src_memory, device_format, buffer_size); + convert_per_component(dst_memory, src_memory, buffer_size, device_format); break; case ConversionType::FLOAT_TO_SNORM8: - float_to_snorm(dst_memory, src_memory, device_format, buffer_size); + convert_per_component, F32>( + dst_memory, src_memory, buffer_size, device_format); break; case ConversionType::SNORM8_TO_FLOAT: - snorm_to_float(dst_memory, src_memory, device_format, buffer_size); - break; - - case ConversionType::FLOAT_TO_UNORM16: - float_to_unorm(dst_memory, src_memory, device_format, buffer_size); - break; - case ConversionType::UNORM16_TO_FLOAT: - unorm_to_float(dst_memory, src_memory, device_format, buffer_size); + convert_per_component>( + dst_memory, src_memory, buffer_size, device_format); break; case ConversionType::FLOAT_TO_SNORM16: - float_to_snorm(dst_memory, src_memory, device_format, buffer_size); + convert_per_component, F32>( + dst_memory, src_memory, buffer_size, device_format); break; case ConversionType::SNORM16_TO_FLOAT: - snorm_to_float(dst_memory, src_memory, device_format, buffer_size); + convert_per_component>( + dst_memory, src_memory, buffer_size, device_format); + break; + + case ConversionType::FLOAT_TO_UNORM8: + convert_per_component, F32>( + dst_memory, src_memory, buffer_size, device_format); + break; + case ConversionType::UNORM8_TO_FLOAT: + convert_per_component>( + dst_memory, src_memory, buffer_size, device_format); + break; + + case ConversionType::FLOAT_TO_UNORM16: + convert_per_component, F32>( + dst_memory, src_memory, buffer_size, device_format); + break; + case ConversionType::UNORM16_TO_FLOAT: + convert_per_component>( + dst_memory, src_memory, buffer_size, device_format); break; case ConversionType::FLOAT_TO_HALF: -- 2.30.2 From e75a754065eaf265aa835b31dbd5e17deb0f51ce Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Mar 2023 11:20:56 +0100 Subject: [PATCH 09/15] Enabled most tests. --- source/blender/gpu/tests/texture_test.cc | 336 ++++++++++-------- .../blender/gpu/vulkan/vk_data_conversion.cc | 28 +- 2 files changed, 201 insertions(+), 163 deletions(-) diff --git a/source/blender/gpu/tests/texture_test.cc b/source/blender/gpu/tests/texture_test.cc index 8eb11182c97..368488df106 100644 --- a/source/blender/gpu/tests/texture_test.cc +++ b/source/blender/gpu/tests/texture_test.cc @@ -13,7 +13,8 @@ /* Not all texture types are supported by all platforms. This define safe guards them until we have * a working workaround or decided to remove support for those texture types. */ #define RUN_UNSUPPORTED false -/* Skip tests that haven't been developed yet due to non standard data types. */ +/* Skip tests that haven't been developed yet due to non standard data types or it needs an + * framebuffer to create the texture.. */ #define RUN_16F_UNIMPLEMENTED false #define RUN_SRGB_UNIMPLEMENTED false #define RUN_NON_STANDARD_UNIMPLEMENTED false @@ -82,7 +83,7 @@ static void texture_create_upload_read() eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; GPUTexture *texture = GPU_texture_create_2d( "texture", Size, Size, 1, DeviceFormat, usage, nullptr); - EXPECT_NE(texture, nullptr); + ASSERT_NE(texture, nullptr); size_t data_len = Size * Size * to_component_len(DeviceFormat); DataType *data = static_cast(generate_test_data(data_len)); @@ -91,8 +92,14 @@ static void texture_create_upload_read() DataType *read_data = static_cast(GPU_texture_read(texture, HostFormat, 0)); bool failed = false; for (int i : IndexRange(data_len)) { - bool ok = abs(read_data[i] - data[i]) < 0.01; - failed |= !ok; + if constexpr (std::is_same_v) { + bool ok = abs(read_data[i] - data[i]) < 0.01; + failed |= !ok; + } + else { + bool ok = (read_data[i] - data[i]) == 0; + failed |= !ok; + } // EXPECT_EQ(read_data[i], data[i]); } EXPECT_FALSE(failed); @@ -402,7 +409,7 @@ GPU_TEST(texture_roundtrip__GPU_DATA_HALF_FLOAT__GPU_RGB16F); /* -------------------------------------------------------------------- */ /** \name Roundtrip testing GPU_DATA_INT * \{ */ -#if 0 + static void test_texture_roundtrip__GPU_DATA_INT__GPU_RGBA8I() { texture_create_upload_read(); @@ -437,7 +444,9 @@ static void test_texture_roundtrip__GPU_DATA_INT__GPU_RG32I() { texture_create_upload_read(); } -GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RG32I);test_texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8_A8 +GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RG32I); + +static void test_texture_roundtrip__GPU_DATA_INT__GPU_R8I() { texture_create_upload_read(); } @@ -455,6 +464,7 @@ static void test_texture_roundtrip__GPU_DATA_INT__GPU_R32I() } GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_R32I); +#if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_INT__GPU_RGB8I() { texture_create_upload_read(); @@ -473,12 +483,13 @@ static void test_texture_roundtrip__GPU_DATA_INT__GPU_RGB32I() } GPU_TEST(texture_roundtrip__GPU_DATA_INT__GPU_RGB32I); #endif + /* \} */ /* -------------------------------------------------------------------- */ /** \name Roundtrip testing GPU_DATA_UINT * \{ */ -#if 0 + static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGBA8UI() { texture_create_upload_read(); @@ -533,6 +544,7 @@ static void test_texture_roundtrip__GPU_DATA_UINT__GPU_R32UI() } GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_R32UI); +#if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH32F_STENCIL8() { texture_create_upload_read(); @@ -544,7 +556,9 @@ static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH24_STENCIL8() texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH24_STENCIL8); +#endif +#if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGB8UI() { texture_create_upload_read(); @@ -562,7 +576,9 @@ static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGB32UI() texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_RGB32UI); +#endif +#if RUN_COMPONENT_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT32F() { texture_create_upload_read(); @@ -581,12 +597,13 @@ static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT16() } GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT16); #endif + /* \} */ /* -------------------------------------------------------------------- */ /** \name Roundtrip testing GPU_DATA_UBYTE * \{ */ -#if 0 + static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_RGBA8UI() { texture_create_upload_read(); @@ -623,12 +640,15 @@ static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_R8() } GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_R8); +#if RUN_SRGB_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8_A8() { texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8_A8); +#endif +#if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_RGB8I() { texture_create_upload_read(); @@ -652,7 +672,8 @@ GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8); /* -------------------------------------------------------------------- */ /** \name Roundtrip testing GPU_DATA_UINT_24_8 * \{ */ -#if 0 + +#if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_UINT_24_8__GPU_DEPTH32F_STENCIL8() { texture_create_upload_read(); @@ -665,35 +686,36 @@ static void test_texture_roundtrip__GPU_DATA_UINT_24_8__GPU_DEPTH24_STENCIL8() } GPU_TEST(texture_roundtrip__GPU_DATA_UINT_24_8__GPU_DEPTH24_STENCIL8); #endif + /* \} */ /* -------------------------------------------------------------------- */ /** \name Roundtrip testing GPU_DATA_10_11_11_REV * \{ */ -#if 0 + static void test_texture_roundtrip__GPU_DATA_10_11_11_REV__GPU_R11F_G11F_B10F() { - texture_create_upload_read(); + texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_10_11_11_REV__GPU_R11F_G11F_B10F); -#endif + /* \} */ /* -------------------------------------------------------------------- */ /** \name Roundtrip testing GPU_DATA_2_10_10_10_REV * \{ */ -#if 0 + static void test_texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2() { - texture_create_upload_read(); + texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2); static void test_texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2UI() { - texture_create_upload_read(); + texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2UI); -#endif + /* \} */ /* -------------------------------------------------------------------- */ @@ -703,160 +725,158 @@ GPU_TEST(texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2UI); * * \{ */ #if 0 - static std::string to_prim_type_string(eGPUDataFormat host_format) - { - switch (host_format) { - case GPU_DATA_FLOAT: - return std::string("float"); +static std::string to_prim_type_string(eGPUDataFormat host_format) +{ + switch (host_format) { + case GPU_DATA_FLOAT: + return std::string("float"); - case GPU_DATA_HALF_FLOAT: - return std::string("uint16_t"); - case GPU_DATA_INT: - return std::string("int32_t"); - case GPU_DATA_UINT: - return std::string("uint32_t"); - case GPU_DATA_UBYTE: - return std::string("uint8_t"); - case GPU_DATA_UINT_24_8: - case GPU_DATA_10_11_11_REV: - case GPU_DATA_2_10_10_10_REV: - return std::string("void"); - } - return std::string("UNKNOWN"); + case GPU_DATA_HALF_FLOAT: + return std::string("uint16_t"); + case GPU_DATA_INT: + return std::string("int32_t"); + case GPU_DATA_UBYTE: + return std::string("uint8_t"); + case GPU_DATA_UINT: + case GPU_DATA_UINT_24_8: + case GPU_DATA_10_11_11_REV: + case GPU_DATA_2_10_10_10_REV: + return std::string("uint32_t"); } - static std::string to_string(eGPUDataFormat host_format) - { - switch (host_format) { - case GPU_DATA_FLOAT: - return std::string("GPU_DATA_FLOAT"); + return std::string("UNKNOWN"); +} +static std::string to_string(eGPUDataFormat host_format) +{ + switch (host_format) { + case GPU_DATA_FLOAT: + return std::string("GPU_DATA_FLOAT"); - case GPU_DATA_HALF_FLOAT: - return std::string("GPU_DATA_HALF_FLOAT"); - case GPU_DATA_INT: - return std::string("GPU_DATA_INT"); - case GPU_DATA_UINT: - return std::string("GPU_DATA_UINT"); - case GPU_DATA_UBYTE: - return std::string("GPU_DATA_UBYTE"); - case GPU_DATA_UINT_24_8: - return std::string("GPU_DATA_UINT_24_8"); - case GPU_DATA_10_11_11_REV: - return std::string("GPU_DATA_10_11_11_REV"); - case GPU_DATA_2_10_10_10_REV: - return std::string("GPU_DATA_2_10_10_10_REV"); - } - return std::string("UNKNOWN"); + case GPU_DATA_HALF_FLOAT: + return std::string("GPU_DATA_HALF_FLOAT"); + case GPU_DATA_INT: + return std::string("GPU_DATA_INT"); + case GPU_DATA_UINT: + return std::string("GPU_DATA_UINT"); + case GPU_DATA_UBYTE: + return std::string("GPU_DATA_UBYTE"); + case GPU_DATA_UINT_24_8: + return std::string("GPU_DATA_UINT_24_8"); + case GPU_DATA_10_11_11_REV: + return std::string("GPU_DATA_10_11_11_REV"); + case GPU_DATA_2_10_10_10_REV: + return std::string("GPU_DATA_2_10_10_10_REV"); } + return std::string("UNKNOWN"); +} - static std::string to_string(eGPUTextureFormat texture_format) - { - return std::string("GPU_") + std::string(GPU_texture_format_name(texture_format)); - } +static std::string to_string(eGPUTextureFormat texture_format) +{ + return std::string("GPU_") + std::string(GPU_texture_format_name(texture_format)); +} - TEST(gpu_util, generate_test_cases) - { - Vector host_formats; - host_formats.append(GPU_DATA_FLOAT); - host_formats.append(GPU_DATA_HALF_FLOAT); - host_formats.append(GPU_DATA_INT); - host_formats.append(GPU_DATA_UINT); - host_formats.append(GPU_DATA_UBYTE); - host_formats.append(GPU_DATA_UINT_24_8); - host_formats.append(GPU_DATA_10_11_11_REV); - host_formats.append(GPU_DATA_2_10_10_10_REV); +TEST(gpu_util, generate_test_cases) +{ + Vector host_formats; + host_formats.append(GPU_DATA_FLOAT); + host_formats.append(GPU_DATA_HALF_FLOAT); + host_formats.append(GPU_DATA_INT); + host_formats.append(GPU_DATA_UINT); + host_formats.append(GPU_DATA_UBYTE); + host_formats.append(GPU_DATA_UINT_24_8); + host_formats.append(GPU_DATA_10_11_11_REV); + host_formats.append(GPU_DATA_2_10_10_10_REV); - Vector texture_formats; - texture_formats.append(GPU_RGBA8UI); - texture_formats.append(GPU_RGBA8I); - texture_formats.append(GPU_RGBA8); - texture_formats.append(GPU_RGBA16UI); - texture_formats.append(GPU_RGBA16I); - texture_formats.append(GPU_RGBA16F); - texture_formats.append(GPU_RGBA16); - texture_formats.append(GPU_RGBA32UI); - texture_formats.append(GPU_RGBA32I); - texture_formats.append(GPU_RGBA32F); - texture_formats.append(GPU_RG8UI); - texture_formats.append(GPU_RG8I); - texture_formats.append(GPU_RG8); - texture_formats.append(GPU_RG16UI); - texture_formats.append(GPU_RG16I); - texture_formats.append(GPU_RG16F); - texture_formats.append(GPU_RG16); - texture_formats.append(GPU_RG32UI); - texture_formats.append(GPU_RG32I); - texture_formats.append(GPU_RG32F); - texture_formats.append(GPU_R8UI); - texture_formats.append(GPU_R8I); - texture_formats.append(GPU_R8); - texture_formats.append(GPU_R16UI); - texture_formats.append(GPU_R16I); - texture_formats.append(GPU_R16F); - texture_formats.append(GPU_R16); - texture_formats.append(GPU_R32UI); - texture_formats.append(GPU_R32I); - texture_formats.append(GPU_R32F); - texture_formats.append(GPU_RGB10_A2); - texture_formats.append(GPU_RGB10_A2UI); - texture_formats.append(GPU_R11F_G11F_B10F); - texture_formats.append(GPU_DEPTH32F_STENCIL8); - texture_formats.append(GPU_DEPTH24_STENCIL8); - texture_formats.append(GPU_SRGB8_A8); - texture_formats.append(GPU_RGBA8_SNORM); - texture_formats.append(GPU_RGBA16_SNORM); - texture_formats.append(GPU_RGB8UI); - texture_formats.append(GPU_RGB8I); - texture_formats.append(GPU_RGB8); - texture_formats.append(GPU_RGB8_SNORM); - texture_formats.append(GPU_RGB16UI); - texture_formats.append(GPU_RGB16I); - texture_formats.append(GPU_RGB16F); - texture_formats.append(GPU_RGB16); - texture_formats.append(GPU_RGB16_SNORM); - texture_formats.append(GPU_RGB32UI); - texture_formats.append(GPU_RGB32I); - texture_formats.append(GPU_RGB32F); - texture_formats.append(GPU_RG8_SNORM); - texture_formats.append(GPU_RG16_SNORM); - texture_formats.append(GPU_R8_SNORM); - texture_formats.append(GPU_R16_SNORM); - texture_formats.append(GPU_SRGB8_A8_DXT1); - texture_formats.append(GPU_SRGB8_A8_DXT3); - texture_formats.append(GPU_SRGB8_A8_DXT5); - texture_formats.append(GPU_RGBA8_DXT1); - texture_formats.append(GPU_RGBA8_DXT3); - texture_formats.append(GPU_RGBA8_DXT5); - texture_formats.append(GPU_SRGB8); - texture_formats.append(GPU_RGB9_E5); - texture_formats.append(GPU_DEPTH_COMPONENT32F); - texture_formats.append(GPU_DEPTH_COMPONENT24); - texture_formats.append(GPU_DEPTH_COMPONENT16); + Vector texture_formats; + texture_formats.append(GPU_RGBA8UI); + texture_formats.append(GPU_RGBA8I); + texture_formats.append(GPU_RGBA8); + texture_formats.append(GPU_RGBA16UI); + texture_formats.append(GPU_RGBA16I); + texture_formats.append(GPU_RGBA16F); + texture_formats.append(GPU_RGBA16); + texture_formats.append(GPU_RGBA32UI); + texture_formats.append(GPU_RGBA32I); + texture_formats.append(GPU_RGBA32F); + texture_formats.append(GPU_RG8UI); + texture_formats.append(GPU_RG8I); + texture_formats.append(GPU_RG8); + texture_formats.append(GPU_RG16UI); + texture_formats.append(GPU_RG16I); + texture_formats.append(GPU_RG16F); + texture_formats.append(GPU_RG16); + texture_formats.append(GPU_RG32UI); + texture_formats.append(GPU_RG32I); + texture_formats.append(GPU_RG32F); + texture_formats.append(GPU_R8UI); + texture_formats.append(GPU_R8I); + texture_formats.append(GPU_R8); + texture_formats.append(GPU_R16UI); + texture_formats.append(GPU_R16I); + texture_formats.append(GPU_R16F); + texture_formats.append(GPU_R16); + texture_formats.append(GPU_R32UI); + texture_formats.append(GPU_R32I); + texture_formats.append(GPU_R32F); + texture_formats.append(GPU_RGB10_A2); + texture_formats.append(GPU_RGB10_A2UI); + texture_formats.append(GPU_R11F_G11F_B10F); + texture_formats.append(GPU_DEPTH32F_STENCIL8); + texture_formats.append(GPU_DEPTH24_STENCIL8); + texture_formats.append(GPU_SRGB8_A8); + texture_formats.append(GPU_RGBA8_SNORM); + texture_formats.append(GPU_RGBA16_SNORM); + texture_formats.append(GPU_RGB8UI); + texture_formats.append(GPU_RGB8I); + texture_formats.append(GPU_RGB8); + texture_formats.append(GPU_RGB8_SNORM); + texture_formats.append(GPU_RGB16UI); + texture_formats.append(GPU_RGB16I); + texture_formats.append(GPU_RGB16F); + texture_formats.append(GPU_RGB16); + texture_formats.append(GPU_RGB16_SNORM); + texture_formats.append(GPU_RGB32UI); + texture_formats.append(GPU_RGB32I); + texture_formats.append(GPU_RGB32F); + texture_formats.append(GPU_RG8_SNORM); + texture_formats.append(GPU_RG16_SNORM); + texture_formats.append(GPU_R8_SNORM); + texture_formats.append(GPU_R16_SNORM); + texture_formats.append(GPU_SRGB8_A8_DXT1); + texture_formats.append(GPU_SRGB8_A8_DXT3); + texture_formats.append(GPU_SRGB8_A8_DXT5); + texture_formats.append(GPU_RGBA8_DXT1); + texture_formats.append(GPU_RGBA8_DXT3); + texture_formats.append(GPU_RGBA8_DXT5); + texture_formats.append(GPU_SRGB8); + texture_formats.append(GPU_RGB9_E5); + texture_formats.append(GPU_DEPTH_COMPONENT32F); + texture_formats.append(GPU_DEPTH_COMPONENT24); + texture_formats.append(GPU_DEPTH_COMPONENT16); - for (eGPUDataFormat host_format : host_formats) { - std::cout << "/* -------------------------------------------------------------------- */\n"; - std::cout << "/** \\name Roundtrip testing " << to_string(host_format) << "\n"; - std::cout << " * \\{ */\n\n"; + for (eGPUDataFormat host_format : host_formats) { + std::cout << "/* -------------------------------------------------------------------- */\n"; + std::cout << "/** \\name Roundtrip testing " << to_string(host_format) << "\n"; + std::cout << " * \\{ */\n\n"; - for (eGPUTextureFormat texture_format : texture_formats) { - if (!validate_data_format(texture_format, host_format)) { - continue; - } - - std::cout << "static void test_texture_roundtrip__" << to_string(host_format) << "__" - << to_string(texture_format) << "()\n"; - std::cout << "{\n"; - - std::cout << " texture_create_upload_read<" << to_string(texture_format) << ", " - << to_string(host_format) << ", " << to_prim_type_string(host_format) - << ">();\n"; - - std::cout << "}\n"; - std::cout << "GPU_TEST(texture_roundtrip__" << to_string(host_format) << "__" - << to_string(texture_format) << ");\n\n"; + for (eGPUTextureFormat texture_format : texture_formats) { + if (!validate_data_format(texture_format, host_format)) { + continue; } - std::cout << "/* \\} */\n\n"; + + std::cout << "static void test_texture_roundtrip__" << to_string(host_format) << "__" + << to_string(texture_format) << "()\n"; + std::cout << "{\n"; + + std::cout << " texture_create_upload_read<" << to_string(texture_format) << ", " + << to_string(host_format) << ", " << to_prim_type_string(host_format) << ">();\n"; + + std::cout << "}\n"; + std::cout << "GPU_TEST(texture_roundtrip__" << to_string(host_format) << "__" + << to_string(texture_format) << ");\n\n"; } + std::cout << "/* \\} */\n\n"; } +} #endif /** \} */ diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc index de4b02cc55a..4e908d9e9ac 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.cc +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -373,12 +373,14 @@ static ConversionType type_of_conversion_ubyte(eGPUTextureFormat device_format) { switch (device_format) { case GPU_RGBA8UI: + case GPU_RGBA8: case GPU_RG8UI: + case GPU_RG8: case GPU_R8UI: + case GPU_R8: return ConversionType::PASS_THROUGH; case GPU_RGBA8I: - case GPU_RGBA8: case GPU_RGBA16UI: case GPU_RGBA16I: case GPU_RGBA16F: @@ -387,7 +389,6 @@ static ConversionType type_of_conversion_ubyte(eGPUTextureFormat device_format) case GPU_RGBA32I: case GPU_RGBA32F: case GPU_RG8I: - case GPU_RG8: case GPU_RG16UI: case GPU_RG16I: case GPU_RG16F: @@ -396,7 +397,6 @@ static ConversionType type_of_conversion_ubyte(eGPUTextureFormat device_format) case GPU_RG32I: case GPU_RG32F: case GPU_R8I: - case GPU_R8: case GPU_R16UI: case GPU_R16I: case GPU_R16F: @@ -444,6 +444,22 @@ static ConversionType type_of_conversion_ubyte(eGPUTextureFormat device_format) return ConversionType::UNSUPPORTED; } +static ConversionType type_of_conversion_r11g11b10(eGPUTextureFormat device_format) +{ + if (device_format == GPU_R11F_G11F_B10F) { + return ConversionType::PASS_THROUGH; + } + return ConversionType::UNSUPPORTED; +} + +static ConversionType type_of_conversion_r10g10b10a2(eGPUTextureFormat device_format) +{ + if (ELEM(device_format, GPU_RGB10_A2, GPU_RGB10_A2UI)) { + return ConversionType::PASS_THROUGH; + } + return ConversionType::UNSUPPORTED; +} + static ConversionType host_to_device(eGPUDataFormat host_format, eGPUTextureFormat device_format) { BLI_assert(validate_data_format(device_format, host_format)); @@ -459,10 +475,12 @@ static ConversionType host_to_device(eGPUDataFormat host_format, eGPUTextureForm return type_of_conversion_half(device_format); case GPU_DATA_UBYTE: return type_of_conversion_ubyte(device_format); + case GPU_DATA_10_11_11_REV: + return type_of_conversion_r11g11b10(device_format); + case GPU_DATA_2_10_10_10_REV: + return type_of_conversion_r10g10b10a2(device_format); case GPU_DATA_UINT_24_8: - case GPU_DATA_10_11_11_REV: - case GPU_DATA_2_10_10_10_REV: return ConversionType::UNSUPPORTED; } -- 2.30.2 From df0e20cae95f039ae6a5b871a8ddbac3d0bb0bd6 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Mar 2023 12:34:49 +0100 Subject: [PATCH 10/15] Added support for F16. --- source/blender/gpu/tests/texture_test.cc | 175 +++++++++++------- .../blender/gpu/vulkan/vk_data_conversion.cc | 100 +++++++++- 2 files changed, 203 insertions(+), 72 deletions(-) diff --git a/source/blender/gpu/tests/texture_test.cc b/source/blender/gpu/tests/texture_test.cc index 368488df106..978b05cc729 100644 --- a/source/blender/gpu/tests/texture_test.cc +++ b/source/blender/gpu/tests/texture_test.cc @@ -13,9 +13,9 @@ /* Not all texture types are supported by all platforms. This define safe guards them until we have * a working workaround or decided to remove support for those texture types. */ #define RUN_UNSUPPORTED false + /* Skip tests that haven't been developed yet due to non standard data types or it needs an - * framebuffer to create the texture.. */ -#define RUN_16F_UNIMPLEMENTED false + * framebuffer to create the texture. */ #define RUN_SRGB_UNIMPLEMENTED false #define RUN_NON_STANDARD_UNIMPLEMENTED false #define RUN_COMPONENT_UNIMPLEMENTED false @@ -79,6 +79,7 @@ template static void texture_create_upload_read() { + static_assert(!std::is_same()); static_assert(validate_data_format(DeviceFormat, HostFormat)); eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; GPUTexture *texture = GPU_texture_create_2d( @@ -92,15 +93,65 @@ static void texture_create_upload_read() DataType *read_data = static_cast(GPU_texture_read(texture, HostFormat, 0)); bool failed = false; for (int i : IndexRange(data_len)) { - if constexpr (std::is_same_v) { - bool ok = abs(read_data[i] - data[i]) < 0.01; - failed |= !ok; - } - else { - bool ok = (read_data[i] - data[i]) == 0; - failed |= !ok; - } - // EXPECT_EQ(read_data[i], data[i]); + bool ok = (read_data[i] - data[i]) == 0; + failed |= !ok; + } + EXPECT_FALSE(failed); + + MEM_freeN(read_data); + MEM_freeN(data); + + GPU_texture_free(texture); +} + +template +static void texture_create_upload_read_with_bias(float max_allowed_bias) +{ + static_assert(validate_data_format(DeviceFormat, HostFormat)); + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; + GPUTexture *texture = GPU_texture_create_2d( + "texture", Size, Size, 1, DeviceFormat, usage, nullptr); + ASSERT_NE(texture, nullptr); + + size_t data_len = Size * Size * to_component_len(DeviceFormat); + float *data = static_cast(generate_test_data(data_len)); + GPU_texture_update(texture, HostFormat, data); + + float *read_data = static_cast(GPU_texture_read(texture, HostFormat, 0)); + float max_used_bias = 0.0f; + for (int i : IndexRange(data_len)) { + float bias = abs(read_data[i] - data[i]); + max_used_bias = max_ff(max_used_bias, bias); + } + EXPECT_LE(max_used_bias, max_allowed_bias); + + MEM_freeN(read_data); + MEM_freeN(data); + + GPU_texture_free(texture); +} + +/* Derivative of texture_create_upload_read_pixels that doesn't test each component, but a pixel at + * a time. This is needed to check the R11G11B10 and similar types. */ +template +static void texture_create_upload_read_pixel() +{ + using DataType = uint32_t; + static_assert(validate_data_format(DeviceFormat, HostFormat)); + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; + GPUTexture *texture = GPU_texture_create_2d( + "texture", Size, Size, 1, DeviceFormat, usage, nullptr); + ASSERT_NE(texture, nullptr); + + size_t data_len = Size * Size; + DataType *data = static_cast(generate_test_data(data_len)); + GPU_texture_update(texture, HostFormat, data); + + DataType *read_data = static_cast(GPU_texture_read(texture, HostFormat, 0)); + bool failed = false; + for (int i : IndexRange(data_len)) { + bool ok = (read_data[i] - data[i]) == 0; + failed |= !ok; } EXPECT_FALSE(failed); @@ -115,98 +166,92 @@ static void texture_create_upload_read() * \{ */ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.004f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8); -#if RUN_16F_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16F() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.9f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16F); -#endif static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.00002f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA32F() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA32F); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.004f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8); -#if RUN_16F_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16F() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.9f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16F); -#endif static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.00002f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG32F() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG32F); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R8() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.004f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R8); -#if RUN_16F_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R16F() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.9f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R16F); -#endif static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R16() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.00002f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R16); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R32F() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R32F); #if RUN_NON_STANDARD_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB10_A2() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB10_A2); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB10_A2UI() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB10_A2UI); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R11F_G11F_B10F() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R11F_G11F_B10F); #endif @@ -214,122 +259,118 @@ GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R11F_G11F_B10F); #if RUN_SRGB_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8); #endif static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_SNORM() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_SNORM); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16_SNORM() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16_SNORM); #if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB8() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB8); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB8_SNORM() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB8_SNORM); -#endif -#if RUN_16F_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16F() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16F); -#endif -#if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16_SNORM() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB16_SNORM); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB32F() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB32F); #endif static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8_SNORM() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8_SNORM); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16_SNORM() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16_SNORM); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R8_SNORM() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R8_SNORM); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R16_SNORM() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R16_SNORM); #if RUN_NON_STANDARD_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT1() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT1); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT3() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT3); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT5() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8_DXT5); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT1() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT1); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT3() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT3); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT5() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT5); #endif @@ -337,7 +378,7 @@ GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_DXT5); #if RUN_SRGB_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8); #endif @@ -345,7 +386,7 @@ GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8); #if RUN_NON_STANDARD_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB9_E5() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB9_E5); #endif @@ -353,7 +394,7 @@ GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB9_E5); #if RUN_UNSUPPORTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT32F() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT32F); #endif @@ -361,13 +402,13 @@ GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT32F); #if RUN_COMPONENT_UNIMPLEMENTED static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT24() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT24); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT16() { - texture_create_upload_read(); + texture_create_upload_read_with_bias(0.0f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT16); #endif @@ -695,7 +736,7 @@ GPU_TEST(texture_roundtrip__GPU_DATA_UINT_24_8__GPU_DEPTH24_STENCIL8); static void test_texture_roundtrip__GPU_DATA_10_11_11_REV__GPU_R11F_G11F_B10F() { - texture_create_upload_read(); + texture_create_upload_read(); } GPU_TEST(texture_roundtrip__GPU_DATA_10_11_11_REV__GPU_R11F_G11F_B10F); @@ -707,12 +748,13 @@ GPU_TEST(texture_roundtrip__GPU_DATA_10_11_11_REV__GPU_R11F_G11F_B10F); static void test_texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2() { - texture_create_upload_read(); + texture_create_upload_read_pixel(); } GPU_TEST(texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2); + static void test_texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2UI() { - texture_create_upload_read(); + texture_create_upload_read_pixel(); } GPU_TEST(texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2UI); @@ -730,17 +772,15 @@ static std::string to_prim_type_string(eGPUDataFormat host_format) switch (host_format) { case GPU_DATA_FLOAT: return std::string("float"); - case GPU_DATA_HALF_FLOAT: return std::string("uint16_t"); case GPU_DATA_INT: return std::string("int32_t"); case GPU_DATA_UBYTE: + case GPU_DATA_10_11_11_REV: return std::string("uint8_t"); case GPU_DATA_UINT: case GPU_DATA_UINT_24_8: - case GPU_DATA_10_11_11_REV: - case GPU_DATA_2_10_10_10_REV: return std::string("uint32_t"); } return std::string("UNKNOWN"); @@ -763,8 +803,6 @@ static std::string to_string(eGPUDataFormat host_format) return std::string("GPU_DATA_UINT_24_8"); case GPU_DATA_10_11_11_REV: return std::string("GPU_DATA_10_11_11_REV"); - case GPU_DATA_2_10_10_10_REV: - return std::string("GPU_DATA_2_10_10_10_REV"); } return std::string("UNKNOWN"); } @@ -784,7 +822,6 @@ TEST(gpu_util, generate_test_cases) host_formats.append(GPU_DATA_UBYTE); host_formats.append(GPU_DATA_UINT_24_8); host_formats.append(GPU_DATA_10_11_11_REV); - host_formats.append(GPU_DATA_2_10_10_10_REV); Vector texture_formats; texture_formats.append(GPU_RGBA8UI); diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc index 4e908d9e9ac..89511cb2fbf 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.cc +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -566,7 +566,6 @@ template struct ComponentValue { InnerType value; }; -using F32 = ComponentValue; using UI8 = ComponentValue; using UI16 = ComponentValue; using UI32 = ComponentValue; @@ -574,6 +573,25 @@ using I8 = ComponentValue; using I16 = ComponentValue; using I32 = ComponentValue; +union F32 { + uint32_t u; + float value; + struct { + uint Mantissa : 23; + uint Exponent : 8; + uint Sign : 1; + }; +}; + +union F16 { + uint16_t u; + struct { + uint Mantissa : 10; + uint Exponent : 5; + uint Sign : 1; + }; +}; + template void convert_component(SignedNormalized &dst, const F32 &src) { @@ -620,6 +638,80 @@ void convert_component(DestinationType &dst, const SourceType &src) dst.value = src.value; } +static F16 float_to_half(const F32 &value) +{ + F16 result; + /* Sign bit, shifted to its position. */ + uint sign_bit = value.u & 0x80000000; + sign_bit >>= 16; + /* Exponent. */ + uint exponent_bits = value.u & 0x7f800000; + /* Non-sign bits. */ + uint value_bits = value.u & 0x7fffffff; + value_bits >>= 13; /* Align mantissa on MSB. */ + value_bits -= 0x1c000; /* Adjust bias. */ + /* Flush-to-zero. */ + value_bits = (exponent_bits < 0x38800000) ? 0 : value_bits; + /* Clamp-to-max. */ + value_bits = (exponent_bits > 0x47000000) ? 0x7bff : value_bits; + /* Denormals-as-zero. */ + value_bits = (exponent_bits == 0 ? 0 : value_bits); + /* Re-insert sign bit and return. */ + result.u = (value_bits | sign_bit); + return result; +} + +static F32 half_to_float(const F16 &h) +{ + F32 o = {0}; + + // From ISPC ref code + if (h.Exponent == 0 && h.Mantissa == 0) // (Signed) zero + o.Sign = h.Sign; + else { + if (h.Exponent == 0) // Denormal (will convert to normalized) + { + // Adjust mantissa so it's normalized (and keep track of exp adjust) + int e = -1; + uint m = h.Mantissa; + do { + e++; + m <<= 1; + } while ((m & 0x400) == 0); + + o.Mantissa = (m & 0x3ff) << 13; + o.Exponent = 127 - 15 - e; + o.Sign = h.Sign; + } + else if (h.Exponent == 0x1f) // Inf/NaN + { + // NOTE: It's safe to treat both with the same code path by just truncating + // lower Mantissa bits in NaNs (this is valid). + o.Mantissa = h.Mantissa << 13; + o.Exponent = 255; + o.Sign = h.Sign; + } + else // Normalized number + { + o.Mantissa = h.Mantissa << 13; + o.Exponent = 127 - 15 + h.Exponent; + o.Sign = h.Sign; + } + } + + return o; +} + +static void convert_component(F16 &dst, const F32 &src) +{ + dst = float_to_half(src); +} + +static void convert_component(F32 &dst, const F16 &src) +{ + dst = half_to_float(src); +} + /* \} */ template @@ -728,9 +820,11 @@ static void convert_buffer(void *dst_memory, break; case ConversionType::FLOAT_TO_HALF: + convert_per_component(dst_memory, src_memory, buffer_size, device_format); + break; case ConversionType::HALF_TO_FLOAT: - BLI_assert_unreachable(); - return; + convert_per_component(dst_memory, src_memory, buffer_size, device_format); + break; } } -- 2.30.2 From 478be6712b2511562b72b73055441dbfcf12ebfb Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Mar 2023 12:40:24 +0100 Subject: [PATCH 11/15] Cleanup. --- source/blender/gpu/tests/gpu_testing.cc | 2 +- source/blender/gpu/tests/texture_test.cc | 159 +---------------------- 2 files changed, 2 insertions(+), 159 deletions(-) diff --git a/source/blender/gpu/tests/gpu_testing.cc b/source/blender/gpu/tests/gpu_testing.cc index 82c0154c148..fd28a18a24b 100644 --- a/source/blender/gpu/tests/gpu_testing.cc +++ b/source/blender/gpu/tests/gpu_testing.cc @@ -17,7 +17,7 @@ void GPUTest::SetUp() GPU_backend_type_selection_set(gpu_backend_type); GHOST_GLSettings glSettings = {}; glSettings.context_type = draw_context_type; - //glSettings.flags = GHOST_glDebugContext; + glSettings.flags = GHOST_glDebugContext; CLG_init(); ghost_system = GHOST_CreateSystem(); ghost_context = GHOST_CreateOpenGLContext(ghost_system, glSettings); diff --git a/source/blender/gpu/tests/texture_test.cc b/source/blender/gpu/tests/texture_test.cc index 978b05cc729..38677c7f121 100644 --- a/source/blender/gpu/tests/texture_test.cc +++ b/source/blender/gpu/tests/texture_test.cc @@ -760,161 +760,4 @@ GPU_TEST(texture_roundtrip__GPU_DATA_2_10_10_10_REV__GPU_RGB10_A2UI); /* \} */ -/* -------------------------------------------------------------------- */ -/** \name Generate test cases. - * - * Next section is kept for convenience to regenerate test cases. - * - * \{ */ -#if 0 -static std::string to_prim_type_string(eGPUDataFormat host_format) -{ - switch (host_format) { - case GPU_DATA_FLOAT: - return std::string("float"); - case GPU_DATA_HALF_FLOAT: - return std::string("uint16_t"); - case GPU_DATA_INT: - return std::string("int32_t"); - case GPU_DATA_UBYTE: - case GPU_DATA_10_11_11_REV: - return std::string("uint8_t"); - case GPU_DATA_UINT: - case GPU_DATA_UINT_24_8: - return std::string("uint32_t"); - } - return std::string("UNKNOWN"); -} -static std::string to_string(eGPUDataFormat host_format) -{ - switch (host_format) { - case GPU_DATA_FLOAT: - return std::string("GPU_DATA_FLOAT"); - - case GPU_DATA_HALF_FLOAT: - return std::string("GPU_DATA_HALF_FLOAT"); - case GPU_DATA_INT: - return std::string("GPU_DATA_INT"); - case GPU_DATA_UINT: - return std::string("GPU_DATA_UINT"); - case GPU_DATA_UBYTE: - return std::string("GPU_DATA_UBYTE"); - case GPU_DATA_UINT_24_8: - return std::string("GPU_DATA_UINT_24_8"); - case GPU_DATA_10_11_11_REV: - return std::string("GPU_DATA_10_11_11_REV"); - } - return std::string("UNKNOWN"); -} - -static std::string to_string(eGPUTextureFormat texture_format) -{ - return std::string("GPU_") + std::string(GPU_texture_format_name(texture_format)); -} - -TEST(gpu_util, generate_test_cases) -{ - Vector host_formats; - host_formats.append(GPU_DATA_FLOAT); - host_formats.append(GPU_DATA_HALF_FLOAT); - host_formats.append(GPU_DATA_INT); - host_formats.append(GPU_DATA_UINT); - host_formats.append(GPU_DATA_UBYTE); - host_formats.append(GPU_DATA_UINT_24_8); - host_formats.append(GPU_DATA_10_11_11_REV); - - Vector texture_formats; - texture_formats.append(GPU_RGBA8UI); - texture_formats.append(GPU_RGBA8I); - texture_formats.append(GPU_RGBA8); - texture_formats.append(GPU_RGBA16UI); - texture_formats.append(GPU_RGBA16I); - texture_formats.append(GPU_RGBA16F); - texture_formats.append(GPU_RGBA16); - texture_formats.append(GPU_RGBA32UI); - texture_formats.append(GPU_RGBA32I); - texture_formats.append(GPU_RGBA32F); - texture_formats.append(GPU_RG8UI); - texture_formats.append(GPU_RG8I); - texture_formats.append(GPU_RG8); - texture_formats.append(GPU_RG16UI); - texture_formats.append(GPU_RG16I); - texture_formats.append(GPU_RG16F); - texture_formats.append(GPU_RG16); - texture_formats.append(GPU_RG32UI); - texture_formats.append(GPU_RG32I); - texture_formats.append(GPU_RG32F); - texture_formats.append(GPU_R8UI); - texture_formats.append(GPU_R8I); - texture_formats.append(GPU_R8); - texture_formats.append(GPU_R16UI); - texture_formats.append(GPU_R16I); - texture_formats.append(GPU_R16F); - texture_formats.append(GPU_R16); - texture_formats.append(GPU_R32UI); - texture_formats.append(GPU_R32I); - texture_formats.append(GPU_R32F); - texture_formats.append(GPU_RGB10_A2); - texture_formats.append(GPU_RGB10_A2UI); - texture_formats.append(GPU_R11F_G11F_B10F); - texture_formats.append(GPU_DEPTH32F_STENCIL8); - texture_formats.append(GPU_DEPTH24_STENCIL8); - texture_formats.append(GPU_SRGB8_A8); - texture_formats.append(GPU_RGBA8_SNORM); - texture_formats.append(GPU_RGBA16_SNORM); - texture_formats.append(GPU_RGB8UI); - texture_formats.append(GPU_RGB8I); - texture_formats.append(GPU_RGB8); - texture_formats.append(GPU_RGB8_SNORM); - texture_formats.append(GPU_RGB16UI); - texture_formats.append(GPU_RGB16I); - texture_formats.append(GPU_RGB16F); - texture_formats.append(GPU_RGB16); - texture_formats.append(GPU_RGB16_SNORM); - texture_formats.append(GPU_RGB32UI); - texture_formats.append(GPU_RGB32I); - texture_formats.append(GPU_RGB32F); - texture_formats.append(GPU_RG8_SNORM); - texture_formats.append(GPU_RG16_SNORM); - texture_formats.append(GPU_R8_SNORM); - texture_formats.append(GPU_R16_SNORM); - texture_formats.append(GPU_SRGB8_A8_DXT1); - texture_formats.append(GPU_SRGB8_A8_DXT3); - texture_formats.append(GPU_SRGB8_A8_DXT5); - texture_formats.append(GPU_RGBA8_DXT1); - texture_formats.append(GPU_RGBA8_DXT3); - texture_formats.append(GPU_RGBA8_DXT5); - texture_formats.append(GPU_SRGB8); - texture_formats.append(GPU_RGB9_E5); - texture_formats.append(GPU_DEPTH_COMPONENT32F); - texture_formats.append(GPU_DEPTH_COMPONENT24); - texture_formats.append(GPU_DEPTH_COMPONENT16); - - for (eGPUDataFormat host_format : host_formats) { - std::cout << "/* -------------------------------------------------------------------- */\n"; - std::cout << "/** \\name Roundtrip testing " << to_string(host_format) << "\n"; - std::cout << " * \\{ */\n\n"; - - for (eGPUTextureFormat texture_format : texture_formats) { - if (!validate_data_format(texture_format, host_format)) { - continue; - } - - std::cout << "static void test_texture_roundtrip__" << to_string(host_format) << "__" - << to_string(texture_format) << "()\n"; - std::cout << "{\n"; - - std::cout << " texture_create_upload_read<" << to_string(texture_format) << ", " - << to_string(host_format) << ", " << to_prim_type_string(host_format) << ">();\n"; - - std::cout << "}\n"; - std::cout << "GPU_TEST(texture_roundtrip__" << to_string(host_format) << "__" - << to_string(texture_format) << ");\n\n"; - } - std::cout << "/* \\} */\n\n"; - } -} -#endif -/** \} */ - -} // namespace blender::gpu::tests \ No newline at end of file +} // namespace blender::gpu::tests -- 2.30.2 From 14c5059c2a800e518ba6e712ac2ed8a84904f2e4 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Mar 2023 13:30:31 +0100 Subject: [PATCH 12/15] Fix OpenGL tests. --- source/blender/gpu/tests/texture_test.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/blender/gpu/tests/texture_test.cc b/source/blender/gpu/tests/texture_test.cc index 38677c7f121..fab8e27d065 100644 --- a/source/blender/gpu/tests/texture_test.cc +++ b/source/blender/gpu/tests/texture_test.cc @@ -266,13 +266,13 @@ GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_SRGB8_A8); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_SNORM() { - texture_create_upload_read_with_bias(0.0f); + texture_create_upload_read_with_bias(0.004f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA8_SNORM); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16_SNORM() { - texture_create_upload_read_with_bias(0.0f); + texture_create_upload_read_with_bias(0.00002f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGBA16_SNORM); @@ -315,25 +315,25 @@ GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB32F); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8_SNORM() { - texture_create_upload_read_with_bias(0.0f); + texture_create_upload_read_with_bias(0.004f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG8_SNORM); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16_SNORM() { - texture_create_upload_read_with_bias(0.0f); + texture_create_upload_read_with_bias(0.00002f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RG16_SNORM); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R8_SNORM() { - texture_create_upload_read_with_bias(0.0f); + texture_create_upload_read_with_bias(0.004f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R8_SNORM); static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_R16_SNORM() { - texture_create_upload_read_with_bias(0.0f); + texture_create_upload_read_with_bias(0.00002f); } GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_R16_SNORM); -- 2.30.2 From 89296c8f7e5ae0fd235789343566e7b06163d8e4 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 20 Mar 2023 08:08:43 +0100 Subject: [PATCH 13/15] Use OpenEXR Imath for float<->half conversion. --- source/blender/gpu/CMakeLists.txt | 1 + .../blender/gpu/vulkan/vk_data_conversion.cc | 91 ++----------------- 2 files changed, 7 insertions(+), 85 deletions(-) diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 31a85e61ec5..04c02517136 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -44,6 +44,7 @@ set(INC set(INC_SYS ${Epoxy_INCLUDE_DIRS} + ${IMATH_INCLUDE_DIR} ) set(SRC diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc index 89511cb2fbf..b5c14593f6a 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.cc +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -7,6 +7,8 @@ #include "vk_data_conversion.hh" +#include "Imath/half.h" + namespace blender::gpu { /* -------------------------------------------------------------------- */ @@ -572,25 +574,8 @@ using UI32 = ComponentValue; using I8 = ComponentValue; using I16 = ComponentValue; using I32 = ComponentValue; - -union F32 { - uint32_t u; - float value; - struct { - uint Mantissa : 23; - uint Exponent : 8; - uint Sign : 1; - }; -}; - -union F16 { - uint16_t u; - struct { - uint Mantissa : 10; - uint Exponent : 5; - uint Sign : 1; - }; -}; +using F32 = ComponentValue; +using F16 = ComponentValue; template void convert_component(SignedNormalized &dst, const F32 &src) @@ -638,78 +623,14 @@ void convert_component(DestinationType &dst, const SourceType &src) dst.value = src.value; } -static F16 float_to_half(const F32 &value) -{ - F16 result; - /* Sign bit, shifted to its position. */ - uint sign_bit = value.u & 0x80000000; - sign_bit >>= 16; - /* Exponent. */ - uint exponent_bits = value.u & 0x7f800000; - /* Non-sign bits. */ - uint value_bits = value.u & 0x7fffffff; - value_bits >>= 13; /* Align mantissa on MSB. */ - value_bits -= 0x1c000; /* Adjust bias. */ - /* Flush-to-zero. */ - value_bits = (exponent_bits < 0x38800000) ? 0 : value_bits; - /* Clamp-to-max. */ - value_bits = (exponent_bits > 0x47000000) ? 0x7bff : value_bits; - /* Denormals-as-zero. */ - value_bits = (exponent_bits == 0 ? 0 : value_bits); - /* Re-insert sign bit and return. */ - result.u = (value_bits | sign_bit); - return result; -} - -static F32 half_to_float(const F16 &h) -{ - F32 o = {0}; - - // From ISPC ref code - if (h.Exponent == 0 && h.Mantissa == 0) // (Signed) zero - o.Sign = h.Sign; - else { - if (h.Exponent == 0) // Denormal (will convert to normalized) - { - // Adjust mantissa so it's normalized (and keep track of exp adjust) - int e = -1; - uint m = h.Mantissa; - do { - e++; - m <<= 1; - } while ((m & 0x400) == 0); - - o.Mantissa = (m & 0x3ff) << 13; - o.Exponent = 127 - 15 - e; - o.Sign = h.Sign; - } - else if (h.Exponent == 0x1f) // Inf/NaN - { - // NOTE: It's safe to treat both with the same code path by just truncating - // lower Mantissa bits in NaNs (this is valid). - o.Mantissa = h.Mantissa << 13; - o.Exponent = 255; - o.Sign = h.Sign; - } - else // Normalized number - { - o.Mantissa = h.Mantissa << 13; - o.Exponent = 127 - 15 + h.Exponent; - o.Sign = h.Sign; - } - } - - return o; -} - static void convert_component(F16 &dst, const F32 &src) { - dst = float_to_half(src); + dst.value = imath_float_to_half(src.value); } static void convert_component(F32 &dst, const F16 &src) { - dst = half_to_float(src); + dst.value = imath_half_to_float(src.value); } /* \} */ -- 2.30.2 From 34565dfe49f88263d53ec0aa208c49006ed232e8 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 20 Mar 2023 08:21:38 +0100 Subject: [PATCH 14/15] Use GTEST_SKIP when texture could not be created on platform. --- source/blender/gpu/tests/texture_test.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/blender/gpu/tests/texture_test.cc b/source/blender/gpu/tests/texture_test.cc index fab8e27d065..2930a20b127 100644 --- a/source/blender/gpu/tests/texture_test.cc +++ b/source/blender/gpu/tests/texture_test.cc @@ -84,7 +84,9 @@ static void texture_create_upload_read() eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; GPUTexture *texture = GPU_texture_create_2d( "texture", Size, Size, 1, DeviceFormat, usage, nullptr); - ASSERT_NE(texture, nullptr); + if (texture == nullptr) { + GTEST_SKIP() << "Platform doesn't support texture format [" << STRINGIFY(DeviceFormat) << "]"; + } size_t data_len = Size * Size * to_component_len(DeviceFormat); DataType *data = static_cast(generate_test_data(data_len)); @@ -111,7 +113,9 @@ static void texture_create_upload_read_with_bias(float max_allowed_bias) eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; GPUTexture *texture = GPU_texture_create_2d( "texture", Size, Size, 1, DeviceFormat, usage, nullptr); - ASSERT_NE(texture, nullptr); + if (texture == nullptr) { + GTEST_SKIP() << "Platform doesn't support texture format [" << STRINGIFY(DeviceFormat) << "]"; + } size_t data_len = Size * Size * to_component_len(DeviceFormat); float *data = static_cast(generate_test_data(data_len)); -- 2.30.2 From 4cacec223cd3f36c0dea324f646d3880a4faca50 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 20 Mar 2023 08:33:36 +0100 Subject: [PATCH 15/15] Fix incorrect datatype F32/16 --- source/blender/gpu/vulkan/vk_data_conversion.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc index b5c14593f6a..27cab7fd905 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.cc +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -574,8 +574,8 @@ using UI32 = ComponentValue; using I8 = ComponentValue; using I16 = ComponentValue; using I32 = ComponentValue; -using F32 = ComponentValue; -using F16 = ComponentValue; +using F32 = ComponentValue; +using F16 = ComponentValue; template void convert_component(SignedNormalized &dst, const F32 &src) -- 2.30.2