From c849f7956a77df538f318da50237d4cb283c7313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Petit?= Date: Sun, 30 Oct 2022 16:36:48 +0000 Subject: [PATCH] WIP texel buffers Change-Id: I4eef91af393b5487bbc208bdc96d43daa4c5c462 --- src/api.cpp | 80 ++++++++++++++++++++++++++++++------------------ src/device.cpp | 1 + src/kernel.cpp | 36 +++++++++++++++++++++- src/memory.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++------- src/memory.hpp | 45 ++++++++++++++++++++++----- src/program.cpp | 12 ++++++++ src/program.hpp | 6 +++- src/queue.hpp | 4 ++- 8 files changed, 214 insertions(+), 51 deletions(-) diff --git a/src/api.cpp b/src/api.cpp index 91d201ad..9866f13e 100644 --- a/src/api.cpp +++ b/src/api.cpp @@ -710,7 +710,7 @@ cl_int CLVK_API_CALL clGetDeviceInfo(cl_device_id dev, size_ret = sizeof(val_uint); break; case CL_DEVICE_IMAGE_MAX_BUFFER_SIZE: - val_sizet = device->vulkan_limits().maxImageDimension1D; + val_sizet = device->vulkan_limits().maxTexelBufferElements; copy_ptr = &val_sizet; size_ret = sizeof(val_sizet); break; @@ -4718,22 +4718,13 @@ std::unordered_map descriptor_writes; std::vector buffer_info; std::vector image_info; + std::vector buffer_views; descriptor_writes.reserve(max_descriptor_writes); buffer_info.reserve(max_descriptor_writes); image_info.reserve(max_descriptor_writes); + buffer_views.reserve(max_descriptor_writes); // Setup module-scope variables if (program->module_constant_data_buffer() != nullptr && @@ -324,6 +328,36 @@ bool cvk_kernel_argument_values::setup_descriptor_sets() { descriptor_writes.push_back(writeDescriptorSet); break; } + case kernel_argument_kind::storage_texel_buffer: + case kernel_argument_kind::uniform_texel_buffer: { + auto image = static_cast(get_arg_value(arg)); + bool uniform = + arg.kind == kernel_argument_kind::uniform_texel_buffer; + auto view = image->vulkan_buffer_view(); + buffer_views.push_back(view); + + cvk_debug_fn("buffer view %p @ set = %u, binding = %u", view, + arg.descriptorSet, arg.binding); + + VkDescriptorType dtype = + uniform ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER + : VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + + VkWriteDescriptorSet writeDescriptorSet = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + nullptr, + ds[arg.descriptorSet], + arg.binding, // dstBinding + 0, // dstArrayElement + 1, // descriptorCount + dtype, + nullptr, // pImageInfo + nullptr, // pBufferInfo + &buffer_views.back(), // pTexelBufferView + }; + descriptor_writes.push_back(writeDescriptorSet); + break; + } case kernel_argument_kind::pod: // skip POD arguments case kernel_argument_kind::pod_ubo: case kernel_argument_kind::pod_pushconstant: diff --git a/src/memory.cpp b/src/memory.cpp index 5688e45b..f9017413 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -243,22 +243,33 @@ bool cvk_sampler::init() { VkFormatFeatureFlags cvk_image::required_format_feature_flags_for(cl_mem_object_type type, cl_mem_flags flags) { - UNUSED(type); // TODO will be required for 1D buffer images - // All images require TRANSFER_SRC, TRANSFER_DST + // 1Dbuffer requires + // RW / RaW: STORAGE_TEXEL_BUFFER + // RO: UNIFORM_TEXEL_BUFFER + // All other images require TRANSFER_SRC, TRANSFER_DST // read-only: SAMPLED_IMAGE, SAMPLED_IMAGE_FILTER_LINEAR // write-only: STORAGE_IMAGE // read-write: STORAGE_IMAGE, SAMPLED_IMAGE, SAMPLED_IMAGE_FILTER_LINEAR // read-and-write: STORAGE_IMAGE VkFormatFeatureFlags format_feature_flags = 0; - format_feature_flags = - VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT; - + if (type != CL_MEM_OBJECT_IMAGE1D_BUFFER) { + format_feature_flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | + VK_FORMAT_FEATURE_TRANSFER_DST_BIT; + } VkFormatFeatureFlags format_feature_flags_RO; - format_feature_flags_RO = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; - + if (type == CL_MEM_OBJECT_IMAGE1D_BUFFER) { + format_feature_flags_RO = VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT; + } else { + format_feature_flags_RO = + VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; + } VkFormatFeatureFlags format_feature_flags_WO; - format_feature_flags_WO = VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; + if (type == CL_MEM_OBJECT_IMAGE1D_BUFFER) { + format_feature_flags_WO = VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT; + } else { + format_feature_flags_WO = VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; + } if (flags & (CL_MEM_KERNEL_READ_AND_WRITE | CL_MEM_WRITE_ONLY)) { format_feature_flags |= format_feature_flags_WO; @@ -292,7 +303,7 @@ cl_image_format_to_vulkan_format(const cl_image_format& clfmt, VkComponentMapping* components_sampled, VkComponentMapping* components_storage); -bool cvk_image::init() { +bool cvk_image::init_vulkan_image() { // Translate image type and size VkImageType image_type; VkImageViewType view_type; @@ -320,7 +331,6 @@ bool cvk_image::init() { size_t host_ptr_size = 0; switch (m_desc.image_type) { - case CL_MEM_OBJECT_IMAGE1D_BUFFER: case CL_MEM_OBJECT_IMAGE1D: image_type = VK_IMAGE_TYPE_1D; view_type = VK_IMAGE_VIEW_TYPE_1D; @@ -485,6 +495,55 @@ bool cvk_image::init() { return true; } +bool cvk_image::init_vulkan_texel_buffer() { + VkResult res; + + auto device = m_context->device(); + auto vkdev = device->vulkan_device(); + + VkFormat format; + VkComponentMapping components_sampled, components_storage; + + auto success = cl_image_format_to_vulkan_format( + m_format, &format, &components_sampled, &components_storage); + if (!success) { + return false; + } + + CVK_ASSERT(buffer()); + CVK_ASSERT(buffer()->is_buffer_type()); + + auto vkbuf = static_cast(buffer())->vulkan_buffer(); + + VkBufferViewCreateInfo createInfo = { + VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, + nullptr, + 0, // flags + vkbuf, // buffer + format, // format + 0, // offset + VK_WHOLE_SIZE // range + }; + + res = vkCreateBufferView(vkdev, &createInfo, nullptr, &m_buffer_view); + if (res != VK_SUCCESS) { + cvk_error_fn("Could not create buffer view"); + return false; + } + + buffer()->retain(); + + return true; +} + +bool cvk_image::init() { + if (is_backed_by_buffer_view()) { + return init_vulkan_texel_buffer(); + } else { + return init_vulkan_image(); + } +} + void cvk_image::prepare_fill_pattern(const void* input_pattern, fill_pattern_array& pattern, size_t* size_ret) const { diff --git a/src/memory.hpp b/src/memory.hpp index 63817558..0d71a6ad 100644 --- a/src/memory.hpp +++ b/src/memory.hpp @@ -317,7 +317,9 @@ struct cvk_buffer : public cvk_mem { VkBufferUsageFlags usage_flags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | + VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; if (m_context->device()->uses_physical_addressing()) { usage_flags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; } @@ -485,10 +487,16 @@ struct cvk_image : public cvk_mem { /* FIXME parent_offset */ 0, std::move(properties), desc->image_type), m_desc(*desc), m_format(*format), m_image(VK_NULL_HANDLE), - m_sampled_view(VK_NULL_HANDLE), m_storage_view(VK_NULL_HANDLE) { + m_sampled_view(VK_NULL_HANDLE), m_storage_view(VK_NULL_HANDLE), + m_buffer_view(VK_NULL_HANDLE) { // All images require asynchronous initialiation for the initial - // layout transition (and copy/use host ptr init) - m_init_tracker.set_state(cvk_mem_init_state::required); + // layout transition (and copy/use host ptr init) apart from + // those backed by a texel buffer + if (is_backed_by_buffer_view()) { + m_init_tracker.set_state(cvk_mem_init_state::completed); + } else { + m_init_tracker.set_state(cvk_mem_init_state::required); + } } ~cvk_image() { @@ -502,6 +510,9 @@ struct cvk_image : public cvk_mem { if (m_storage_view != VK_NULL_HANDLE) { vkDestroyImageView(vkdev, m_storage_view, nullptr); } + if (m_buffer_view != VK_NULL_HANDLE) { + vkDestroyBufferView(vkdev, m_buffer_view, nullptr); + } if (buffer() != nullptr) { buffer()->release(); } @@ -530,9 +541,26 @@ struct cvk_image : public cvk_mem { const cl_image_format* format, void* host_ptr, std::vector&& properties); - VkImage vulkan_image() const { return m_image; } - VkImageView vulkan_sampled_view() const { return m_sampled_view; } - VkImageView vulkan_storage_view() const { return m_storage_view; } + bool is_backed_by_buffer_view() const { + return type() == CL_MEM_OBJECT_IMAGE1D_BUFFER; + } + + VkImage vulkan_image() const { + CVK_ASSERT(!is_backed_by_buffer_view()); + return m_image; + } + VkImageView vulkan_sampled_view() const { + CVK_ASSERT(!is_backed_by_buffer_view()); + return m_sampled_view; + } + VkImageView vulkan_storage_view() const { + CVK_ASSERT(!is_backed_by_buffer_view()); + return m_storage_view; + } + VkBufferView vulkan_buffer_view() const { + CVK_ASSERT(is_backed_by_buffer_view()); + return m_buffer_view; + } const cl_image_format& format() const { return m_format; } size_t element_size() const { switch (m_format.image_channel_data_type) { @@ -693,6 +721,8 @@ struct cvk_image : public cvk_mem { size_t* size_ret) const; private: + bool init_vulkan_image(); + bool init_vulkan_texel_buffer(); bool init(); size_t num_channels() const { @@ -746,6 +776,7 @@ struct cvk_image : public cvk_mem { VkImage m_image; VkImageView m_sampled_view; VkImageView m_storage_view; + VkBufferView m_buffer_view; std::unordered_map> m_mappings; std::mutex m_mappings_lock; std::unique_ptr m_init_data; diff --git a/src/program.cpp b/src/program.cpp index b0390fab..9e538dcd 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -117,6 +117,10 @@ spv_result_t parse_reflection(void* user_data, return kernel_argument_kind::sampled_image; case NonSemanticClspvReflectionArgumentStorageImage: return kernel_argument_kind::storage_image; + case NonSemanticClspvReflectionArgumentStorageTexelBuffer: + return kernel_argument_kind::storage_texel_buffer; + case NonSemanticClspvReflectionArgumentUniformTexelBuffer: + return kernel_argument_kind::uniform_texel_buffer; case NonSemanticClspvReflectionArgumentSampler: return kernel_argument_kind::sampler; case NonSemanticClspvReflectionArgumentWorkgroup: @@ -234,6 +238,8 @@ spv_result_t parse_reflection(void* user_data, case NonSemanticClspvReflectionArgumentUniform: case NonSemanticClspvReflectionArgumentSampledImage: case NonSemanticClspvReflectionArgumentStorageImage: + case NonSemanticClspvReflectionArgumentStorageTexelBuffer: + case NonSemanticClspvReflectionArgumentUniformTexelBuffer: case NonSemanticClspvReflectionArgumentSampler: { // These arguments have descriptor set, binding and an optional // arg info. @@ -1743,6 +1749,12 @@ bool cvk_entry_point::build_descriptor_sets_layout_bindings_for_arguments( case kernel_argument_kind::storage_image: dt = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; break; + case kernel_argument_kind::storage_texel_buffer: + dt = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + break; + case kernel_argument_kind::uniform_texel_buffer: + dt = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + break; case kernel_argument_kind::sampler: dt = VK_DESCRIPTOR_TYPE_SAMPLER; break; diff --git a/src/program.hpp b/src/program.hpp index 8df31c7e..7a65bc35 100644 --- a/src/program.hpp +++ b/src/program.hpp @@ -47,6 +47,8 @@ enum class kernel_argument_kind pointer_pushconstant, sampled_image, storage_image, + storage_texel_buffer, + uniform_texel_buffer, sampler, local, unused, @@ -101,7 +103,9 @@ struct kernel_argument { return (kind == kernel_argument_kind::buffer) || (kind == kernel_argument_kind::buffer_ubo) || (kind == kernel_argument_kind::sampled_image) || - (kind == kernel_argument_kind::storage_image); + (kind == kernel_argument_kind::storage_image) || + (kind == kernel_argument_kind::storage_texel_buffer) || + (kind == kernel_argument_kind::uniform_texel_buffer); } bool is_unused() const { return kind == kernel_argument_kind::unused; } diff --git a/src/queue.hpp b/src/queue.hpp index 4acd0e5e..134e8d55 100644 --- a/src/queue.hpp +++ b/src/queue.hpp @@ -1141,7 +1141,9 @@ struct cvk_command_image_init final : public cvk_command_batchable { cvk_command_image_init(cvk_command_queue* queue, cvk_image* image) : cvk_command_batchable(CLVK_COMMAND_IMAGE_INIT, queue), - m_image(image) {} + m_image(image) { + CVK_ASSERT(!m_image->is_backed_by_buffer_view()); + } bool is_data_movement() const override { return true; } CHECK_RETURN cl_int build_batchable_inner(cvk_command_buffer& cmdbuf) override final;