Skip to content

Commit

Permalink
init image at creation time
Browse files Browse the repository at this point in the history
fix #719
  • Loading branch information
rjodinchr committed Nov 7, 2024
1 parent 1f76af2 commit 2531142
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 5 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,12 @@ using the name of the corresponding environment variable.
can be a work-around when having issues with clang compiling in the
application thread.

* `CLVK_INIT_IMAGE_AT_CREATION` force to initialize OpenCL images created with
`CL_MEM_COPY_HOST_PTR` or `CL_MEM_USE_HOST_PTR` at creation time instead of
initializing them during first use of the image (default: false). It reduces
the memory footprint as clvk needs to keep a buffer with the data to
initialize at first use.

# Limitations

* Only one device per CL context
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ endif()
add_library(OpenCL-objects OBJECT
api.cpp
config.cpp
context.cpp
device.cpp
device_properties.cpp
event.cpp
Expand Down
2 changes: 2 additions & 0 deletions src/config.def
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ OPTION(uint32_t, opencl_version, (uint32_t)CL_MAKE_VERSION(3, 0, 0))

OPTION(bool, build_in_separate_thread, false)

OPTION(bool, init_image_at_creation, false)

#if COMPILER_AVAILABLE
OPTION(std::string, clspv_options, "")
#if !CLSPV_ONLINE_COMPILER
Expand Down
33 changes: 33 additions & 0 deletions src/context.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2024 The clvk authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "context.hpp"
#include "queue.hpp"

cvk_command_queue* cvk_context::get_or_create_image_init_command_queue() {
std::unique_lock<std::mutex> lock(m_queue_image_init_lock);
if (m_queue_image_init != nullptr) {
return m_queue_image_init;
}
std::vector<cl_queue_properties> properties_array;
m_queue_image_init = new cvk_command_queue(
this, m_device, 0, std::move(properties_array), true);
cl_int ret = m_queue_image_init->init();
if (ret != CL_SUCCESS) {
return nullptr;
}
return m_queue_image_init;
}

void cvk_context::free_image_init_command_queue() { delete m_queue_image_init; }
9 changes: 9 additions & 0 deletions src/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ struct cvk_context_callback {
void* data;
};

struct cvk_command_queue;

struct cvk_context : public _cl_context,
refcounted,
object_magic_header<object_magic::context> {
Expand Down Expand Up @@ -73,6 +75,7 @@ struct cvk_context : public _cl_context,
auto cb = *cbi;
cb.pointer(this, cb.data);
}
free_image_init_command_queue();
}

const std::vector<cl_context_properties>& properties() const {
Expand Down Expand Up @@ -116,6 +119,9 @@ struct cvk_context : public _cl_context,
cvk_printf_callback_t get_printf_callback() { return m_printf_callback; }
void* get_printf_userdata() { return m_user_data; }

cvk_command_queue* get_or_create_image_init_command_queue();
void free_image_init_command_queue();

private:
cvk_device* m_device;
std::mutex m_callbacks_lock;
Expand All @@ -124,6 +130,9 @@ struct cvk_context : public _cl_context,
size_t m_printf_buffersize;
cvk_printf_callback_t m_printf_callback;
void* m_user_data;

std::mutex m_queue_image_init_lock;
cvk_command_queue* m_queue_image_init = nullptr;
};

static inline cvk_context* icd_downcast(cl_context context) {
Expand Down
20 changes: 20 additions & 0 deletions src/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,26 @@ bool cvk_image::init_vulkan_image() {
"Could not copy image host_ptr data to the staging buffer");
return false;
}

if (config.init_image_at_creation()) {
auto queue = m_context->get_or_create_image_init_command_queue();
if (queue == nullptr) {
return false;
}

auto initimage = new cvk_command_image_init(queue, this);
ret = queue->enqueue_command_with_deps(initimage, 0, nullptr,
nullptr);
if (ret != CL_SUCCESS) {
return false;
}
ret = queue->finish();
if (ret != CL_SUCCESS) {
return false;
}
std::lock_guard<std::mutex> lock(m_init_tracker.mutex());
m_init_tracker.set_state(cvk_mem_init_state::completed);
}
}

