diff options
author | Denis Steckelmacher <steckdenis@yahoo.fr> | 2011-07-26 18:05:49 +0200 |
---|---|---|
committer | Denis Steckelmacher <steckdenis@yahoo.fr> | 2011-07-26 18:05:49 +0200 |
commit | a038e07d3998624e0b9679c837fa008187d37e3d (patch) | |
tree | 66d9a094293d3585d982246065b1bd4615e6a938 | |
parent | 0092eb928ce15476e8d4303512be38f91a00fae4 (diff) |
Implement cl{Read,Write}BufferRect.
-rw-r--r-- | src/api/api_enqueue.cpp | 76 | ||||
-rw-r--r-- | src/core/cpu/worker.cpp | 52 | ||||
-rw-r--r-- | src/core/events.cpp | 193 | ||||
-rw-r--r-- | src/core/events.h | 73 | ||||
-rw-r--r-- | tests/test_commandqueue.cpp | 112 |
5 files changed, 506 insertions, 0 deletions
diff --git a/src/api/api_enqueue.cpp b/src/api/api_enqueue.cpp index 4ee94ae..f07bf6b 100644 --- a/src/api/api_enqueue.cpp +++ b/src/api/api_enqueue.cpp @@ -103,6 +103,82 @@ clEnqueueWriteBuffer(cl_command_queue command_queue, } cl_int +clEnqueueReadBufferRect(cl_command_queue command_queue, + cl_mem buffer, + cl_bool blocking_read, + const size_t * buffer_origin, + const size_t * host_origin, + const size_t * region, + size_t buffer_row_pitch, + size_t buffer_slice_pitch, + size_t host_row_pitch, + size_t host_slice_pitch, + void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) +{ + cl_int rs = CL_SUCCESS; + + if (!command_queue) + return CL_INVALID_COMMAND_QUEUE; + + Coal::ReadBufferRectEvent *command = new Coal::ReadBufferRectEvent( + (Coal::CommandQueue *)command_queue, + (Coal::MemObject *)buffer, + buffer_origin, host_origin, region, buffer_row_pitch, buffer_slice_pitch, + host_row_pitch, host_slice_pitch, 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 +clEnqueueWriteBufferRect(cl_command_queue command_queue, + cl_mem buffer, + cl_bool blocking_write, + const size_t * buffer_origin, + const size_t * host_origin, + const size_t * region, + size_t buffer_row_pitch, + size_t buffer_slice_pitch, + size_t host_row_pitch, + size_t host_slice_pitch, + const void * ptr, + cl_uint num_events_in_wait_list, + const cl_event * event_wait_list, + cl_event * event) +{ + cl_int rs = CL_SUCCESS; + + if (!command_queue) + return CL_INVALID_COMMAND_QUEUE; + + Coal::WriteBufferRectEvent *command = new Coal::WriteBufferRectEvent( + (Coal::CommandQueue *)command_queue, + (Coal::MemObject *)buffer, + buffer_origin, host_origin, region, buffer_row_pitch, buffer_slice_pitch, + host_row_pitch, host_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 clEnqueueCopyBuffer(cl_command_queue command_queue, cl_mem src_buffer, cl_mem dst_buffer, diff --git a/src/core/cpu/worker.cpp b/src/core/cpu/worker.cpp index 87b42ca..74c5caf 100644 --- a/src/core/cpu/worker.cpp +++ b/src/core/cpu/worker.cpp @@ -13,6 +13,19 @@ using namespace Coal; +static unsigned char *imageData(unsigned char *base, size_t x, size_t y, + size_t z, size_t row_pitch, size_t slice_pitch, + unsigned int bytes_per_pixel) +{ + unsigned char *result = base; + + result += (z * slice_pitch) + + (y * row_pitch) + + (x * bytes_per_pixel); + + return result; +} + void *worker(void *data) { CPUDevice *device = (CPUDevice *)data; @@ -63,6 +76,45 @@ void *worker(void *data) break; } + case Event::ReadBufferRect: + case Event::WriteBufferRect: + { + ReadWriteBufferRectEvent *e = (ReadWriteBufferRectEvent *)event; + CPUBuffer *buf = (CPUBuffer *)e->buffer()->deviceBuffer(device); + + unsigned char *host = (unsigned char *)e->ptr(); + unsigned char *mem = (unsigned char *)buf->data(); + + // Iterate over the lines to copy and use memcpy + for (size_t z=0; z<e->region(2); ++z) + { + for (size_t y=0; y<e->region(1); ++y) + { + unsigned char *h; + unsigned char *b; + + h = imageData(host, + e->host_origin(0), + y + e->host_origin(1), + z + e->host_origin(2), + e->host_row_pitch(), + e->host_slice_pitch(), + 1); + + b = imageData(mem, + e->buffer_origin(0), + y + e->buffer_origin(1), + z + e->buffer_origin(2), + e->buffer_row_pitch(), + e->buffer_slice_pitch(), + 1); + if (t == Event::ReadBufferRect) + std::memcpy(h, b, e->region(0)); + else + std::memcpy(b, h, e->region(0)); + } + } + } case Event::MapBuffer: // All was already done in CPUBuffer::initEventDeviceData() break; diff --git a/src/core/events.cpp b/src/core/events.cpp index 325c170..a591128 100644 --- a/src/core/events.cpp +++ b/src/core/events.cpp @@ -678,3 +678,196 @@ void UserEvent::flushQueues() for (it = p_dependent_queues.begin(); it != p_dependent_queues.end(); ++it) (*it)->pushEventsOnDevice(); } + +/* + * ReadWriteBufferRectEvent + */ +ReadWriteBufferRectEvent::ReadWriteBufferRectEvent(CommandQueue *parent, + MemObject *buffer, + const size_t buffer_origin[3], + const size_t host_origin[3], + const size_t region[3], + size_t buffer_row_pitch, + size_t buffer_slice_pitch, + size_t host_row_pitch, + size_t host_slice_pitch, + void *ptr, + cl_uint num_events_in_wait_list, + const Event **event_wait_list, + cl_int *errcode_ret) +: BufferEvent (parent, buffer, num_events_in_wait_list, event_wait_list, + errcode_ret), p_ptr(ptr) +{ + if (!ptr) + { + *errcode_ret = CL_INVALID_VALUE; + return; + } + + // Copy the vectors + std::memcpy(&p_buffer_origin, buffer_origin, 3 * sizeof(size_t)); + std::memcpy(&p_host_origin, host_origin, 3 * sizeof(size_t)); + + for (unsigned int i=0; i<3; ++i) + { + if (!region[i]) + { + *errcode_ret = CL_INVALID_VALUE; + return; + } + + p_region[i] = region[i]; + } + // Compute the pitches + p_buffer_row_pitch = region[0]; + + if (buffer_row_pitch) + { + if (buffer_row_pitch < p_buffer_row_pitch) + { + *errcode_ret = CL_INVALID_VALUE; + return; + } + + p_buffer_row_pitch = buffer_row_pitch; + } + + p_buffer_slice_pitch = region[1] * p_buffer_row_pitch; + + if (buffer_slice_pitch) + { + if (buffer_slice_pitch < p_buffer_slice_pitch) + { + *errcode_ret = CL_INVALID_VALUE; + return; + } + + p_buffer_slice_pitch = buffer_slice_pitch; + } + + p_host_row_pitch = region[0]; + + if (host_row_pitch) + { + if (host_row_pitch < p_host_row_pitch) + { + *errcode_ret = CL_INVALID_VALUE; + return; + } + + p_host_row_pitch = host_row_pitch; + } + + p_host_slice_pitch = region[1] * p_host_row_pitch; + + if (host_slice_pitch) + { + if (host_slice_pitch < p_host_slice_pitch) + { + *errcode_ret = CL_INVALID_VALUE; + return; + } + + p_host_slice_pitch = host_slice_pitch; + } + + // Check for out-of-bounds + if (buffer_origin[0] + region[0] > p_buffer_row_pitch || + (buffer_origin[1] + region[1]) * p_buffer_row_pitch > p_buffer_slice_pitch || + (buffer_origin[2] + region[2]) * p_buffer_slice_pitch > buffer->size()) + { + *errcode_ret = CL_INVALID_VALUE; + return; + } +} + +size_t ReadWriteBufferRectEvent::buffer_origin(unsigned int index) const +{ + return p_buffer_origin[index]; +} + +size_t ReadWriteBufferRectEvent::host_origin(unsigned int index) const +{ + return p_host_origin[index]; +} + +size_t ReadWriteBufferRectEvent::region(unsigned int index) const +{ + return p_region[index]; +} + +size_t ReadWriteBufferRectEvent::buffer_row_pitch() const +{ + return p_buffer_row_pitch; +} + +size_t ReadWriteBufferRectEvent::buffer_slice_pitch() const +{ + return p_buffer_slice_pitch; +} + +size_t ReadWriteBufferRectEvent::host_row_pitch() const +{ + return p_host_row_pitch; +} + +size_t ReadWriteBufferRectEvent::host_slice_pitch() const +{ + return p_host_slice_pitch; +} + +void *ReadWriteBufferRectEvent::ptr() const +{ + return p_ptr; +} + +ReadBufferRectEvent::ReadBufferRectEvent (CommandQueue *parent, + MemObject *buffer, + const size_t buffer_origin[3], + const size_t host_origin[3], + const size_t region[3], + size_t buffer_row_pitch, + size_t buffer_slice_pitch, + size_t host_row_pitch, + size_t host_slice_pitch, + void *ptr, + cl_uint num_events_in_wait_list, + const Event **event_wait_list, + 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, + event_wait_list, errcode_ret) +{ +} + +Event::Type ReadBufferRectEvent::type() const +{ + return ReadBufferRect; +} + +WriteBufferRectEvent::WriteBufferRectEvent (CommandQueue *parent, + MemObject *buffer, + const size_t buffer_origin[3], + const size_t host_origin[3], + const size_t region[3], + size_t buffer_row_pitch, + size_t buffer_slice_pitch, + size_t host_row_pitch, + size_t host_slice_pitch, + void *ptr, + cl_uint num_events_in_wait_list, + const Event **event_wait_list, + 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, + event_wait_list, errcode_ret) +{ +} + +Event::Type WriteBufferRectEvent::type() const +{ + return WriteBufferRect; +} + diff --git a/src/core/events.h b/src/core/events.h index 46eb2c2..d16e26b 100644 --- a/src/core/events.h +++ b/src/core/events.h @@ -121,6 +121,79 @@ class UnmapBufferEvent : public BufferEvent void *p_mapping; }; +class ReadWriteBufferRectEvent : public BufferEvent +{ + public: + ReadWriteBufferRectEvent(CommandQueue *parent, + MemObject *buffer, + const size_t buffer_origin[3], + const size_t host_origin[3], + const size_t region[3], + size_t buffer_row_pitch, + size_t buffer_slice_pitch, + size_t host_row_pitch, + size_t host_slice_pitch, + void *ptr, + cl_uint num_events_in_wait_list, + const Event **event_wait_list, + cl_int *errcode_ret); + + size_t buffer_origin(unsigned int index) const; + size_t host_origin(unsigned int index) const; + size_t region(unsigned int index) const; + size_t buffer_row_pitch() const; + size_t buffer_slice_pitch() const; + size_t host_row_pitch() const; + size_t host_slice_pitch() const; + void *ptr() const; + + private: + size_t p_buffer_origin[3], p_host_origin[3], p_region[3]; + size_t p_buffer_row_pitch, p_buffer_slice_pitch; + size_t p_host_row_pitch, p_host_slice_pitch; + void *p_ptr; +}; + +class ReadBufferRectEvent : public ReadWriteBufferRectEvent +{ + public: + ReadBufferRectEvent(CommandQueue *parent, + MemObject *buffer, + const size_t buffer_origin[3], + const size_t host_origin[3], + const size_t region[3], + size_t buffer_row_pitch, + size_t buffer_slice_pitch, + size_t host_row_pitch, + size_t host_slice_pitch, + void *ptr, + cl_uint num_events_in_wait_list, + const Event **event_wait_list, + cl_int *errcode_ret); + + Type type() const; +}; + +class WriteBufferRectEvent : public ReadWriteBufferRectEvent +{ + public: + WriteBufferRectEvent(CommandQueue *parent, + MemObject *buffer, + const size_t buffer_origin[3], + const size_t host_origin[3], + const size_t region[3], + size_t buffer_row_pitch, + size_t buffer_slice_pitch, + size_t host_row_pitch, + size_t host_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/tests/test_commandqueue.cpp b/tests/test_commandqueue.cpp index 589430b..b3394e9 100644 --- a/tests/test_commandqueue.cpp +++ b/tests/test_commandqueue.cpp @@ -1,3 +1,6 @@ +#include <cstring> +#include <iostream> + #include "test_commandqueue.h" #include "CL/cl.h" @@ -342,6 +345,114 @@ START_TEST (test_events) } END_TEST +START_TEST (test_read_write_rect) +{ + cl_platform_id platform = 0; + cl_device_id device; + cl_context ctx; + cl_command_queue queue; + cl_int result; + cl_mem buf; + + // Grid xyz = (5 x 7 x 2) + unsigned char grid[70] = { + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 1, 2, 2, 2, 1, + 1, 2, 3, 2, 1, + 1, 2, 2, 2, 1, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + 0, 0, 1, 0, 0, + 0, 0, 2, 0, 0, + 0, 1, 3, 1, 0, + 0, 2, 3, 2, 0, + 1, 3, 3, 3, 1, + 2, 3, 3, 3, 2, + 3, 3, 3, 3, 3 + }; + + // Middle of the "image" : 3 x 3 x 2 centered at (3, 3) + unsigned char part[18] = { + 2, 2, 2, + 2, 3, 2, + 2, 2, 2, + + 1, 3, 1, + 2, 3, 2, + 3, 3, 3 + }; + + unsigned char buffer[70], buffer_part[18]; + size_t host_origin[3] = {0, 0, 0}; + size_t buf_origin[3] = {0, 0, 0}; + size_t region[3] = {5, 7, 2}; + + 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" + ); + + buf = clCreateBuffer(ctx, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, + sizeof(buffer), buffer, &result); + fail_if( + result != CL_SUCCESS, + "cannot create a valid CL_MEM_USE_HOST_PTR read-write buffer" + ); + + // Write grid into buffer + result = clEnqueueWriteBufferRect(queue, buf, 1, buf_origin, host_origin, + region, 0, 0, 0, 0, grid, 0, 0, 0); + std::cout << result << std::endl; + fail_if( + result != CL_SUCCESS, + "cannot enqueue a blocking write buffer rect event with pitches guessed" + ); + fail_if( + std::memcmp(buffer, grid, sizeof(buffer)) != 0, + "buffer doesn't contain the data" + ); + + // Read it back into a temporary region + buf_origin[0] = 1; + buf_origin[1] = 2; + buf_origin[2] = 0; + // host_origin remains (0, 0, 0) + region[0] = 3; + region[1] = 3; + region[2] = 2; + + result = clEnqueueReadBufferRect(queue, buf, 1, buf_origin, host_origin, + region, 5, 5*7, 0, 0, buffer_part, 0, 0, 0); + fail_if( + result != CL_SUCCESS, + "unable to queue a blocking write buffer rect event with host pitches guessed" + ); + fail_if( + std::memcmp(buffer_part, part, sizeof(part)) != 0, + "the part of the buffer was not correctly read" + ); + + clReleaseMemObject(buf); + clReleaseCommandQueue(queue); + clReleaseContext(ctx); +} +END_TEST + TCase *cl_commandqueue_tcase_create(void) { TCase *tc = NULL; @@ -350,5 +461,6 @@ TCase *cl_commandqueue_tcase_create(void) tcase_add_test(tc, test_get_command_queue_info); tcase_add_test(tc, test_object_tree); tcase_add_test(tc, test_events); + tcase_add_test(tc, test_read_write_rect); return tc; } |