summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Steckelmacher <steckdenis@yahoo.fr>2011-07-26 18:05:49 +0200
committerDenis Steckelmacher <steckdenis@yahoo.fr>2011-07-26 18:05:49 +0200
commita038e07d3998624e0b9679c837fa008187d37e3d (patch)
tree66d9a094293d3585d982246065b1bd4615e6a938
parent0092eb928ce15476e8d4303512be38f91a00fae4 (diff)
Implement cl{Read,Write}BufferRect.
-rw-r--r--src/api/api_enqueue.cpp76
-rw-r--r--src/core/cpu/worker.cpp52
-rw-r--r--src/core/events.cpp193
-rw-r--r--src/core/events.h73
-rw-r--r--tests/test_commandqueue.cpp112
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;
}