Skip to content

Commit b283ed3

Browse files
committed
Add option to fill images on device
Create a second image (with write_only flag) using the same VkDeviceMemory at runtime when it detects a fillimage on a read_only image.
1 parent 95a14fe commit b283ed3

File tree

7 files changed

+293
-25
lines changed

7 files changed

+293
-25
lines changed

src/api.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5450,6 +5450,19 @@ cl_int CLVK_API_CALL clEnqueueFillImage(
54505450
// Create image map command
54515451
std::array<size_t, 3> reg = {region[0], region[1], region[2]};
54525452

5453+
if (config.fill_image_on_device()) {
5454+
std::array<size_t, 3> org = {origin[0], origin[1], origin[2]};
5455+
std::array<uint8_t, 16> fill_color_array;
5456+
std::memcpy(fill_color_array.data(), fill_color,
5457+
sizeof(fill_color_array));
5458+
5459+
auto cmd_fill_on_device = new cvk_command_fill_image_on_device(
5460+
command_queue, image, fill_color_array, org, reg);
5461+
return command_queue->enqueue_command_with_deps(cmd_fill_on_device,
5462+
num_events_in_wait_list,
5463+
event_wait_list, event);
5464+
}
5465+
54535466
void* map_ptr;
54545467
_cl_event* evt_map;
54555468
size_t image_row_pitch, image_slice_pitch;

src/config.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ OPTION(bool, keep_memory_allocations_mapped, false)
7171
OPTION(std::string, device_extensions, "")
7272
OPTION(std::string, device_extensions_masked, "")
7373

74+
OPTION(bool, fill_image_on_device, false)
75+
7476
//
7577
// Logging
7678
//

src/device.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,10 +1292,12 @@ void cvk_device::select_work_group_size(
12921292
cvk_kernel* kernel, const std::array<uint32_t, 3>& global_size,
12931293
std::array<uint32_t, 3>& local_size) const {
12941294

1295-
auto required_work_group_size = kernel->required_work_group_size();
1296-
if (required_work_group_size[0] != 0) {
1297-
local_size = required_work_group_size;
1298-
return;
1295+
if (kernel != nullptr) {
1296+
auto required_work_group_size = kernel->required_work_group_size();
1297+
if (required_work_group_size[0] != 0) {
1298+
local_size = required_work_group_size;
1299+
return;
1300+
}
12991301
}
13001302
// Start at (1,1,1), which is always valid.
13011303
local_size = {1, 1, 1};

src/memory.cpp

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,21 @@ cvk_image* cvk_image::create(cvk_context* ctx, cl_mem_flags flags,
325325
return image.release();
326326
}
327327

328-
bool cvk_image::init_vulkan_image() {
328+
cvk_image* cvk_image::create_write_enable_image_from(cvk_image* image) {
329+
auto properties = image->properties();
330+
auto image_write_enabled =
331+
std::make_unique<cvk_image>(image->m_context, CL_MEM_WRITE_ONLY,
332+
(const cl_image_desc*)&(image->m_desc),
333+
(const cl_image_format*)&(image->m_format),
334+
nullptr, std::move(properties));
335+
if (!image_write_enabled->init(image->m_memory)) {
336+
return nullptr;
337+
}
338+
return image_write_enabled.release();
339+
}
340+
341+
bool cvk_image::init_vulkan_image(
342+
std::shared_ptr<cvk_memory_allocation> memory) {
329343
// Translate image type and size
330344
VkImageType image_type;
331345
VkImageViewType view_type;
@@ -431,25 +445,29 @@ bool cvk_image::init_vulkan_image() {
431445
return false;
432446
}
433447

434-
CVK_ASSERT(m_desc.image_type != CL_MEM_OBJECT_IMAGE1D_BUFFER);
435-
// Select memory type
436-
cvk_device::allocation_parameters params =
437-
device->select_memory_for(m_image);
438-
if (params.memory_type_index == VK_MAX_MEMORY_TYPES) {
439-
cvk_error_fn("Could not get memory type!");
440-
return false;
441-
}
448+
if (memory != VK_NULL_HANDLE) {
449+
m_memory = memory;
450+
} else {
451+
CVK_ASSERT(m_desc.image_type != CL_MEM_OBJECT_IMAGE1D_BUFFER);
452+
// Select memory type
453+
cvk_device::allocation_parameters params =
454+
device->select_memory_for(m_image);
455+
if (params.memory_type_index == VK_MAX_MEMORY_TYPES) {
456+
cvk_error_fn("Could not get memory type!");
457+
return false;
458+
}
442459

443-
// Allocate memory
444-
m_memory = std::make_unique<cvk_memory_allocation>(
445-
vkdev, params.size, params.memory_type_index, params.memory_coherent,
446-
device->keep_memory_allocations_mapped());
460+
// Allocate memory
461+
m_memory = std::make_unique<cvk_memory_allocation>(
462+
vkdev, params.size, params.memory_type_index,
463+
params.memory_coherent, device->keep_memory_allocations_mapped());
447464

448-
res = m_memory->allocate(device->uses_physical_addressing());
465+
res = m_memory->allocate(device->uses_physical_addressing());
449466

450-
if (res != VK_SUCCESS) {
451-
cvk_error_fn("Could not allocate memory!");
452-
return false;
467+
if (res != VK_SUCCESS) {
468+
cvk_error_fn("Could not allocate memory!");
469+
return false;
470+
}
453471
}
454472

455473
// Bind the image to memory
@@ -582,11 +600,11 @@ bool cvk_image::init_vulkan_texel_buffer() {
582600
return true;
583601
}
584602

585-
bool cvk_image::init() {
603+
bool cvk_image::init(std::shared_ptr<cvk_memory_allocation> memory) {
586604
if (is_backed_by_buffer_view()) {
587605
return init_vulkan_texel_buffer();
588606
} else {
589-
return init_vulkan_image();
607+
return init_vulkan_image(memory);
590608
}
591609
}
592610

src/memory.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,7 @@ struct cvk_image : public cvk_mem {
638638
const cl_image_desc* desc,
639639
const cl_image_format* format, void* host_ptr,
640640
std::vector<cl_mem_properties>&& properties);
641+
static cvk_image* create_write_enable_image_from(cvk_image* image);
641642

642643
bool is_backed_by_buffer_view() const {
643644
return type() == CL_MEM_OBJECT_IMAGE1D_BUFFER;
@@ -700,6 +701,7 @@ struct cvk_image : public cvk_mem {
700701
cvk_mem* buffer() const { return icd_downcast(m_desc.buffer); }
701702
cl_uint num_mip_levels() const { return m_desc.num_mip_levels; }
702703
cl_uint num_samples() const { return m_desc.num_samples; }
704+
cl_image_info image_type() const { return m_desc.image_type; }
703705

704706
bool has_same_format(const cvk_image* other) const {
705707
auto fmt = format();
@@ -828,9 +830,9 @@ struct cvk_image : public cvk_mem {
828830
size_t* size_ret) const;
829831

830832
private:
831-
bool init_vulkan_image();
833+
bool init_vulkan_image(std::shared_ptr<cvk_memory_allocation> memory);
832834
bool init_vulkan_texel_buffer();
833-
bool init();
835+
bool init(std::shared_ptr<cvk_memory_allocation> memory = nullptr);
834836

835837
size_t num_channels() const {
836838
switch (m_format.image_channel_order) {

src/queue.cpp

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,3 +1891,178 @@ cvk_command_image_init::build_batchable_inner(cvk_command_buffer& cmdbuf) {
18911891

18921892
return CL_SUCCESS;
18931893
}
1894+
1895+
cl_int cvk_command_fill_image_on_device::build_batchable_inner(
1896+
cvk_command_buffer& cmdbuf) {
1897+
if (m_cmd_kernel != nullptr) {
1898+
return m_cmd_kernel->build_batchable_inner(cmdbuf);
1899+
}
1900+
char source[1024];
1901+
char color[512];
1902+
const char* kernel_name = "fill_image";
1903+
const char* type = get_image_type();
1904+
const char* access_qualifier = get_image_access_qualifier();
1905+
const char* coord = get_image_coord();
1906+
get_image_color(color);
1907+
sprintf(source,
1908+
"kernel void %s(write_only %s image) { write_image%s(image, "
1909+
"%s, %s); }",
1910+
kernel_name, type, access_qualifier, coord, color);
1911+
1912+
auto program = std::make_unique<cvk_program>(m_queue->context());
1913+
program->append_source(source, strlen(source));
1914+
const cl_device_id device = static_cast<cl_device_id>(m_queue->device());
1915+
auto err = program->build(build_operation::build, 1, &device, nullptr, 0,
1916+
nullptr, nullptr, nullptr, nullptr);
1917+
if (err != CL_SUCCESS) {
1918+
cvk_error_fn("fail to build program (%u)", err);
1919+
return CL_OUT_OF_RESOURCES;
1920+
}
1921+
1922+
auto prog = program.release();
1923+
auto kernel = std::make_unique<cvk_kernel>(prog, kernel_name);
1924+
prog->release();
1925+
err = kernel->init();
1926+
if (err != CL_SUCCESS) {
1927+
cvk_error_fn("fail to init kernel (%u)", err);
1928+
return err;
1929+
}
1930+
err = kernel->set_arg(0, sizeof(m_mem), &m_mem);
1931+
if (err != CL_SUCCESS) {
1932+
cvk_error_fn("fail to set arg (%u)", err);
1933+
return err;
1934+
}
1935+
1936+
cl_uint work_dim = dimensions();
1937+
cvk_ndrange ndrange(work_dim, m_work_offset.data(), m_work_size.data(),
1938+
nullptr);
1939+
auto kern = kernel.release();
1940+
m_cmd_kernel =
1941+
std::make_unique<cvk_command_kernel>(m_queue, kern, work_dim, ndrange);
1942+
kern->release();
1943+
return m_cmd_kernel->build_batchable_inner(cmdbuf);
1944+
}
1945+
1946+
cl_uint cvk_command_fill_image_on_device::dimensions() const {
1947+
switch (m_image->image_type()) {
1948+
default:
1949+
CVK_ASSERT(false);
1950+
return 0;
1951+
case CL_MEM_OBJECT_IMAGE1D:
1952+
case CL_MEM_OBJECT_IMAGE1D_BUFFER:
1953+
return 1;
1954+
case CL_MEM_OBJECT_IMAGE1D_ARRAY:
1955+
case CL_MEM_OBJECT_IMAGE2D:
1956+
return 2;
1957+
case CL_MEM_OBJECT_IMAGE2D_ARRAY:
1958+
case CL_MEM_OBJECT_IMAGE3D:
1959+
return 3;
1960+
}
1961+
}
1962+
1963+
const char*
1964+
cvk_command_fill_image_on_device::get_image_access_qualifier() const {
1965+
switch (m_image->format().image_channel_data_type) {
1966+
default:
1967+
CVK_ASSERT(false);
1968+
return nullptr;
1969+
case CL_UNORM_SHORT_565:
1970+
case CL_UNORM_SHORT_555:
1971+
case CL_UNORM_INT_101010:
1972+
case CL_UNORM_INT_101010_2:
1973+
case CL_UNORM_INT8:
1974+
case CL_UNORM_INT16:
1975+
return "ui";
1976+
case CL_UNSIGNED_INT8:
1977+
case CL_UNSIGNED_INT16:
1978+
case CL_UNSIGNED_INT32:
1979+
case CL_SIGNED_INT8:
1980+
case CL_SIGNED_INT16:
1981+
case CL_SIGNED_INT32:
1982+
case CL_FLOAT:
1983+
case CL_HALF_FLOAT:
1984+
return "f";
1985+
case CL_SNORM_INT8:
1986+
case CL_SNORM_INT16:
1987+
return "i";
1988+
}
1989+
}
1990+
1991+
const char* cvk_command_fill_image_on_device::get_image_type() const {
1992+
switch (m_image->image_type()) {
1993+
default:
1994+
CVK_ASSERT(false);
1995+
return nullptr;
1996+
case CL_MEM_OBJECT_IMAGE1D:
1997+
return "image1d_t";
1998+
case CL_MEM_OBJECT_IMAGE1D_BUFFER:
1999+
return "image1d_buffer_t";
2000+
case CL_MEM_OBJECT_IMAGE1D_ARRAY:
2001+
return "image1d_array_t";
2002+
case CL_MEM_OBJECT_IMAGE2D:
2003+
return "image2d_t";
2004+
case CL_MEM_OBJECT_IMAGE2D_ARRAY:
2005+
return "image2d_array_t";
2006+
case CL_MEM_OBJECT_IMAGE3D:
2007+
return "image3d";
2008+
}
2009+
}
2010+
2011+
const char* cvk_command_fill_image_on_device::get_image_coord() const {
2012+
switch (m_image->image_type()) {
2013+
default:
2014+
CVK_ASSERT(false);
2015+
return nullptr;
2016+
case CL_MEM_OBJECT_IMAGE1D:
2017+
case CL_MEM_OBJECT_IMAGE1D_BUFFER:
2018+
return "get_global_id(0)";
2019+
case CL_MEM_OBJECT_IMAGE1D_ARRAY:
2020+
case CL_MEM_OBJECT_IMAGE2D:
2021+
return "(int2)(get_global_id(0), get_global_id(1))";
2022+
case CL_MEM_OBJECT_IMAGE2D_ARRAY:
2023+
case CL_MEM_OBJECT_IMAGE3D:
2024+
return "(int4)(get_global_id(0), get_global_id(1), "
2025+
"get_global_id(2), 0)";
2026+
}
2027+
}
2028+
2029+
void cvk_command_fill_image_on_device::get_image_color(char* color) const {
2030+
switch (m_image->format().image_channel_data_type) {
2031+
default:
2032+
CVK_ASSERT(false);
2033+
break;
2034+
case CL_UNORM_SHORT_565:
2035+
case CL_UNORM_SHORT_555:
2036+
case CL_UNORM_INT_101010:
2037+
case CL_UNORM_INT_101010_2:
2038+
case CL_UNORM_INT8:
2039+
case CL_UNORM_INT16: {
2040+
auto fill_color = static_cast<const uint32_t*>(
2041+
static_cast<const void*>(m_fill_color.data()));
2042+
sprintf(color, "(uint4)(%u, %u, %u, %u)", fill_color[0], fill_color[1],
2043+
fill_color[2], fill_color[3]);
2044+
} break;
2045+
case CL_UNSIGNED_INT8:
2046+
case CL_UNSIGNED_INT16:
2047+
case CL_UNSIGNED_INT32:
2048+
case CL_SIGNED_INT8:
2049+
case CL_SIGNED_INT16:
2050+
case CL_SIGNED_INT32:
2051+
case CL_FLOAT:
2052+
case CL_HALF_FLOAT: {
2053+
auto fill_color = static_cast<const uint32_t*>(
2054+
static_cast<const void*>(m_fill_color.data()));
2055+
sprintf(color,
2056+
"(float4)(as_float(0x%x), as_float(0x%x), as_float(0x%x), "
2057+
"as_float(0x%x))",
2058+
fill_color[0], fill_color[1], fill_color[2], fill_color[3]);
2059+
} break;
2060+
case CL_SNORM_INT8:
2061+
case CL_SNORM_INT16: {
2062+
auto fill_color = static_cast<const int32_t*>(
2063+
static_cast<const void*>(m_fill_color.data()));
2064+
sprintf(color, "(int4)(%i, %i, %i, %i)", fill_color[0], fill_color[1],
2065+
fill_color[2], fill_color[3]);
2066+
} break;
2067+
}
2068+
}

src/queue.hpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,3 +1115,59 @@ struct cvk_command_image_init final : public cvk_command_batchable {
11151115
private:
11161116
cvk_image_holder m_image;
11171117
};
1118+
1119+
struct cvk_command_fill_image_on_device final : public cvk_command_batchable {
1120+
cvk_command_fill_image_on_device(cvk_command_queue* queue, cl_mem image,
1121+
const std::array<uint8_t, 16> fill_color,
1122+
const std::array<size_t, 3> work_offset,
1123+
const std::array<size_t, 3> work_size)
1124+
: cvk_command_batchable(CL_COMMAND_FILL_IMAGE, queue),
1125+
m_image(static_cast<cvk_image*>(icd_downcast(image))),
1126+
m_fill_color(fill_color), m_work_offset(work_offset),
1127+
m_work_size(work_size) {
1128+
const std::array<uint32_t, 3> global_size = {(uint32_t)work_size[0],
1129+
(uint32_t)work_size[1],
1130+
(uint32_t)work_size[2]};
1131+
std::array<uint32_t, 3> local_size;
1132+
queue->device()->select_work_group_size(nullptr, global_size,
1133+
local_size);
1134+
m_local_size[0] = local_size[0];
1135+
m_local_size[1] = local_size[1];
1136+
m_local_size[2] = local_size[2];
1137+
1138+
if (!m_image->has_any_flag(CL_MEM_WRITE_ONLY | CL_MEM_READ_WRITE)) {
1139+
m_image_write_enabled.reset(
1140+
cvk_image::create_write_enable_image_from(m_image));
1141+
m_mem = m_image_write_enabled;
1142+
} else {
1143+
m_mem = image;
1144+
}
1145+
}
1146+
1147+
CHECK_RETURN cl_int
1148+
build_batchable_inner(cvk_command_buffer& cmdbuf) override final;
1149+
1150+
bool can_be_batched() const override final {
1151+
return cvk_command_batchable::can_be_batched();
1152+
}
1153+
1154+
const std::vector<cvk_mem*> memory_objects() const override {
1155+
return {m_image};
1156+
}
1157+
1158+
private:
1159+
cl_uint dimensions() const;
1160+
const char* get_image_access_qualifier() const;
1161+
const char* get_image_type() const;
1162+
const char* get_image_coord() const;
1163+
void get_image_color(char* color) const;
1164+
1165+
cl_mem m_mem;
1166+
cvk_image_holder m_image;
1167+
cvk_image_holder m_image_write_enabled;
1168+
std::array<uint8_t, 16> m_fill_color;
1169+
std::array<size_t, 3> m_work_offset;
1170+
std::array<size_t, 3> m_work_size;
1171+
std::array<size_t, 3> m_local_size;
1172+
std::unique_ptr<cvk_command_kernel> m_cmd_kernel;
1173+
};

0 commit comments

Comments
 (0)