diff options
author | Denis Steckelmacher <steckdenis@yahoo.fr> | 2011-07-30 15:20:45 +0200 |
---|---|---|
committer | Denis Steckelmacher <steckdenis@yahoo.fr> | 2011-07-30 15:20:45 +0200 |
commit | e5f4415b7350c1f6ff59c1e0ea4a50528cfd52b2 (patch) | |
tree | 3c85297a0c6ea5acccc35291ecc8291939312fd2 | |
parent | 1eaf54d98364b275fb33b7b4671b2fe660cb678b (diff) |
Implement clEnqueueReadImage and clEnqueueWriteImage
-rw-r--r-- | src/api/api_enqueue.cpp | 47 | ||||
-rw-r--r-- | src/core/cpu/worker.cpp | 4 | ||||
-rw-r--r-- | src/core/events.cpp | 107 | ||||
-rw-r--r-- | src/core/events.h | 53 | ||||
-rw-r--r-- | src/core/memobject.cpp | 80 | ||||
-rw-r--r-- | src/core/memobject.h | 1 | ||||
-rw-r--r-- | tests/test_commandqueue.cpp | 88 | ||||
-rw-r--r-- | tests/test_mem.cpp | 2 |
8 files changed, 358 insertions, 24 deletions
diff --git a/src/api/api_enqueue.cpp b/src/api/api_enqueue.cpp index 8f5e550..d2ce092 100644 --- a/src/api/api_enqueue.cpp +++ b/src/api/api_enqueue.cpp @@ -1,6 +1,7 @@ #include <CL/cl.h> #include <core/events.h> +#include <core/memobject.h> static inline cl_int queueEvent(Coal::CommandQueue *queue, Coal::Event *command, @@ -203,7 +204,7 @@ clEnqueueCopyBufferRect(cl_command_queue command_queue, (Coal::MemObject *)src_buffer, (Coal::MemObject *)dst_buffer, src_origin, dst_origin, region, src_row_pitch, src_slice_pitch, - dst_row_pitch, dst_slice_pitch, + dst_row_pitch, dst_slice_pitch, 1, num_events_in_wait_list, (const Coal::Event **)event_wait_list, &rs ); @@ -262,7 +263,29 @@ clEnqueueReadImage(cl_command_queue command_queue, const cl_event * event_wait_list, cl_event * event) { - return 0; + cl_int rs = CL_SUCCESS; + + if (!command_queue) + return CL_INVALID_COMMAND_QUEUE; + + if (!image || (image->type() != Coal::MemObject::Image2D && + image->type() != Coal::MemObject::Image3D)) + return CL_INVALID_MEM_OBJECT; + + Coal::ReadImageEvent *command = new Coal::ReadImageEvent( + (Coal::CommandQueue *)command_queue, + (Coal::Image2D *)image, + origin, region, row_pitch, slice_pitch, (void *)ptr, + num_events_in_wait_list, (const Coal::Event **)event_wait_list, &rs + ); + + if (rs != CL_SUCCESS) + { + delete command; + return rs; + } + + return queueEvent(command_queue, command, event, blocking_read); } cl_int @@ -278,7 +301,25 @@ clEnqueueWriteImage(cl_command_queue command_queue, const cl_event * event_wait_list, cl_event * event) { - return 0; + cl_int rs = CL_SUCCESS; + + if (!command_queue) + return CL_INVALID_COMMAND_QUEUE; + + Coal::WriteImageEvent *command = new Coal::WriteImageEvent( + (Coal::CommandQueue *)command_queue, + (Coal::Image2D *)image, + origin, region, row_pitch, slice_pitch, (void *)ptr, + num_events_in_wait_list, (const Coal::Event **)event_wait_list, &rs + ); + + if (rs != CL_SUCCESS) + { + delete command; + return rs; + } + + return queueEvent(command_queue, command, event, blocking_write); } cl_int diff --git a/src/core/cpu/worker.cpp b/src/core/cpu/worker.cpp index 595f5a1..d7606d1 100644 --- a/src/core/cpu/worker.cpp +++ b/src/core/cpu/worker.cpp @@ -89,6 +89,8 @@ void *worker(void *data) case Event::ReadBufferRect: case Event::WriteBufferRect: case Event::CopyBufferRect: + case Event::ReadImage: + case Event::WriteImage: { // src = buffer and dst = mem if note copy ReadWriteCopyBufferRectEvent *e = (ReadWriteCopyBufferRectEvent *)event; @@ -137,7 +139,7 @@ void *worker(void *data) e->src_slice_pitch(), 1); - if (t == Event::WriteBufferRect) + if (t == Event::WriteBufferRect || t == Event::WriteImage) std::memcpy(s, d, e->region(0)); // Write dest (memory) in src else std::memcpy(d, s, e->region(0)); // Write src (buffer) in dest (memory), or copy the buffers diff --git a/src/core/events.cpp b/src/core/events.cpp index 70264a7..b6923d7 100644 --- a/src/core/events.cpp +++ b/src/core/events.cpp @@ -6,6 +6,7 @@ #include <cstdlib> #include <cstring> +#include <iostream> using namespace Coal; @@ -762,6 +763,7 @@ ReadWriteCopyBufferRectEvent::ReadWriteCopyBufferRectEvent(CommandQueue *parent, size_t src_slice_pitch, size_t dst_row_pitch, size_t dst_slice_pitch, + unsigned int bytes_per_element, cl_uint num_events_in_wait_list, const Event **event_wait_list, cl_int *errcode_ret) @@ -769,8 +771,15 @@ ReadWriteCopyBufferRectEvent::ReadWriteCopyBufferRectEvent(CommandQueue *parent, errcode_ret) { // Copy the vectors - std::memcpy(&p_src_origin, src_origin, 3 * sizeof(size_t)); - std::memcpy(&p_dst_origin, dst_origin, 3 * sizeof(size_t)); + if (src_origin) + std::memcpy(&p_src_origin, src_origin, 3 * sizeof(size_t)); + else + std::memset(&p_src_origin, 0, 3 * sizeof(size_t)); + + if (dst_origin) + std::memcpy(&p_dst_origin, dst_origin, 3 * sizeof(size_t)); + else + std::memset(&p_dst_origin, 0, 3 * sizeof(size_t)); for (unsigned int i=0; i<3; ++i) { @@ -782,8 +791,14 @@ ReadWriteCopyBufferRectEvent::ReadWriteCopyBufferRectEvent(CommandQueue *parent, p_region[i] = region[i]; } + + // Multiply the elements (for images) + p_region[0] *= bytes_per_element; + p_src_origin[0] *= bytes_per_element; + p_dst_origin[0] *= bytes_per_element; + // Compute the pitches - p_src_row_pitch = region[0]; + p_src_row_pitch = p_region[0]; if (src_row_pitch) { @@ -796,7 +811,7 @@ ReadWriteCopyBufferRectEvent::ReadWriteCopyBufferRectEvent(CommandQueue *parent, p_src_row_pitch = src_row_pitch; } - p_src_slice_pitch = region[1] * p_src_row_pitch; + p_src_slice_pitch = p_region[1] * p_src_row_pitch; if (src_slice_pitch) { @@ -809,7 +824,7 @@ ReadWriteCopyBufferRectEvent::ReadWriteCopyBufferRectEvent(CommandQueue *parent, p_src_slice_pitch = src_slice_pitch; } - p_dst_row_pitch = region[0]; + p_dst_row_pitch = p_region[0]; if (dst_row_pitch) { @@ -822,7 +837,7 @@ ReadWriteCopyBufferRectEvent::ReadWriteCopyBufferRectEvent(CommandQueue *parent, p_dst_row_pitch = dst_row_pitch; } - p_dst_slice_pitch = region[1] * p_dst_row_pitch; + p_dst_slice_pitch = p_region[1] * p_dst_row_pitch; if (dst_slice_pitch) { @@ -886,13 +901,14 @@ CopyBufferRectEvent::CopyBufferRectEvent(CommandQueue *parent, size_t src_slice_pitch, size_t dst_row_pitch, size_t dst_slice_pitch, + unsigned int bytes_per_element, cl_uint num_events_in_wait_list, const Event **event_wait_list, cl_int *errcode_ret) : ReadWriteCopyBufferRectEvent(parent, source, src_origin, dst_origin, region, src_row_pitch, src_slice_pitch, dst_row_pitch, - dst_slice_pitch, num_events_in_wait_list, - event_wait_list, errcode_ret), + dst_slice_pitch, bytes_per_element, + num_events_in_wait_list, event_wait_list, errcode_ret), p_destination(destination) { if (!destination) @@ -902,7 +918,7 @@ CopyBufferRectEvent::CopyBufferRectEvent(CommandQueue *parent, } // Check for out-of-bounds - if (src_origin[0] + region[0] > this->src_row_pitch() || + if ((src_origin[0] + region[0]) * bytes_per_element > this->src_row_pitch() || (src_origin[1] + region[1]) * this->src_row_pitch() > this->src_slice_pitch() || (src_origin[2] + region[2]) * this->src_slice_pitch() > source->size()) { @@ -910,7 +926,7 @@ CopyBufferRectEvent::CopyBufferRectEvent(CommandQueue *parent, return; } - if (dst_origin[0] + region[0] > this->dst_row_pitch() || + if ((dst_origin[0] + region[0]) * bytes_per_element > this->dst_row_pitch() || (dst_origin[1] + region[1]) * this->dst_row_pitch() > this->dst_slice_pitch() || (dst_origin[2] + region[2]) * this->dst_slice_pitch() > destination->size()) { @@ -960,12 +976,13 @@ ReadWriteBufferRectEvent::ReadWriteBufferRectEvent(CommandQueue *parent, size_t host_row_pitch, size_t host_slice_pitch, void *ptr, + unsigned int bytes_per_element, cl_uint num_events_in_wait_list, const Event **event_wait_list, cl_int *errcode_ret) : ReadWriteCopyBufferRectEvent(parent, buffer, buffer_origin, host_origin, region, buffer_row_pitch, buffer_slice_pitch, - host_row_pitch, host_slice_pitch, + host_row_pitch, host_slice_pitch, bytes_per_element, num_events_in_wait_list, event_wait_list, errcode_ret), p_ptr(ptr) { @@ -976,10 +993,11 @@ ReadWriteBufferRectEvent::ReadWriteBufferRectEvent(CommandQueue *parent, } // Check for out-of-bounds - if (buffer_origin[0] + region[0] > src_row_pitch() || + if ((buffer_origin[0] + region[0]) * bytes_per_element > src_row_pitch() || (buffer_origin[1] + region[1]) * src_row_pitch() > src_slice_pitch() || (buffer_origin[2] + region[2]) * src_slice_pitch() > buffer->size()) { + std::cout << buffer_origin[0] << '+' << region[0] << '*' << bytes_per_element << '>' << src_row_pitch() << std::endl; *errcode_ret = CL_INVALID_VALUE; return; } @@ -1005,7 +1023,7 @@ ReadBufferRectEvent::ReadBufferRectEvent (CommandQueue *parent, cl_int *errcode_ret) : ReadWriteBufferRectEvent(parent, buffer, buffer_origin, host_origin, region, buffer_row_pitch, buffer_slice_pitch, host_row_pitch, - host_slice_pitch, ptr, num_events_in_wait_list, + host_slice_pitch, ptr, 1, num_events_in_wait_list, event_wait_list, errcode_ret) { } @@ -1030,7 +1048,7 @@ WriteBufferRectEvent::WriteBufferRectEvent (CommandQueue *parent, cl_int *errcode_ret) : ReadWriteBufferRectEvent (parent, buffer, buffer_origin, host_origin, region, buffer_row_pitch, buffer_slice_pitch, host_row_pitch, - host_slice_pitch, ptr, num_events_in_wait_list, + host_slice_pitch, ptr, 1, num_events_in_wait_list, event_wait_list, errcode_ret) { } @@ -1040,3 +1058,64 @@ Event::Type WriteBufferRectEvent::type() const return WriteBufferRect; } +ReadWriteImageEvent::ReadWriteImageEvent (CommandQueue *parent, + Image2D *image, + const size_t origin[3], + const size_t region[3], + size_t row_pitch, + size_t slice_pitch, + void *ptr, + cl_uint num_events_in_wait_list, + const Event **event_wait_list, + cl_int *errcode_ret) +: ReadWriteBufferRectEvent(parent, image, origin, 0, region, image->row_pitch(), + (image->type() == MemObject::Image3D ? + ((Image3D *)image)->slice_pitch() : + 0), row_pitch, slice_pitch, ptr, image->pixel_size(), + num_events_in_wait_list, event_wait_list, errcode_ret) +{ + if (image->type() == MemObject::Image2D && + (origin[2] != 0 || region[2] != 1)) + { + *errcode_ret = CL_INVALID_VALUE; + return; + } +} + +ReadImageEvent::ReadImageEvent(CommandQueue *parent, + Image2D *image, + const size_t origin[3], + const size_t region[3], + size_t row_pitch, + size_t slice_pitch, + void *ptr, + cl_uint num_events_in_wait_list, + const Event **event_wait_list, + cl_int *errcode_ret) +: ReadWriteImageEvent(parent, image, origin, region, row_pitch, slice_pitch, ptr, + num_events_in_wait_list, event_wait_list, errcode_ret) +{} + +Event::Type ReadImageEvent::type() const +{ + return Event::ReadImage; +} + +WriteImageEvent::WriteImageEvent(CommandQueue *parent, + Image2D *image, + const size_t origin[3], + const size_t region[3], + size_t row_pitch, + size_t slice_pitch, + void *ptr, + cl_uint num_events_in_wait_list, + const Event **event_wait_list, + cl_int *errcode_ret) +: ReadWriteImageEvent (parent, image, origin, region, row_pitch, slice_pitch, ptr, + num_events_in_wait_list, event_wait_list, errcode_ret) +{} + +Event::Type WriteImageEvent::type() const +{ + return Event::WriteImage; +} diff --git a/src/core/events.h b/src/core/events.h index 0376007..fe2b7b0 100644 --- a/src/core/events.h +++ b/src/core/events.h @@ -10,6 +10,7 @@ namespace Coal { class MemObject; +class Image2D; class Kernel; class DeviceKernel; class DeviceInterface; @@ -164,6 +165,7 @@ class ReadWriteCopyBufferRectEvent : public BufferEvent size_t src_slice_pitch, size_t dst_row_pitch, size_t dst_slice_pitch, + unsigned int bytes_per_element, cl_uint num_events_in_wait_list, const Event **event_wait_list, cl_int *errcode_ret); @@ -196,6 +198,7 @@ class CopyBufferRectEvent : public ReadWriteCopyBufferRectEvent size_t src_slice_pitch, size_t dst_row_pitch, size_t dst_slice_pitch, + unsigned int bytes_per_element, cl_uint num_events_in_wait_list, const Event **event_wait_list, cl_int *errcode_ret); @@ -220,6 +223,7 @@ class ReadWriteBufferRectEvent : public ReadWriteCopyBufferRectEvent size_t host_row_pitch, size_t host_slice_pitch, void *ptr, + unsigned int bytes_per_element, cl_uint num_events_in_wait_list, const Event **event_wait_list, cl_int *errcode_ret); @@ -270,6 +274,55 @@ class WriteBufferRectEvent : public ReadWriteBufferRectEvent Type type() const; }; +class ReadWriteImageEvent : public ReadWriteBufferRectEvent +{ + public: + ReadWriteImageEvent(CommandQueue *parent, + Image2D *image, + const size_t origin[3], + const size_t region[3], + size_t row_pitch, + size_t slice_pitch, + void *ptr, + cl_uint num_events_in_wait_list, + const Event **event_wait_list, + cl_int *errcode_ret); +}; + +class ReadImageEvent : public ReadWriteImageEvent +{ + public: + ReadImageEvent(CommandQueue *parent, + Image2D *image, + const size_t origin[3], + const size_t region[3], + size_t row_pitch, + size_t slice_pitch, + void *ptr, + cl_uint num_events_in_wait_list, + const Event **event_wait_list, + cl_int *errcode_ret); + + Type type() const; +}; + +class WriteImageEvent : public ReadWriteImageEvent +{ + public: + WriteImageEvent(CommandQueue *parent, + Image2D *image, + const size_t origin[3], + const size_t region[3], + size_t row_pitch, + size_t slice_pitch, + void *ptr, + cl_uint num_events_in_wait_list, + const Event **event_wait_list, + cl_int *errcode_ret); + + Type type() const; +}; + class NativeKernelEvent : public Event { public: diff --git a/src/core/memobject.cpp b/src/core/memobject.cpp index 048e4e0..32fa49d 100644 --- a/src/core/memobject.cpp +++ b/src/core/memobject.cpp @@ -5,6 +5,7 @@ #include <cstdlib> #include <cstring> +#include <iostream> using namespace Coal; @@ -463,6 +464,69 @@ Image2D::Image2D(Context *ctx, size_t width, size_t height, size_t row_pitch, p_format = *format; + // Check format descriptor + switch (p_format.image_channel_data_type) + { + case CL_UNORM_INT_101010: + case CL_UNORM_SHORT_555: + case CL_UNORM_SHORT_565: + if (p_format.image_channel_order != CL_RGB || + p_format.image_channel_order != CL_RGBx) + { + *errcode_ret = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR; + return; + } + } + + switch (p_format.image_channel_order) + { + case CL_LUMINANCE: + case CL_INTENSITY: + switch (p_format.image_channel_data_type) + { + case CL_UNORM_INT8: + case CL_UNORM_INT16: + case CL_SNORM_INT8: + case CL_SNORM_INT16: + case CL_HALF_FLOAT: + case CL_FLOAT: + break; + default: + *errcode_ret = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR; + return; + } + break; + + case CL_RGB: + case CL_RGBx: + switch (p_format.image_channel_data_type) + { + case CL_UNORM_SHORT_555: + case CL_UNORM_SHORT_565: + case CL_UNORM_INT_101010: + break; + default: + *errcode_ret = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR; + return; + } + break; + + case CL_ARGB: + case CL_BGRA: + switch (p_format.image_channel_data_type) + { + case CL_UNORM_INT8: + case CL_SNORM_INT8: + case CL_SIGNED_INT8: + case CL_UNSIGNED_INT8: + break; + default: + *errcode_ret = CL_INVALID_IMAGE_FORMAT_DESCRIPTOR; + return; + } + break; + } + // Row pitch p_row_pitch = width * pixel_size(p_format); @@ -636,15 +700,16 @@ size_t Image2D::pixel_size(const cl_image_format &format) multiplier = 2; break; - case CL_RGB: - case CL_RGBx: - multiplier = 3; - break; - case CL_RGBA: case CL_ARGB: case CL_BGRA: multiplier = 4; + break; + + case CL_RGBx: + case CL_RGB: + multiplier = 0; // Only special data types allowed (565, 555, etc) + break; default: return 0; @@ -662,6 +727,11 @@ size_t Image2D::pixel_size(const cl_image_format &format) } } +size_t Image2D::pixel_size() const +{ + return pixel_size(p_format); +} + /* * Image3D */ diff --git a/src/core/memobject.h b/src/core/memobject.h index 7a91879..dce70b5 100644 --- a/src/core/memobject.h +++ b/src/core/memobject.h @@ -116,6 +116,7 @@ class Image2D : public MemObject static size_t element_size(const cl_image_format &format); static size_t pixel_size(const cl_image_format &format); + size_t pixel_size() const; private: size_t p_width, p_height, p_row_pitch; diff --git a/tests/test_commandqueue.cpp b/tests/test_commandqueue.cpp index ea27497..a97b1de 100644 --- a/tests/test_commandqueue.cpp +++ b/tests/test_commandqueue.cpp @@ -554,6 +554,93 @@ START_TEST (test_copy_buffer) } END_TEST +START_TEST (test_read_write_image) +{ + cl_platform_id platform = 0; + cl_device_id device; + cl_context ctx; + cl_command_queue queue; + cl_mem image2d; + cl_int result; + + unsigned char image2d_data_24bpp[3*3*4] = { + 255, 0, 0, 0, 0, 255, 0, 0, 128, 128, 128, 0, + 0, 0, 255, 0, 255, 255, 0, 0, 0, 128, 0, 0, + 255, 128, 0, 0, 128, 0, 255, 0, 0, 0, 0, 0 + }; + + unsigned char image2d_part_24bpp[2*2*4] = { + 255, 0, 0, 0, 0, 255, 0, 0, + 0, 0, 255, 0, 255, 255, 0, 0 + }; + + unsigned char image2d_buffer[3*3*4]; + unsigned char image2d_part[2*2*4]; + + cl_image_format fmt; + + fmt.image_channel_data_type = CL_UNORM_INT8; + fmt.image_channel_order = CL_RGBA; + + size_t origin[3] = {0, 0, 0}; + size_t region[3] = {3, 3, 1}; + + result = clGetDeviceIDs(platform, CL_DEVICE_TYPE_DEFAULT, 1, &device, 0); + fail_if( + result != CL_SUCCESS, + "unable to get the default device" + ); + + ctx = clCreateContext(0, 1, &device, 0, 0, &result); + fail_if( + result != CL_SUCCESS || ctx == 0, + "unable to create a valid context" + ); + + queue = clCreateCommandQueue(ctx, device, 0, &result); + fail_if( + result != CL_SUCCESS || queue == 0, + "cannot create a command queue" + ); + + image2d = clCreateImage2D(ctx, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, &fmt, + 3, 3, 0, image2d_buffer, &result); + fail_if( + result != CL_SUCCESS || image2d == 0, + "cannot create a valid 3x3 image2D" + ); + + // Write data in buffer + result = clEnqueueWriteImage(queue, image2d, 1, origin, region, 0, 0, + image2d_data_24bpp, 0, 0, 0); + fail_if( + result != CL_SUCCESS, + "cannot enqueue a blocking write image event" + ); + + // Read it back + region[0] = 2; + region[1] = 2; + + result = clEnqueueReadImage(queue, image2d, 1, origin, region, 0, 0, + image2d_part, 0, 0, 0); + fail_if( + result != CL_SUCCESS, + "cannot enqueue a blocking read image event" + ); + + // Compare + fail_if( + std::memcmp(image2d_part, image2d_part_24bpp, sizeof(image2d_part)) != 0, + "reading and writing images doesn't produce the correct result" + ); + + clReleaseMemObject(image2d); + clReleaseCommandQueue(queue); + clReleaseContext(ctx); +} +END_TEST + TCase *cl_commandqueue_tcase_create(void) { TCase *tc = NULL; @@ -564,5 +651,6 @@ TCase *cl_commandqueue_tcase_create(void) tcase_add_test(tc, test_events); tcase_add_test(tc, test_read_write_rect); tcase_add_test(tc, test_copy_buffer); + tcase_add_test(tc, test_read_write_image); return tc; } diff --git a/tests/test_mem.cpp b/tests/test_mem.cpp index 18b5d04..90f6180 100644 --- a/tests/test_mem.cpp +++ b/tests/test_mem.cpp @@ -270,7 +270,7 @@ START_TEST (test_images) cl_image_format fmt; fmt.image_channel_data_type = CL_UNORM_INT8; - fmt.image_channel_order = CL_RGBx; + fmt.image_channel_order = CL_RGBA; ctx = clCreateContextFromType(0, CL_DEVICE_TYPE_CPU, 0, 0, &result); fail_if( |