summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Steckelmacher <steckdenis@yahoo.fr>2011-08-01 14:57:40 +0200
committerDenis Steckelmacher <steckdenis@yahoo.fr>2011-08-01 14:57:40 +0200
commitce8975073e81ae54c8542646d146b43c741048e4 (patch)
tree3c656cebc8b247858daa1a0782e864146be5b066
parentaac90234d34bc2d6cee8461b692a740c56a140da (diff)
Implement clEnqueueCopyImageToBuffer and clEnqueueCopyBufferToImage
Plus bug fixes regarding Image2D slice_pitch.
-rw-r--r--src/api/api_enqueue.cpp40
-rw-r--r--src/core/cpu/worker.cpp45
-rw-r--r--src/core/events.cpp151
-rw-r--r--src/core/events.h42
-rw-r--r--src/core/memobject.cpp6
-rw-r--r--src/core/memobject.h1
-rw-r--r--tests/test_commandqueue.cpp116
7 files changed, 366 insertions, 35 deletions
diff --git a/src/api/api_enqueue.cpp b/src/api/api_enqueue.cpp
index 1c28ee0..6ea5ef5 100644
--- a/src/api/api_enqueue.cpp
+++ b/src/api/api_enqueue.cpp
@@ -365,7 +365,25 @@ clEnqueueCopyImageToBuffer(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::CopyImageToBufferEvent *command = new Coal::CopyImageToBufferEvent(
+ (Coal::CommandQueue *)command_queue,
+ (Coal::Image2D *)src_image, (Coal::MemObject *)dst_buffer,
+ src_origin, region, dst_offset,
+ 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, false);
}
cl_int
@@ -379,7 +397,25 @@ clEnqueueCopyBufferToImage(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::CopyBufferToImageEvent *command = new Coal::CopyBufferToImageEvent(
+ (Coal::CommandQueue *)command_queue,
+ (Coal::MemObject *)src_buffer, (Coal::Image2D *)dst_image,
+ src_offset, dst_origin, region,
+ 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, false);
}
void *
diff --git a/src/core/cpu/worker.cpp b/src/core/cpu/worker.cpp
index 2c055e6..550dadf 100644
--- a/src/core/cpu/worker.cpp
+++ b/src/core/cpu/worker.cpp
@@ -92,6 +92,8 @@ void *worker(void *data)
case Event::ReadImage:
case Event::WriteImage:
case Event::CopyImage:
+ case Event::CopyBufferToImage:
+ case Event::CopyImageToBuffer:
{
// src = buffer and dst = mem if note copy
ReadWriteCopyBufferRectEvent *e = (ReadWriteCopyBufferRectEvent *)event;
@@ -100,20 +102,27 @@ void *worker(void *data)
unsigned char *src = (unsigned char *)src_buf->data();
unsigned char *dst;
- if (t == Event::CopyBufferRect || t == Event::CopyImage)
+ switch (t)
{
- CopyBufferRectEvent *cbre = (CopyBufferRectEvent *)e;
- CPUBuffer *dst_buf =
- (CPUBuffer *)cbre->destination()->deviceBuffer(device);
+ case Event::CopyBufferRect:
+ case Event::CopyImage:
+ case Event::CopyImageToBuffer:
+ case Event::CopyBufferToImage:
+ {
+ CopyBufferRectEvent *cbre = (CopyBufferRectEvent *)e;
+ CPUBuffer *dst_buf =
+ (CPUBuffer *)cbre->destination()->deviceBuffer(device);
- dst = (unsigned char *)dst_buf->data();
- }
- else
- {
- // dst = host memory location
- ReadWriteBufferRectEvent *rwbre = (ReadWriteBufferRectEvent *)e;
+ dst = (unsigned char *)dst_buf->data();
+ break;
+ }
+ default:
+ {
+ // dst = host memory location
+ ReadWriteBufferRectEvent *rwbre = (ReadWriteBufferRectEvent *)e;
- dst = (unsigned char *)rwbre->ptr();
+ dst = (unsigned char *)rwbre->ptr();
+ }
}
// Iterate over the lines to copy and use memcpy
@@ -140,6 +149,20 @@ void *worker(void *data)
e->src_slice_pitch(),
1);
+ // Copying and image to a buffer may need to add an offset
+ // to the buffer address (its rectangular origin is
+ // always (0, 0, 0)).
+ if (t == Event::CopyBufferToImage)
+ {
+ CopyBufferToImageEvent *cptie = (CopyBufferToImageEvent *)e;
+ s += cptie->offset();
+ }
+ else if (t == Event::CopyImageToBuffer)
+ {
+ CopyImageToBufferEvent *citbe = (CopyImageToBufferEvent *)e;
+ d += citbe->offset();
+ }
+
if (t == Event::WriteBufferRect || t == Event::WriteImage)
std::memcpy(s, d, e->region(0)); // Write dest (memory) in src
else
diff --git a/src/core/events.cpp b/src/core/events.cpp
index c1ac530..7cf6415 100644
--- a/src/core/events.cpp
+++ b/src/core/events.cpp
@@ -22,6 +22,8 @@ BufferEvent::BufferEvent(CommandQueue *parent,
: Event(parent, Queued, num_events_in_wait_list, event_wait_list, errcode_ret),
p_buffer(buffer)
{
+ if (*errcode_ret != CL_SUCCESS) return;
+
// Correct buffer
if (!buffer)
{
@@ -105,6 +107,8 @@ ReadWriteBufferEvent::ReadWriteBufferEvent(CommandQueue *parent,
: BufferEvent(parent, buffer, num_events_in_wait_list, event_wait_list, errcode_ret),
p_offset(offset), p_cb(cb), p_ptr(ptr)
{
+ if (*errcode_ret != CL_SUCCESS) return;
+
// Check for out-of-bounds reads
if (!ptr)
{
@@ -179,6 +183,8 @@ MapBufferEvent::MapBufferEvent(CommandQueue *parent,
: BufferEvent(parent, buffer, num_events_in_wait_list, event_wait_list, errcode_ret),
p_offset(offset), p_cb(cb), p_map_flags(map_flags)
{
+ if (*errcode_ret != CL_SUCCESS) return;
+
// Check flags
if (map_flags & ~(CL_MAP_READ | CL_MAP_WRITE))
{
@@ -228,6 +234,8 @@ UnmapBufferEvent::UnmapBufferEvent(CommandQueue *parent,
: BufferEvent(parent, buffer, num_events_in_wait_list, event_wait_list, errcode_ret),
p_mapping(mapped_addr)
{
+ if (*errcode_ret != CL_SUCCESS) return;
+
// TODO: Check that p_mapping is ok (will be done in the drivers)
if (!mapped_addr)
{
@@ -259,6 +267,8 @@ CopyBufferEvent::CopyBufferEvent(CommandQueue *parent,
errcode_ret), p_destination(destination), p_src_offset(src_offset),
p_dst_offset(dst_offset), p_cb(cb)
{
+ if (*errcode_ret != CL_SUCCESS) return;
+
if (!destination)
{
*errcode_ret = CL_INVALID_MEM_OBJECT;
@@ -352,6 +362,8 @@ NativeKernelEvent::NativeKernelEvent(CommandQueue *parent,
: Event (parent, Queued, num_events_in_wait_list, event_wait_list, errcode_ret),
p_user_func((void *)user_func), p_args(0)
{
+ if (*errcode_ret != CL_SUCCESS) return;
+
// Parameters sanity
if (!user_func)
{
@@ -475,6 +487,8 @@ KernelEvent::KernelEvent(CommandQueue *parent,
: Event(parent, Queued, num_events_in_wait_list, event_wait_list, errcode_ret),
p_kernel(kernel), p_work_dim(work_dim)
{
+ if (*errcode_ret != CL_SUCCESS) return;
+
*errcode_ret = CL_SUCCESS;
// Sanity checks
@@ -770,6 +784,8 @@ ReadWriteCopyBufferRectEvent::ReadWriteCopyBufferRectEvent(CommandQueue *parent,
: BufferEvent (parent, source, num_events_in_wait_list, event_wait_list,
errcode_ret)
{
+ if (*errcode_ret != CL_SUCCESS) return;
+
// Copy the vectors
if (src_origin)
std::memcpy(&p_src_origin, src_origin, 3 * sizeof(size_t));
@@ -911,6 +927,8 @@ CopyBufferRectEvent::CopyBufferRectEvent(CommandQueue *parent,
num_events_in_wait_list, event_wait_list, errcode_ret),
p_destination(destination)
{
+ if (*errcode_ret != CL_SUCCESS) return;
+
if (!destination)
{
*errcode_ret = CL_INVALID_MEM_OBJECT;
@@ -918,17 +936,17 @@ CopyBufferRectEvent::CopyBufferRectEvent(CommandQueue *parent,
}
// Check for out-of-bounds
- 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())
+ if ((p_src_origin[0] + p_region[0]) > p_src_row_pitch ||
+ (p_src_origin[1] + p_region[1]) * p_src_row_pitch > p_src_slice_pitch ||
+ (p_src_origin[2] + p_region[2]) * p_src_slice_pitch > source->size())
{
*errcode_ret = CL_INVALID_VALUE;
return;
}
- 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())
+ if ((p_dst_origin[0] + p_region[0]) > p_dst_row_pitch ||
+ (p_dst_origin[1] + p_region[1]) * p_dst_row_pitch > p_dst_slice_pitch ||
+ (p_dst_origin[2] + p_region[2]) * p_dst_slice_pitch > destination->size())
{
*errcode_ret = CL_INVALID_VALUE;
return;
@@ -941,8 +959,8 @@ CopyBufferRectEvent::CopyBufferRectEvent(CommandQueue *parent,
for (unsigned int i=0; i<3; ++i)
{
- if (dst_origin[i] < src_origin[i] && dst_origin[i] + region[i] > src_origin[i] ||
- src_origin[i] < dst_origin[i] && src_origin[i] + region[i] > dst_origin[i])
+ if ((p_dst_origin[i] < p_src_origin[i] && p_dst_origin[i] + p_region[i] > p_src_origin[i]) ||
+ (p_src_origin[i] < p_dst_origin[i] && p_src_origin[i] + p_region[i] > p_dst_origin[i]))
overlapping_dimensions++;
}
@@ -1006,6 +1024,8 @@ ReadWriteBufferRectEvent::ReadWriteBufferRectEvent(CommandQueue *parent,
num_events_in_wait_list, event_wait_list, errcode_ret),
p_ptr(ptr)
{
+ if (*errcode_ret != CL_SUCCESS) return;
+
if (!ptr)
{
*errcode_ret = CL_INVALID_VALUE;
@@ -1013,9 +1033,9 @@ ReadWriteBufferRectEvent::ReadWriteBufferRectEvent(CommandQueue *parent,
}
// Check for out-of-bounds
- 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())
+ if ((p_src_origin[0] + p_region[0]) > p_src_row_pitch ||
+ (p_src_origin[1] + p_region[1]) * p_src_row_pitch > p_src_slice_pitch ||
+ (p_src_origin[2] + p_region[2]) * p_src_slice_pitch > buffer->size())
{
*errcode_ret = CL_INVALID_VALUE;
return;
@@ -1088,11 +1108,12 @@ ReadWriteImageEvent::ReadWriteImageEvent (CommandQueue *parent,
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)
+ image->slice_pitch(), row_pitch, slice_pitch, ptr,
+ image->pixel_size(), num_events_in_wait_list,
+ event_wait_list, errcode_ret)
{
+ if (*errcode_ret != CL_SUCCESS) return;
+
if (image->type() == MemObject::Image2D &&
(origin[2] != 0 || region[2] != 1))
{
@@ -1155,15 +1176,13 @@ CopyImageEvent::CopyImageEvent(CommandQueue *parent,
const Event **event_wait_list,
cl_int *errcode_ret)
: CopyBufferRectEvent (parent, source, destination, src_origin, dst_origin,
- region, source->row_pitch(),
- (source->type() == MemObject::Image3D ?
- ((Image3D *)source)->slice_pitch() : 0),
- destination->row_pitch(),
- (destination->type() == MemObject::Image3D ?
- ((Image3D *)destination)->slice_pitch() : 0),
+ region, source->row_pitch(), source->slice_pitch(),
+ destination->row_pitch(), destination->slice_pitch(),
source->pixel_size(), num_events_in_wait_list,
event_wait_list, errcode_ret)
{
+ if (*errcode_ret != CL_SUCCESS) return;
+
// Check bounds
if (source->type() == MemObject::Image2D &&
(src_origin[2] != 0 || region[2] != 1))
@@ -1191,3 +1210,93 @@ Event::Type CopyImageEvent::type() const
{
return Event::CopyImage;
}
+
+CopyImageToBufferEvent::CopyImageToBufferEvent(CommandQueue *parent,
+ Image2D *source,
+ MemObject *destination,
+ const size_t src_origin[3],
+ const size_t region[3],
+ size_t dst_offset,
+ cl_uint num_events_in_wait_list,
+ const Event **event_wait_list,
+ cl_int *errcode_ret)
+: CopyBufferRectEvent(parent, source, destination, src_origin, 0, region,
+ source->row_pitch(), source->slice_pitch(), 0, 0,
+ source->pixel_size(), num_events_in_wait_list,
+ event_wait_list, errcode_ret),
+ p_offset(dst_offset)
+{
+ if (*errcode_ret != CL_SUCCESS) return;
+
+ // Check for buffer overflow
+ size_t dst_cb = region[2] * region[1] * region[0] * source->pixel_size();
+
+ if (dst_offset + dst_cb > destination->size())
+ {
+ *errcode_ret = CL_INVALID_VALUE;
+ return;
+ }
+
+ // Check validity
+ if (source->type() == MemObject::Image2D &&
+ (src_origin[2] != 0 || region[2] != 1))
+ {
+ *errcode_ret = CL_INVALID_VALUE;
+ return;
+ }
+}
+
+size_t CopyImageToBufferEvent::offset() const
+{
+ return p_offset;
+}
+
+Event::Type CopyImageToBufferEvent::type() const
+{
+ return Event::CopyImageToBuffer;
+}
+
+CopyBufferToImageEvent::CopyBufferToImageEvent(CommandQueue *parent,
+ MemObject *source,
+ Image2D *destination,
+ size_t src_offset,
+ const size_t dst_origin[3],
+ const size_t region[3],
+ cl_uint num_events_in_wait_list,
+ const Event **event_wait_list,
+ cl_int *errcode_ret)
+: CopyBufferRectEvent(parent, source, destination, 0, dst_origin, region, 0, 0,
+ destination->row_pitch(), destination->slice_pitch(),
+ destination->pixel_size(), num_events_in_wait_list,
+ event_wait_list, errcode_ret),
+ p_offset(src_offset)
+{
+ if (*errcode_ret != CL_SUCCESS) return;
+
+ // Check for buffer overflow
+ size_t src_cb = region[2] * region[1] * region[0] * destination->pixel_size();
+
+ if (src_offset + src_cb > source->size())
+ {
+ *errcode_ret = CL_INVALID_VALUE;
+ return;
+ }
+
+ // Check validity
+ if (destination->type() == MemObject::Image2D &&
+ (dst_origin[2] != 0 || region[2] != 1))
+ {
+ *errcode_ret = CL_INVALID_VALUE;
+ return;
+ }
+}
+
+size_t CopyBufferToImageEvent::offset() const
+{
+ return p_offset;
+}
+
+Event::Type CopyBufferToImageEvent::type() const
+{
+ return Event::CopyBufferToImage;
+}
diff --git a/src/core/events.h b/src/core/events.h
index 4d8cd86..7ed08dd 100644
--- a/src/core/events.h
+++ b/src/core/events.h
@@ -179,7 +179,7 @@ class ReadWriteCopyBufferRectEvent : public BufferEvent
size_t dst_slice_pitch() const;
MemObject *source() const;
- private:
+ protected:
size_t p_src_origin[3], p_dst_origin[3], p_region[3];
size_t p_src_row_pitch, p_src_slice_pitch;
size_t p_dst_row_pitch, p_dst_slice_pitch;
@@ -339,6 +339,46 @@ class CopyImageEvent : public CopyBufferRectEvent
Type type() const;
};
+class CopyImageToBufferEvent : public CopyBufferRectEvent
+{
+ public:
+ CopyImageToBufferEvent(CommandQueue *parent,
+ Image2D *source,
+ MemObject *destination,
+ const size_t src_origin[3],
+ const size_t region[3],
+ size_t dst_offset,
+ cl_uint num_events_in_wait_list,
+ const Event **event_wait_list,
+ cl_int *errcode_ret);
+
+ size_t offset() const;
+ Type type() const;
+
+ private:
+ size_t p_offset;
+};
+
+class CopyBufferToImageEvent : public CopyBufferRectEvent
+{
+ public:
+ CopyBufferToImageEvent(CommandQueue *parent,
+ MemObject *source,
+ Image2D *destination,
+ size_t src_offset,
+ const size_t dst_origin[3],
+ const size_t region[3],
+ cl_uint num_events_in_wait_list,
+ const Event **event_wait_list,
+ cl_int *errcode_ret);
+
+ size_t offset() const;
+ Type type() const;
+
+ private:
+ size_t p_offset;
+};
+
class NativeKernelEvent : public Event
{
public:
diff --git a/src/core/memobject.cpp b/src/core/memobject.cpp
index 32fa49d..aabb974 100644
--- a/src/core/memobject.cpp
+++ b/src/core/memobject.cpp
@@ -578,6 +578,12 @@ size_t Image2D::row_pitch() const
return p_row_pitch;
}
+size_t Image2D::slice_pitch() const
+{
+ // An Image2D is made of only one slice
+ return size();
+}
+
const cl_image_format &Image2D::format() const
{
return p_format;
diff --git a/src/core/memobject.h b/src/core/memobject.h
index dce70b5..a0ac36b 100644
--- a/src/core/memobject.h
+++ b/src/core/memobject.h
@@ -107,6 +107,7 @@ class Image2D : public MemObject
size_t width() const;
size_t height() const;
size_t row_pitch() const;
+ virtual size_t slice_pitch() const;
const cl_image_format &format() const;
cl_int imageInfo(cl_image_info param_name,
diff --git a/tests/test_commandqueue.cpp b/tests/test_commandqueue.cpp
index 70dc161..2bb57f6 100644
--- a/tests/test_commandqueue.cpp
+++ b/tests/test_commandqueue.cpp
@@ -476,6 +476,7 @@ START_TEST (test_read_write_rect)
"the part of the buffer was not correctly read using a buffer"
);
+ clReleaseEvent(event);
clReleaseMemObject(buf_part);
clReleaseMemObject(buf);
clReleaseCommandQueue(queue);
@@ -665,6 +666,7 @@ START_TEST (test_read_write_image)
"copying images doesn't produce the correct result"
);
+ clReleaseEvent(event);
clReleaseMemObject(part2d);
clReleaseMemObject(image2d);
clReleaseCommandQueue(queue);
@@ -672,6 +674,119 @@ START_TEST (test_read_write_image)
}
END_TEST
+START_TEST (test_copy_image_buffer)
+{
+ cl_platform_id platform = 0;
+ cl_device_id device;
+ cl_context ctx;
+ cl_command_queue queue;
+ cl_mem image, buffer;
+ cl_int result;
+ cl_event event;
+
+ unsigned char image_buffer[3*3*4] = {
+ 255, 0, 0, 0, 0, 255, 0, 0, 0, 0, 255, 0,
+ 128, 0, 0, 0, 0, 128, 0, 0, 0, 0, 128, 0,
+ 64, 0, 0, 0, 0, 64, 0, 0, 0, 0, 64, 0
+ };
+
+ // Square that will be put in image_buffer at (1, 0)
+ unsigned char buffer_buffer[2*2*4+1] = {
+ 33, // Oh, a padding !
+ 255, 255, 255, 0, 255, 0, 255, 0,
+ 0, 255, 255, 0, 255, 255, 0, 0
+ };
+
+ // What we must get once re-reading 2x2 rect at (1, 1)
+ unsigned char correct_data[2*2*4] = {
+ 0, 255, 255, 0, 255, 255, 0, 0,
+ 0, 64, 0, 0, 0, 0, 64, 0
+ };
+
+ cl_image_format fmt;
+
+ fmt.image_channel_data_type = CL_UNORM_INT8;
+ fmt.image_channel_order = CL_RGBA;
+
+ size_t origin[3] = {1, 0, 0};
+ size_t region[3] = {2, 2, 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"
+ );
+
+ image = clCreateImage2D(ctx, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, &fmt,
+ 3, 3, 0, image_buffer, &result);
+ fail_if(
+ result != CL_SUCCESS,
+ "unable to create a 3x3 bgra image"
+ );
+
+ buffer = clCreateBuffer(ctx, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,
+ sizeof(buffer_buffer), buffer_buffer, &result);
+ fail_if(
+ result != CL_SUCCESS,
+ "unable to create a buffer object"
+ );
+
+ // Write buffer in image
+ result = clEnqueueCopyBufferToImage(queue, buffer, image, 1, origin, region,
+ 0, 0, &event);
+ fail_if(
+ result != CL_SUCCESS,
+ "unable to queue a copy buffer to image event, buffer offset 1, image 2x2 @ (1, 0)"
+ );
+
+ result = clWaitForEvents(1, &event);
+ fail_if(
+ result != CL_SUCCESS,
+ "cannot wait for event"
+ );
+
+ clReleaseEvent(event);
+
+ // Read it back into buffer, again with an offset
+ origin[1] = 1;
+ result = clEnqueueCopyImageToBuffer(queue, image, buffer, origin, region, 1,
+ 0, 0, &event);
+ fail_if(
+ result != CL_SUCCESS,
+ "unable to queue a copy image to buffer event, buffer offset 1, image 2x2 @ (1, 1)"
+ );
+
+ result = clWaitForEvents(1, &event);
+ fail_if(
+ result != CL_SUCCESS,
+ "cannot wait for event"
+ );
+
+ fail_if(
+ std::memcmp(buffer_buffer + 1, correct_data, sizeof(correct_data)) != 0,
+ "copying data around isn't working the expected way"
+ );
+
+ clReleaseEvent(event);
+ clReleaseMemObject(image);
+ clReleaseMemObject(buffer);
+ clReleaseCommandQueue(queue);
+ clReleaseContext(ctx);
+}
+END_TEST
+
TCase *cl_commandqueue_tcase_create(void)
{
TCase *tc = NULL;
@@ -683,5 +798,6 @@ TCase *cl_commandqueue_tcase_create(void)
tcase_add_test(tc, test_read_write_rect);
tcase_add_test(tc, test_copy_buffer);
tcase_add_test(tc, test_read_write_image);
+ tcase_add_test(tc, test_copy_image_buffer);
return tc;
}