Skip to content

Commit

Permalink
add support for image1d_buffer (#609)
Browse files Browse the repository at this point in the history
* WIP texel buffers

Change-Id: I4eef91af393b5487bbc208bdc96d43daa4c5c462

* add support for image1d_buffer

remove 1DBUFFER mention in init_vulkan_image
limit CL_DEVICE_IMAGE_MAX_BUFFER_SIZE WITH CL_DEVICE_MAX_MEM_ALLOC_SIZE

* kpet feedback

* fix formatting

* update clspv

* use bigger padding in test

---------

Co-authored-by: Kévin Petit <kpet@free.fr>
  • Loading branch information
rjodinchr and kpet committed Oct 29, 2023
1 parent 1b3b025 commit a25eb53
Show file tree
Hide file tree
Showing 13 changed files with 502 additions and 135 deletions.
280 changes: 201 additions & 79 deletions src/api.cpp

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,7 @@ bool cvk_device::supports_capability(spv::Capability capability) const {
case spv::CapabilityImage1D:
case spv::CapabilityImageQuery:
case spv::CapabilityImageBuffer:
case spv::CapabilitySampledBuffer:
return true;
// Optional capabilities:
case spv::CapabilityFloat16:
Expand Down
5 changes: 5 additions & 0 deletions src/device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ struct cvk_device : public _cl_device_id,
return maxAllocSz;
}

size_t image_max_buffer_size() const {
return std::min((uint64_t)vulkan_limits().maxTexelBufferElements,
max_mem_alloc_size());
}

cl_uint mem_base_addr_align() const {
// The OpenCL spec requires at least 1024 bits (long16's alignment)
uint32_t required_by_vulkan_impl =
Expand Down
36 changes: 35 additions & 1 deletion src/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ cl_int cvk_kernel::set_arg(cl_uint index, size_t size, const void* value) {
// if the argument is an image, we need to set its metadata
// (channel_order/channel_data_type).
if (arg.kind == kernel_argument_kind::sampled_image ||
arg.kind == kernel_argument_kind::storage_image) {
arg.kind == kernel_argument_kind::storage_image ||
arg.kind == kernel_argument_kind::storage_texel_buffer ||
arg.kind == kernel_argument_kind::uniform_texel_buffer) {
set_image_metadata(index, value);
}

Expand Down Expand Up @@ -155,9 +157,11 @@ bool cvk_kernel_argument_values::setup_descriptor_sets() {
std::vector<VkWriteDescriptorSet> descriptor_writes;
std::vector<VkDescriptorBufferInfo> buffer_info;
std::vector<VkDescriptorImageInfo> image_info;
std::vector<VkBufferView> 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 &&
Expand Down Expand Up @@ -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<cvk_image*>(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:
Expand Down
117 changes: 86 additions & 31 deletions src/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -397,29 +407,24 @@ bool cvk_image::init() {
return false;
}

if (m_desc.image_type == CL_MEM_OBJECT_IMAGE1D_BUFFER) {
auto buffer = static_cast<cvk_mem*>(m_desc.buffer);
m_memory = buffer->memory();
buffer->retain();
} else {
// Select memory type
cvk_device::allocation_parameters params =
device->select_memory_for(m_image);
if (params.memory_type_index == VK_MAX_MEMORY_TYPES) {
cvk_error_fn("Could not get memory type!");
return false;
}
CVK_ASSERT(m_desc.image_type != CL_MEM_OBJECT_IMAGE1D_BUFFER);
// Select memory type
cvk_device::allocation_parameters params =
device->select_memory_for(m_image);
if (params.memory_type_index == VK_MAX_MEMORY_TYPES) {
cvk_error_fn("Could not get memory type!");
return false;
}

// Allocate memory
m_memory = std::make_unique<cvk_memory_allocation>(
vkdev, params.size, params.memory_type_index);
// Allocate memory
m_memory = std::make_unique<cvk_memory_allocation>(
vkdev, params.size, params.memory_type_index);

res = m_memory->allocate(device->uses_physical_addressing());
res = m_memory->allocate(device->uses_physical_addressing());

if (res != VK_SUCCESS) {
cvk_error_fn("Could not allocate memory!");
return false;
}
if (res != VK_SUCCESS) {
cvk_error_fn("Could not allocate memory!");
return false;
}

// Bind the image to memory
Expand Down Expand Up @@ -485,6 +490,56 @@ 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<cvk_buffer*>(buffer())->vulkan_buffer();
auto offset = static_cast<cvk_buffer*>(buffer())->vulkan_buffer_offset();

VkBufferViewCreateInfo createInfo = {
VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
nullptr,
0, // flags
vkbuf, // buffer
format, // format
offset, // 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 {
Expand Down
52 changes: 42 additions & 10 deletions src/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,10 +314,13 @@ struct cvk_buffer : public cvk_mem {
cvk_mem* create_subbuffer(cl_mem_flags, size_t origin, size_t size);

VkBufferUsageFlags prepare_usage_flags() {
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;
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_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;
}
Expand Down Expand Up @@ -485,10 +488,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() {
Expand All @@ -502,6 +511,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();
}
Expand Down Expand Up @@ -530,9 +542,26 @@ struct cvk_image : public cvk_mem {
const cl_image_format* format, void* host_ptr,
std::vector<cl_mem_properties>&& 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) {
Expand Down Expand Up @@ -693,6 +722,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 {
Expand Down Expand Up @@ -746,6 +777,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<void*, std::list<cvk_image_mapping>> m_mappings;
std::mutex m_mappings_lock;
std::unique_ptr<cvk_buffer> m_init_data;
Expand Down
12 changes: 12 additions & 0 deletions src/program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 5 additions & 1 deletion src/program.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ enum class kernel_argument_kind
pointer_pushconstant,
sampled_image,
storage_image,
storage_texel_buffer,
uniform_texel_buffer,
sampler,
local,
unused,
Expand Down Expand Up @@ -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; }
Expand Down
Loading

0 comments on commit a25eb53

Please sign in to comment.