diff options
Diffstat (limited to 'tests/test_commandqueue.cpp')
-rw-r--r-- | tests/test_commandqueue.cpp | 1027 |
1 files changed, 1027 insertions, 0 deletions
diff --git a/tests/test_commandqueue.cpp b/tests/test_commandqueue.cpp new file mode 100644 index 0000000..0119ec5 --- /dev/null +++ b/tests/test_commandqueue.cpp @@ -0,0 +1,1027 @@ +/* + * Copyright (c) 2011, Denis Steckelmacher <steckdenis@yahoo.fr> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <cstring> +#include <cstdlib> +#include <iostream> + +#include "test_commandqueue.h" +#include "CL/cl.h" + +#include <unistd.h> + +START_TEST (test_create_command_queue) +{ + cl_device_id device; + cl_context ctx; + cl_command_queue queue; + cl_int result; + + cl_platform_id platform = 0; + cl_uint num_platforms = 0; + clGetPlatformIDs(1, &platform, &num_platforms); + + 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(0, device, 0, &result); + fail_if( + result != CL_INVALID_CONTEXT, + "context must be valid" + ); + + queue = clCreateCommandQueue(ctx, 0, 0, &result); + fail_if( + result != CL_INVALID_DEVICE, + "device cannot be NULL" + ); + + queue = clCreateCommandQueue(ctx, device, 1337, &result); + fail_if( + result != CL_INVALID_VALUE, + "1337 is not a valid value for properties" + ); + + queue = clCreateCommandQueue(ctx, device, 0, &result); + fail_if( + result != CL_SUCCESS || queue == 0, + "cannot create a command queue" + ); + + clReleaseCommandQueue(queue); + clReleaseContext(ctx); +} +END_TEST + +START_TEST (test_get_command_queue_info) +{ + cl_device_id device; + cl_context ctx; + cl_command_queue queue; + cl_int result; + + cl_platform_id platform = 0; + cl_uint num_platforms = 0; + clGetPlatformIDs(1, &platform, &num_platforms); + + union { + cl_context ctx; + cl_device_id device; + cl_uint refcount; + cl_command_queue_properties properties; + } info; + + 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" + ); + + result = clGetCommandQueueInfo(queue, CL_QUEUE_CONTEXT, sizeof(cl_context), + (void *)&info, 0); + fail_if( + result != CL_SUCCESS || info.ctx != ctx, + "the queue doesn't retain its context" + ); + + result = clGetCommandQueueInfo(queue, CL_QUEUE_DEVICE, sizeof(cl_device_id), + (void *)&info, 0); + fail_if( + result != CL_SUCCESS || info.device != device, + "the queue doesn't retain its device" + ); + + result = clGetCommandQueueInfo(queue, CL_QUEUE_REFERENCE_COUNT, sizeof(cl_uint), + (void *)&info, 0); + fail_if( + result != CL_SUCCESS || info.refcount != 1, + "the queue must have a refcount of 1 when it's created" + ); + + result = clGetCommandQueueInfo(queue, CL_QUEUE_PROPERTIES, sizeof(cl_command_queue_properties), + (void *)&info, 0); + fail_if( + result != CL_SUCCESS || info.properties != 0, + "we gave no properties to the command queue" + ); + + clReleaseCommandQueue(queue); + clReleaseContext(ctx); +} +END_TEST + +START_TEST (test_object_tree) +{ + cl_device_id device; + cl_context ctx; + cl_command_queue queue; + cl_int result; + cl_uint refcount; + + cl_platform_id platform = 0; + cl_uint num_platforms = 0; + clGetPlatformIDs(1, &platform, &num_platforms); + + 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" + ); + + result = clGetContextInfo(ctx, CL_CONTEXT_REFERENCE_COUNT, sizeof(cl_uint), + (void *)&refcount, 0); + fail_if( + result != CL_SUCCESS || refcount != 2, + "the queue must increment the refcount of its context" + ); + + clReleaseCommandQueue(queue); + + result = clGetContextInfo(ctx, CL_CONTEXT_REFERENCE_COUNT, sizeof(cl_uint), + (void *)&refcount, 0); + fail_if( + result != CL_SUCCESS || refcount != 1, + "the queue must decrement the refcount of its context when it's destroyed" + ); + + clReleaseContext(ctx); +} +END_TEST + +static void event_notify(cl_event event, cl_int exec_status, void *user_data) +{ + unsigned char *good = (unsigned char *)user_data; + + *good = 1; +} + +START_TEST (test_events) +{ + cl_device_id device; + cl_context ctx; + cl_command_queue queue; + cl_int result; + cl_event user_event, write_event; + cl_mem buf; + + cl_platform_id platform = 0; + cl_uint num_platforms = 0; + clGetPlatformIDs(1, &platform, &num_platforms); + + char s[] = "Original content"; + unsigned char good = 0; + + 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, CL_QUEUE_PROFILING_ENABLE, &result); + fail_if( + result != CL_SUCCESS || queue == 0, + "cannot create a command queue" + ); + + user_event = clCreateUserEvent(0, &result); + fail_if( + result != CL_INVALID_CONTEXT, + "0 is not a valid context" + ); + + user_event = clCreateUserEvent(ctx, &result); + fail_if( + result != CL_SUCCESS || user_event == 0, + "cannot create an user event" + ); + + buf = clCreateBuffer(ctx, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, + sizeof(s), s, &result); + fail_if( + result != CL_SUCCESS, + "cannot create a valid CL_MEM_USE_HOST_PTR read-write buffer" + ); + + // Queue a write buffer + result = clEnqueueWriteBuffer(queue, buf, 0, 0, 8, "Modified", 1, + &user_event, &write_event); + fail_if( + result != CL_SUCCESS, + "cannot enqueue an asynchronous write buffer command" + ); + + result = clSetEventCallback(write_event, CL_SUBMITTED, &event_notify, &good); + fail_if( + result != CL_INVALID_VALUE, + "callback_type must be CL_COMPLETE in OpenCL 1.1" + ); + + result = clSetEventCallback(write_event, CL_COMPLETE, &event_notify, &good); + fail_if( + result != CL_COMPLETE, + "cannot register an event callback" + ); + + sleep(1); // Let the worker threads a chance to do faulty things + + fail_if( + good != 0 || strncmp(s, "Original content", sizeof(s)), + "at this time, nothing can have happened, the user event isn't complete" + ); + + // Now we can execute everything + result = clSetUserEventStatus(write_event, CL_COMPLETE); + fail_if( + result != CL_INVALID_EVENT, + "write_event is not an user event" + ); + + result = clSetUserEventStatus(user_event, CL_SUBMITTED); + fail_if( + result != CL_INVALID_VALUE, + "the execution status must be CL_COMPLETE" + ); + + result = clSetUserEventStatus(user_event, CL_COMPLETE); + fail_if( + result != CL_SUCCESS, + "cannot set the user event as completed" + ); + + // And wait (TODO: More careful checks of this function) + result = clWaitForEvents(1, &write_event); + fail_if( + result != CL_SUCCESS, + "cannot wait for events" + ); + + // Checks that all went good + fail_if( + good != 1, + "the callback function must be called when an event is completed" + ); + fail_if( + strncmp(s, "Modified content", sizeof(s)), + "the buffer must contain \"Modified content\"" + ); + + result = clSetUserEventStatus(user_event, CL_COMPLETE); + fail_if( + result != CL_INVALID_OPERATION, + "we cannot call clSetUserEventStatus two times for an event" + ); + + // Queue a map buffer + char *data; + + data = (char *) clEnqueueMapBuffer(queue, buf, 1, CL_MAP_READ, 0, sizeof(s), + 0, 0, 0, &result); + fail_if( + result != CL_SUCCESS || !data || strncmp(data, s, sizeof(s)), + "unable to map a buffer containing what the buffer contains" + ); + + result = clEnqueueUnmapMemObject(queue, buf, data, 0, 0, 0); + fail_if( + result != CL_SUCCESS, + "unable to unmap a mapped buffer" + ); + + // Get timing information about the event + cl_ulong timing_queued, timing_submit, timing_start, timing_end; + + result = clGetEventProfilingInfo(write_event, CL_PROFILING_COMMAND_QUEUED, + sizeof(cl_ulong), &timing_queued, 0); + result |= clGetEventProfilingInfo(write_event, CL_PROFILING_COMMAND_SUBMIT, + sizeof(cl_ulong), &timing_submit, 0); + result |= clGetEventProfilingInfo(write_event, CL_PROFILING_COMMAND_START, + sizeof(cl_ulong), &timing_start, 0); + result |= clGetEventProfilingInfo(write_event, CL_PROFILING_COMMAND_END, + sizeof(cl_ulong), &timing_end, 0); + fail_if( + result != CL_SUCCESS, + "unable to get timing information about a profiling-enabled event" + ); + fail_if( + !(timing_queued <= timing_submit && + timing_submit <= timing_start && + timing_start <= timing_end), + "something went wrong with the timings : they are unordered" + ); + + clReleaseEvent(write_event); + clReleaseEvent(user_event); + clReleaseMemObject(buf); + clReleaseCommandQueue(queue); + clReleaseContext(ctx); +} +END_TEST + +START_TEST (test_read_write_rect) +{ + cl_device_id device; + cl_context ctx; + cl_command_queue queue; + cl_int result; + cl_mem buf, buf_part; + + cl_platform_id platform = 0; + cl_uint num_platforms = 0; + clGetPlatformIDs(1, &platform, &num_platforms); + + // 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" + ); + + buf_part = clCreateBuffer(ctx, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, + sizeof(buffer_part), buffer_part, &result); + fail_if( + result != CL_SUCCESS, + "cannot create a buffer for the part that will be read" + ); + + // Write grid into buffer + result = clEnqueueWriteBufferRect(queue, buf, 1, buf_origin, host_origin, + region, 0, 0, 0, 0, grid, 0, 0, 0); + 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" + ); + + // Clear the temporary region and re-read into it using buf_part + std::memset(buffer_part, 0, sizeof(buffer_part)); + cl_event event; + + result = clEnqueueCopyBufferRect(queue, buf, buf_part, buf_origin, + host_origin, region, 5, 5*7, 0, 0, 0, 0, &event); + fail_if( + result != CL_SUCCESS, + "unable to queue a copy buffer rect event" + ); + + result = clWaitForEvents(1, &event); + fail_if( + result != CL_SUCCESS, + "unable to wait for the event" + ); + + fail_if( + std::memcmp(buffer_part, part, sizeof(part)) != 0, + "the part of the buffer was not correctly read using a buffer" + ); + + clReleaseEvent(event); + clReleaseMemObject(buf_part); + clReleaseMemObject(buf); + clReleaseCommandQueue(queue); + clReleaseContext(ctx); +} +END_TEST + +START_TEST (test_copy_buffer) +{ + cl_device_id device; + cl_context ctx; + cl_command_queue queue; + cl_int result; + cl_mem src_buf, dst_buf; + cl_event event; + + cl_platform_id platform = 0; + cl_uint num_platforms = 0; + clGetPlatformIDs(1, &platform, &num_platforms); + + char src[] = "This is the data."; + char dst[] = "Overwrite this..."; + + 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" + ); + + src_buf = clCreateBuffer(ctx, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, + sizeof(src), src, &result); + fail_if( + result != CL_SUCCESS, + "cannot create the source buffer" + ); + + dst_buf = clCreateBuffer(ctx, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, + sizeof(dst), dst, &result); + fail_if( + result != CL_SUCCESS, + "cannot create the destination buffer" + ); + + result = clEnqueueCopyBuffer(queue, src_buf, dst_buf, 0, 0, sizeof(src), + 0, 0, &event); + fail_if( + result != CL_SUCCESS, + "unable to queue a copy buffer event" + ); + + result = clWaitForEvents(1, &event); + fail_if( + result != CL_SUCCESS, + "unable to wait for the event" + ); + + fail_if( + std::memcmp(src, dst, sizeof(src)) != 0, + "the buffer wasn't copied" + ); + + clReleaseEvent(event); + clReleaseMemObject(src_buf); + clReleaseMemObject(dst_buf); + clReleaseCommandQueue(queue); + clReleaseContext(ctx); +} +END_TEST + +START_TEST (test_read_write_image) +{ + cl_device_id device; + cl_context ctx; + cl_command_queue queue; + cl_mem image2d, part2d; + cl_int result; + + cl_platform_id platform = 0; + cl_uint num_platforms = 0; + clGetPlatformIDs(1, &platform, &num_platforms); + + 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" + ); + + part2d = clCreateImage2D(ctx, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, &fmt, + 2, 2, 0, image2d_part, &result); + fail_if( + result != CL_SUCCESS || image2d == 0, + "cannot create a valid 2x2 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 + #if 0 // images not supported + fail_if( + std::memcmp(image2d_part, image2d_part_24bpp, sizeof(image2d_part)) != 0, + "reading and writing images doesn't produce the correct result" + ); +#endif + + // Read it back using a buffer + cl_event event; + std::memset(image2d_part, 0, sizeof(image2d_part)); + + result = clEnqueueCopyImage(queue, image2d, part2d, origin, origin, + region, 0, 0, &event); + fail_if( + result != CL_SUCCESS, + "unable to enqueue a copy image event" + ); + + result = clWaitForEvents(1, &event); + fail_if( + result != CL_SUCCESS, + "unable to wait for events" + ); + + // Compare +#if 0 // images not supported + fail_if( + std::memcmp(image2d_part, image2d_part_24bpp, sizeof(image2d_part)) != 0, + "copying images doesn't produce the correct result" + ); +#endif + + clReleaseEvent(event); + clReleaseMemObject(part2d); + clReleaseMemObject(image2d); + clReleaseCommandQueue(queue); + clReleaseContext(ctx); +} +END_TEST + +START_TEST (test_copy_image_buffer) +{ + cl_device_id device; + cl_context ctx; + cl_command_queue queue; + cl_mem image, buffer; + cl_int result; + cl_event event; + + cl_platform_id platform = 0; + cl_uint num_platforms = 0; + clGetPlatformIDs(1, &platform, &num_platforms); + + 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" + ); + +#if 0 // images not supported + fail_if( + std::memcmp(buffer_buffer + 1, correct_data, sizeof(correct_data)) != 0, + "copying data around isn't working the expected way" + ); +#endif + + + // Map the image and check pointers + unsigned char *mapped; + size_t row_pitch; + + origin[0] = 0; + origin[1] = 0; + origin[2] = 0; + + mapped = (unsigned char *)clEnqueueMapImage(queue, image, 1, CL_MAP_READ, + origin, region, &row_pitch, 0, 0, + 0, 0, &result); + fail_if( + result != CL_SUCCESS, + "unable to map an image" + ); +#if 0 // images not supported + fail_if( + mapped != image_buffer, + "mapped aread doesn't match host ptr" + ); +#endif + + clReleaseEvent(event); + clReleaseMemObject(image); + clReleaseMemObject(buffer); + clReleaseCommandQueue(queue); + clReleaseContext(ctx); +} +END_TEST + +START_TEST (test_misc_events) +{ + cl_platform_id platform = 0; + cl_uint num_platforms = 0; + clGetPlatformIDs(1, &platform, &num_platforms); + + cl_device_id device; + cl_context ctx; + cl_command_queue queue; + cl_int result; + cl_event uevent1, uevent2, marker1, marker2; + + 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" + ); + + /* + * This test will build a command queue blocked by an user event. The events + * will be in this order : + * + * -: UserEvent1 + * 0: WaitForEvents1 (wait=UserEvent1) + * 1: Marker1 + * -: UserEvent2 + * 2: WaitForEvents2 (wait=UserEvent2) + * 3: Barrier + * 4: Marker2 (to check the barrier worked) + * + * When the command queue is built, we : + * - Check that Marker1 is Queued (WaitForEvents waits) + * - Set UserEvent1 to Complete + * - Check that Marker1 is Complete (WaitForEvents stopped to wait) + * - Check that Marker2 is Queued (Barrier is there) + * - Set UserEvent2 to Complete + * - Check that Marker2 is Complete (no more barrier) + */ + uevent1 = clCreateUserEvent(ctx, &result); + fail_if( + result != CL_SUCCESS, + "unable to create UserEvent1" + ); + + uevent2 = clCreateUserEvent(ctx, &result); + fail_if( + result != CL_SUCCESS, + "unable to create UserEvent2" + ); + + result = clEnqueueWaitForEvents(queue, 1, &uevent1); + fail_if( + result != CL_SUCCESS, + "unable to enqueue WaitForEvents(UserEvent1)" + ); + + result = clEnqueueMarker(queue, &marker1); + fail_if( + result != CL_SUCCESS, + "unable to enqueue Marker1" + ); + + result = clEnqueueWaitForEvents(queue, 1, &uevent2); + fail_if( + result != CL_SUCCESS, + "unable to enqueue WaitForEvents(UserEvent2)" + ); + + result = clEnqueueBarrier(queue); + fail_if( + result != CL_SUCCESS, + "unable to enqueue Barrier" + ); + + result = clEnqueueMarker(queue, &marker2); + fail_if( + result != CL_SUCCESS, + "unable to enqueue Marker2" + ); + + // Now the checks + cl_int status; + + result = clGetEventInfo(marker1, CL_EVENT_COMMAND_EXECUTION_STATUS, + sizeof(cl_int), &status, 0); + fail_if( + result != CL_SUCCESS || status != CL_QUEUED, + "Marker1 must be Queued" + ); + + result = clSetUserEventStatus(uevent1, CL_COMPLETE); + fail_if( + result != CL_SUCCESS, + "unable to set UserEvent1 to Complete" + ); + + result = clGetEventInfo(marker1, CL_EVENT_COMMAND_EXECUTION_STATUS, + sizeof(cl_int), &status, 0); + fail_if( + result != CL_SUCCESS || status != CL_COMPLETE, + "Marker1 must be Complete" + ); + + result = clGetEventInfo(marker2, CL_EVENT_COMMAND_EXECUTION_STATUS, + sizeof(cl_int), &status, 0); + fail_if( + result != CL_SUCCESS || status != CL_QUEUED, + "Marker2 must be Queued" + ); + + result = clSetUserEventStatus(uevent2, CL_COMPLETE); + fail_if( + result != CL_SUCCESS, + "unable to set UserEvent2 to Complete" + ); + + result = clGetEventInfo(marker2, CL_EVENT_COMMAND_EXECUTION_STATUS, + sizeof(cl_int), &status, 0); + fail_if( + result != CL_SUCCESS || status != CL_COMPLETE, + "Marker2 must be Complete" + ); + + clFinish(queue); + + clReleaseEvent(uevent1); + clReleaseEvent(uevent2); + clReleaseEvent(marker1); + clReleaseEvent(marker2); + clReleaseCommandQueue(queue); + clReleaseContext(ctx); +} +END_TEST + +TCase *cl_commandqueue_tcase_create(void) +{ + TCase *tc = NULL; + tc = tcase_create("commandqueue"); + tcase_add_test(tc, test_create_command_queue); + 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); + tcase_add_test(tc, test_copy_buffer); +#if 0 // Images not supported + tcase_add_test(tc, test_read_write_image); + tcase_add_test(tc, test_copy_image_buffer); +#endif + tcase_add_test(tc, test_misc_events); + return tc; +} |