return true;
Expand Down
13 changes: 9 additions & 4 deletions src/queue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ static cvk_executor_thread_pool* get_thread_pool() {
cvk_command_queue::cvk_command_queue(
cvk_context* ctx, cvk_device* device,
cl_command_queue_properties properties,
std::vector<cl_queue_properties>&& properties_array)
: api_object(ctx), m_device(device), m_properties(properties),
m_properties_array(std::move(properties_array)), m_executor(nullptr),
m_command_batch(nullptr), m_vulkan_queue(device->vulkan_queue_allocate()),
std::vector<cl_queue_properties>&& properties_array, bool init_image_queue)
: api_object(ctx), m_init_image_queue(init_image_queue), m_device(device),
m_properties(properties), m_properties_array(std::move(properties_array)),
m_executor(nullptr), m_command_batch(nullptr),
m_vulkan_queue(device->vulkan_queue_allocate()),
m_command_pool(device, m_vulkan_queue.queue_family()),
m_max_cmd_batch_size(device->get_max_cmd_batch_size()),
m_max_first_cmd_batch_size(device->get_max_first_cmd_batch_size()),
Expand Down Expand Up @@ -63,6 +64,10 @@ cvk_command_queue::cvk_command_queue(

TRACE_CNT(batch_in_flight_counter, 0);
TRACE_CNT(group_in_flight_counter, 0);

if (init_image_queue) {
m_context.reset(nullptr);
}
}

cl_int cvk_command_queue::init() {
Expand Down
15 changes: 14 additions & 1 deletion src/queue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,13 @@ struct cvk_command_queue : public _cl_command_queue,

cvk_command_queue(cvk_context* ctx, cvk_device* dev,
cl_command_queue_properties props,
std::vector<cl_queue_properties>&& properties_array);
std::vector<cl_queue_properties>&& properties_array,
bool init_image_at_creation);

cvk_command_queue(cvk_context* ctx, cvk_device* dev,
cl_command_queue_properties props,
std::vector<cl_queue_properties>&& props_arr)
: cvk_command_queue(ctx, dev, props, std::move(props_arr), false) {};

CHECK_RETURN cl_int init();

Expand Down Expand Up @@ -175,6 +181,11 @@ struct cvk_command_queue : public _cl_command_queue,
}

cvk_buffer* get_or_create_printf_buffer() {
if (m_init_image_queue) {
cvk_error_fn("Could not get printf buffer from init-image queue");
CVK_ASSERT(false);
return nullptr;
}
if (!m_printf_buffer) {
cl_int status;
m_printf_buffer = cvk_buffer::create(
Expand Down Expand Up @@ -246,6 +257,8 @@ struct cvk_command_queue : public _cl_command_queue,
CHECK_RETURN cl_int end_current_command_batch(bool from_flush = false);
void executor();

bool m_init_image_queue;

cvk_device* m_device;
cl_command_queue_properties m_properties;
std::vector<cl_queue_properties> m_properties_array;
Expand Down
49 changes: 49 additions & 0 deletions tests/api/images.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define CL_USE_DEPRECATED_OPENCL_1_1_APIS

#include "testcl.hpp"
#include "utils.hpp"

TEST_F(WithContext, CreateImageLegacy) {
cl_image_format format = {CL_RGBA, CL_UNORM_INT8};
Expand Down Expand Up @@ -804,3 +805,51 @@ TEST_F(WithCommandQueue, 1DBufferImageReleaseAfterUnmap) {
Finish();
EXPECT_TRUE(destructor_called);
}

#ifdef CLVK_UNIT_TESTING_ENABLED

TEST_F(WithCommandQueue, ImageInitAtCreation) {
auto cfg =
CLVK_CONFIG_SCOPED_OVERRIDE(init_image_at_creation, bool, true, true);

const size_t IMAGE_WIDTH = 16;
const cl_uchar init_value = 0xAB;
std::vector<cl_uchar> host_data(IMAGE_WIDTH, init_value);
std::vector<cl_uchar> read_data(IMAGE_WIDTH, 0);

cl_image_format format = {CL_R, CL_UNSIGNED_INT8};
cl_image_desc desc = {
CL_MEM_OBJECT_IMAGE1D, // image_type
IMAGE_WIDTH, // image_width
1, // image_height
1, // image_depth
0, // image_array_size
0, // image_row_pitch
0, // image_slice_pitch
0, // num_mip_levels
0, // num_samples
nullptr, // buffer
};
auto image = CreateImage(CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, &format,
&desc, host_data.data());

// Read the data back from the image.
size_t origin[3] = {0, 0, 0};
size_t region[3] = {IMAGE_WIDTH, 1, 1};
EnqueueReadImage(image, CL_FALSE, origin, region, 0, 0, read_data.data());
Finish();

// Check that we got the values copied from the initial host pointer.
bool success = true;
for (int i = 0; i < IMAGE_WIDTH; ++i) {
auto val = read_data[i];
if (val != init_value) {
printf("Failed comparison at data[%d]: expected %d but got %d\n", i,
init_value, val);
success = false;
}
}
EXPECT_TRUE(success);
}

#endif

0 comments on commit 2531142

Please sign in to comment.