Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for image1d_buffer #609

Merged
merged 6 commits into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the latest CI failures, it seems we also need VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR which apparently is only available as a "2" format feature so we're dragging #497 as a dependency.

} 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
Loading