| // |
| // Copyright (c) 2017 The Khronos Group Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| #include "harness/compat.h" |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <time.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| |
| #include "procs.h" |
| #include "harness/testHarness.h" |
| #include "harness/errorHelpers.h" |
| |
| static const char *read3d_kernel_code = |
| "\n" |
| "__kernel void read3d(read_only image3d_t srcimg, __global unsigned char *dst, sampler_t sampler)\n" |
| "{\n" |
| " int tid_x = get_global_id(0);\n" |
| " int tid_y = get_global_id(1);\n" |
| " int tid_z = get_global_id(2);\n" |
| " int indx = (tid_z * get_image_height(srcimg) + tid_y) * get_image_width(srcimg) + tid_x;\n" |
| " float4 color;\n" |
| "\n" |
| " color = read_imagef(srcimg, sampler, (int4)(tid_x, tid_y, tid_z, 0));\n" |
| " indx *= 4;\n" |
| " dst[indx+0] = (unsigned char)(color.x * 255.0f);\n" |
| " dst[indx+1] = (unsigned char)(color.y * 255.0f);\n" |
| " dst[indx+2] = (unsigned char)(color.z * 255.0f);\n" |
| " dst[indx+3] = (unsigned char)(color.w * 255.0f);\n" |
| "\n" |
| "}\n"; |
| |
| |
| static cl_uchar *createImage( int elements, MTdata d ) |
| { |
| int i; |
| cl_uchar *ptr = (cl_uchar *)malloc( elements * sizeof( cl_uchar ) ); |
| if( ! ptr ) |
| return NULL; |
| |
| for( i = 0; i < elements; i++ ){ |
| ptr[i] = (cl_uchar)genrand_int32(d); |
| } |
| |
| return ptr; |
| |
| } // end createImage() |
| |
| |
| static int verifyImages( cl_uchar *ptr0, cl_uchar *ptr1, cl_uchar tolerance, int xsize, int ysize, int zsize, int nChannels ) |
| { |
| int x, y, z, c; |
| cl_uchar *p0 = ptr0; |
| cl_uchar *p1 = ptr1; |
| |
| for( z = 0; z < zsize; z++ ){ |
| for( y = 0; y < ysize; y++ ){ |
| for( x = 0; x < xsize; x++ ){ |
| for( c = 0; c < nChannels; c++ ){ |
| if( (cl_uchar)abs( (int)( *p0++ - *p1++ ) ) > tolerance ){ |
| log_error( " images differ at x,y,z = %d,%d,%d channel = %d, %d to %d\n", |
| x, y, z, c, (int)p0[-1], (int)p1[-1] ); |
| return -1; |
| } |
| } |
| } |
| } |
| } |
| |
| return 0; |
| |
| } // end verifyImages() |
| |
| |
| static int run_kernel( cl_device_id device, cl_context context, cl_command_queue queue, |
| int w, int h, int d, int nChannels, cl_uchar *inptr, cl_uchar *outptr ) |
| { |
| cl_program program[1]; |
| cl_kernel kernel[1]; |
| cl_mem memobjs[2]; |
| cl_image_format image_format_desc = { CL_RGBA, CL_UNORM_INT8 }; |
| cl_event executeEvent = NULL; |
| cl_ulong queueStart, submitStart, writeStart, writeEnd; |
| size_t threads[3]; |
| size_t localThreads[3]; |
| int err = 0; |
| |
| // set thread dimensions |
| threads[0] = w; |
| threads[1] = h; |
| threads[2] = d; |
| |
| err = clGetDeviceInfo( device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof( cl_uint ), (size_t*)localThreads, NULL ); |
| if (err) |
| { |
| localThreads[0] = 256; localThreads[1] = 1; localThreads[2] = 1; |
| err = 0; |
| } |
| if( localThreads[0] > threads[0] ) |
| localThreads[0] = threads[0]; |
| if( localThreads[1] > threads[1] ) |
| localThreads[1] = threads[1]; |
| |
| cl_sampler sampler = clCreateSampler( context, CL_FALSE, CL_ADDRESS_CLAMP_TO_EDGE, CL_FILTER_NEAREST, &err ); |
| if( err ){ |
| log_error( " clCreateSampler failed.\n" ); |
| return -1; |
| } |
| |
| // allocate the input and output image memory objects |
| memobjs[0] = |
| create_image_3d(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, |
| &image_format_desc, w, h, d, 0, 0, inptr, &err); |
| if( memobjs[0] == (cl_mem)0 ){ |
| log_error( " unable to create 2D image using create_image_2d\n" ); |
| return -1; |
| } |
| |
| // allocate an array memory object to load the filter weights |
| memobjs[1] = |
| clCreateBuffer(context, CL_MEM_READ_WRITE, |
| sizeof(cl_float) * w * h * d * nChannels, NULL, &err); |
| if( memobjs[1] == (cl_mem)0 ){ |
| log_error( " unable to create array using clCreateBuffer\n" ); |
| clReleaseMemObject( memobjs[0] ); |
| return -1; |
| } |
| |
| // create the compute program |
| err = create_single_kernel_helper( context, &program[0], &kernel[0], 1, &read3d_kernel_code, "read3d" ); |
| if( err ){ |
| clReleaseMemObject( memobjs[1] ); |
| clReleaseMemObject( memobjs[0] ); |
| return -1; |
| } |
| |
| |
| // create kernel args object and set arg values. |
| // set the args values |
| err |= clSetKernelArg( kernel[0], 0, sizeof( cl_mem ), (void *)&memobjs[0] ); |
| err |= clSetKernelArg( kernel[0], 1, sizeof( cl_mem ), (void *)&memobjs[1] ); |
| err |= clSetKernelArg(kernel[0], 2, sizeof sampler, &sampler); |
| |
| if( err != CL_SUCCESS ){ |
| print_error( err, "clSetKernelArg failed\n" ); |
| clReleaseKernel( kernel[0] ); |
| clReleaseProgram( program[0] ); |
| clReleaseMemObject( memobjs[1] ); |
| clReleaseMemObject( memobjs[0] ); |
| return -1; |
| } |
| |
| err = clEnqueueNDRangeKernel( queue, kernel[0], 3, NULL, threads, localThreads, 0, NULL, &executeEvent ); |
| |
| if( err != CL_SUCCESS ){ |
| print_error( err, "clEnqueueNDRangeKernel failed\n" ); |
| clReleaseKernel( kernel[0] ); |
| clReleaseProgram( program[0] ); |
| clReleaseMemObject( memobjs[1] ); |
| clReleaseMemObject( memobjs[0] ); |
| return -1; |
| } |
| |
| if (executeEvent) { |
| |
| // This synchronization point is needed in order to assume the data is valid. |
| // Getting profiling information is not a synchronization point. |
| err = clWaitForEvents( 1, &executeEvent ); |
| if( err != CL_SUCCESS ) |
| { |
| print_error( err, "clWaitForEvents failed\n" ); |
| clReleaseKernel( kernel[0] ); |
| clReleaseProgram( program[0] ); |
| clReleaseMemObject( memobjs[1] ); |
| clReleaseMemObject( memobjs[0] ); |
| return -1; |
| } |
| |
| // test profiling |
| while( ( err = clGetEventProfilingInfo( executeEvent, CL_PROFILING_COMMAND_QUEUED, sizeof( cl_ulong ), &queueStart, NULL ) ) == CL_PROFILING_INFO_NOT_AVAILABLE ); |
| if( err != CL_SUCCESS ){ |
| print_error( err, "clGetEventProfilingInfo failed" ); |
| clReleaseKernel( kernel[0] ); |
| clReleaseProgram( program[0] ); |
| clReleaseMemObject( memobjs[1] ); |
| clReleaseMemObject( memobjs[0] ); |
| return -1; |
| } |
| |
| while( ( err = clGetEventProfilingInfo( executeEvent, CL_PROFILING_COMMAND_SUBMIT, sizeof( cl_ulong ), &submitStart, NULL ) ) == CL_PROFILING_INFO_NOT_AVAILABLE ); |
| if( err != CL_SUCCESS ){ |
| print_error( err, "clGetEventProfilingInfo failed" ); |
| clReleaseKernel( kernel[0] ); |
| clReleaseProgram( program[0] ); |
| clReleaseMemObject( memobjs[1] ); |
| clReleaseMemObject( memobjs[0] ); |
| return -1; |
| } |
| |
| err = clGetEventProfilingInfo( executeEvent, CL_PROFILING_COMMAND_START, sizeof( cl_ulong ), &writeStart, NULL ); |
| if( err != CL_SUCCESS ){ |
| print_error( err, "clGetEventProfilingInfo failed" ); |
| clReleaseKernel( kernel[0] ); |
| clReleaseProgram( program[0] ); |
| clReleaseMemObject( memobjs[1] ); |
| clReleaseMemObject( memobjs[0] ); |
| return -1; |
| } |
| |
| err = clGetEventProfilingInfo( executeEvent, CL_PROFILING_COMMAND_END, sizeof( cl_ulong ), &writeEnd, NULL ); |
| if( err != CL_SUCCESS ){ |
| print_error( err, "clGetEventProfilingInfo failed" ); |
| clReleaseKernel( kernel[0] ); |
| clReleaseProgram( program[0] ); |
| clReleaseMemObject( memobjs[1] ); |
| clReleaseMemObject( memobjs[0] ); |
| return -1; |
| } |
| |
| log_info( "Profiling info:\n" ); |
| log_info( "Time from queue to start of clEnqueueNDRangeKernel: %f seconds\n", (double)(writeStart - queueStart) / 1000000000000.f ); |
| log_info( "Time from start of clEnqueueNDRangeKernel to end: %f seconds\n", (double)(writeEnd - writeStart) / 1000000000000.f ); |
| } |
| |
| // read output image |
| err = clEnqueueReadBuffer(queue, memobjs[1], CL_TRUE, 0, w*h*d*nChannels*4, outptr, 0, NULL, NULL); |
| if( err != CL_SUCCESS ){ |
| print_error( err, "clReadImage failed\n" ); |
| clReleaseKernel( kernel[0] ); |
| clReleaseProgram( program[0] ); |
| clReleaseMemObject( memobjs[1] ); |
| clReleaseMemObject( memobjs[0] ); |
| return -1; |
| } |
| |
| // release kernel, program, and memory objects |
| clReleaseKernel( kernel[0] ); |
| clReleaseProgram( program[0] ); |
| clReleaseMemObject( memobjs[1] ); |
| clReleaseMemObject( memobjs[0] ); |
| |
| return err; |
| |
| } // end run_kernel() |
| |
| |
| // The main point of this test is to exercise code that causes a multipass cld launch for a single |
| // kernel exec at the cl level. This is done on the gpu for 3d launches, and it's also done |
| // to handle gdims that excede the maximums allowed by the hardware. In this case we |
| // use 3d to exercise the multipass events. In the future 3d may not be multpass, in which |
| // case we will need to ensure that we use gdims large enough to force multipass. |
| |
| int execute_multipass( cl_device_id device, cl_context context, cl_command_queue queue, int num_elements ) |
| { |
| cl_uchar *inptr; |
| cl_uchar *outptr; |
| int w = 256, h = 128, d = 32; |
| int nChannels = 4; |
| int nElements = w * h * d * nChannels; |
| int err = 0; |
| MTdata mtData; |
| |
| PASSIVE_REQUIRE_IMAGE_SUPPORT( device ) |
| |
| mtData = init_genrand( gRandomSeed ); |
| inptr = createImage( nElements, mtData ); |
| free_mtdata( mtData); mtData = NULL; |
| if( ! inptr ){ |
| log_error( " unable to allocate %d bytes of memory for image\n", nElements ); |
| return -1; |
| } |
| |
| outptr = (cl_uchar *)malloc( nElements * sizeof( cl_uchar ) ); |
| if( ! outptr ){ |
| log_error( " unable to allocate %d bytes of memory for output image #1\n", nElements ); |
| free( (void *)inptr ); |
| return -1; |
| } |
| |
| |
| err = run_kernel( device, context, queue, w, h, d, nChannels, inptr, outptr ); |
| |
| if( ! err ){ |
| // verify that the images are the same |
| err = verifyImages( outptr, inptr, (cl_uchar)0x1, w, h, d, nChannels ); |
| if( err ) |
| log_error( " images do not match\n" ); |
| } |
| |
| // clean up |
| free( (void *)outptr ); |
| free( (void *)inptr ); |
| |
| return err; |
| |
| } // end execute() |
| |
| |
| |