1 //
2 // Copyright (c) 2017 The Khronos Group Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 #include "../testBase.h"
17
18 extern void read_image_pixel_float( void *imageData, image_descriptor *imageInfo, int x, int y, int z, float *outData );
19
free_pitch_buffer(cl_mem image,void * buf)20 static void CL_CALLBACK free_pitch_buffer( cl_mem image, void *buf )
21 {
22 free( buf );
23 }
24
create_image(cl_context context,cl_command_queue queue,BufferOwningPtr<char> & data,image_descriptor * imageInfo,int * error)25 cl_mem create_image( cl_context context, cl_command_queue queue, BufferOwningPtr<char>& data, image_descriptor *imageInfo, int *error )
26 {
27 cl_mem img;
28 cl_image_desc imageDesc;
29 cl_mem_flags mem_flags = CL_MEM_READ_ONLY;
30 void *host_ptr = NULL;
31
32 memset(&imageDesc, 0x0, sizeof(cl_image_desc));
33 imageDesc.image_type = imageInfo->type;
34 imageDesc.image_width = imageInfo->width;
35 imageDesc.image_height = imageInfo->height;
36 imageDesc.image_depth = imageInfo->depth;
37 imageDesc.image_array_size = imageInfo->arraySize;
38 imageDesc.image_row_pitch = gEnablePitch ? imageInfo->rowPitch : 0;
39 imageDesc.image_slice_pitch = gEnablePitch ? imageInfo->slicePitch : 0;
40
41 switch (imageInfo->type)
42 {
43 case CL_MEM_OBJECT_IMAGE1D:
44 if ( gDebugTrace )
45 log_info( " - Creating 1D image %d ...\n", (int)imageInfo->width );
46 if ( gEnablePitch )
47 host_ptr = malloc( imageInfo->rowPitch );
48 break;
49 case CL_MEM_OBJECT_IMAGE2D:
50 if ( gDebugTrace )
51 log_info( " - Creating 2D image %d by %d ...\n", (int)imageInfo->width, (int)imageInfo->height );
52 if ( gEnablePitch )
53 host_ptr = malloc( imageInfo->height * imageInfo->rowPitch );
54 break;
55 case CL_MEM_OBJECT_IMAGE3D:
56 if ( gDebugTrace )
57 log_info( " - Creating 3D image %d by %d by %d...\n", (int)imageInfo->width, (int)imageInfo->height, (int)imageInfo->depth );
58 if ( gEnablePitch )
59 host_ptr = malloc( imageInfo->depth * imageInfo->slicePitch );
60 break;
61 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
62 if ( gDebugTrace )
63 log_info( " - Creating 1D image array %d by %d...\n", (int)imageInfo->width, (int)imageInfo->arraySize );
64 if ( gEnablePitch )
65 host_ptr = malloc( imageInfo->arraySize * imageInfo->slicePitch );
66 break;
67 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
68 if ( gDebugTrace )
69 log_info( " - Creating 2D image array %d by %d by %d...\n", (int)imageInfo->width, (int)imageInfo->height, (int)imageInfo->arraySize );
70 if ( gEnablePitch )
71 host_ptr = malloc( imageInfo->arraySize * imageInfo->slicePitch );
72 break;
73 }
74
75 if (gEnablePitch)
76 {
77 if ( NULL == host_ptr )
78 {
79 log_error( "ERROR: Unable to create backing store for pitched 3D image. %ld bytes\n", imageInfo->depth * imageInfo->slicePitch );
80 return NULL;
81 }
82 mem_flags = CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR;
83 }
84
85 img = clCreateImage(context, mem_flags, imageInfo->format, &imageDesc, host_ptr, error);
86
87 if (gEnablePitch)
88 {
89 if ( *error == CL_SUCCESS )
90 {
91 int callbackError = clSetMemObjectDestructorCallback( img, free_pitch_buffer, host_ptr );
92 if ( CL_SUCCESS != callbackError )
93 {
94 free( host_ptr );
95 log_error( "ERROR: Unable to attach destructor callback to pitched 3D image. Err: %d\n", callbackError );
96 clReleaseMemObject( img );
97 return NULL;
98 }
99 }
100 else
101 free(host_ptr);
102 }
103
104 if ( *error != CL_SUCCESS )
105 {
106 long long unsigned imageSize = get_image_size_mb( imageInfo );
107 switch (imageInfo->type)
108 {
109 case CL_MEM_OBJECT_IMAGE1D:
110 log_error( "ERROR: Unable to create 1D image of size %d (%llu MB): %s\n", (int)imageInfo->width, imageSize, IGetErrorString( *error ) );
111 break;
112 case CL_MEM_OBJECT_IMAGE2D:
113 log_error( "ERROR: Unable to create 2D image of size %d x %d (%llu MB): %s\n", (int)imageInfo->width, (int)imageInfo->height, imageSize, IGetErrorString( *error ) );
114 break;
115 case CL_MEM_OBJECT_IMAGE3D:
116 log_error( "ERROR: Unable to create 3D image of size %d x %d x %d (%llu MB): %s\n", (int)imageInfo->width, (int)imageInfo->height, (int)imageInfo->depth, imageSize, IGetErrorString( *error ) );
117 break;
118 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
119 log_error( "ERROR: Unable to create 1D image array of size %d x %d (%llu MB): %s\n", (int)imageInfo->width, (int)imageInfo->arraySize, imageSize, IGetErrorString( *error ) );
120 break;
121 break;
122 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
123 log_error( "ERROR: Unable to create 2D image array of size %d x %d x %d (%llu MB): %s\n", (int)imageInfo->width, (int)imageInfo->height, (int)imageInfo->arraySize, imageSize, IGetErrorString( *error ) );
124 break;
125 }
126 return NULL;
127 }
128
129 // Copy the specified data to the image via a Map operation.
130 size_t mappedRow, mappedSlice;
131 size_t height;
132 size_t depth;
133 size_t imageSize = 0;
134
135 switch (imageInfo->type)
136 {
137 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
138 height = imageInfo->arraySize;
139 depth = 1;
140 imageSize = imageInfo->rowPitch * imageInfo->arraySize;
141 break;
142 case CL_MEM_OBJECT_IMAGE1D:
143 height = depth = 1;
144 imageSize = imageInfo->rowPitch;
145 break;
146 case CL_MEM_OBJECT_IMAGE2D:
147 height = imageInfo->height;
148 depth = 1;
149 imageSize = imageInfo->rowPitch * imageInfo->height;
150 break;
151 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
152 height = imageInfo->height;
153 depth = imageInfo->arraySize;
154 imageSize = imageInfo->slicePitch * imageInfo->arraySize;
155 break;
156 case CL_MEM_OBJECT_IMAGE3D:
157 height = imageInfo->height;
158 depth = imageInfo->depth;
159 imageSize = imageInfo->slicePitch * imageInfo->depth;
160 break;
161 }
162
163 size_t origin[ 3 ] = { 0, 0, 0 };
164 size_t region[ 3 ] = { imageInfo->width, height, depth };
165
166 void* mapped = (char*)clEnqueueMapImage(queue, img, CL_TRUE, CL_MAP_WRITE, origin, region, &mappedRow, &mappedSlice, 0, NULL, NULL, error);
167 if (*error != CL_SUCCESS || !mapped)
168 {
169 log_error( "ERROR: Unable to map image for writing: %s\n", IGetErrorString( *error ) );
170 return NULL;
171 }
172 size_t mappedSlicePad = mappedSlice - (mappedRow * height);
173
174 // Copy the image.
175 size_t scanlineSize = imageInfo->rowPitch;
176 size_t sliceSize = imageInfo->slicePitch - scanlineSize * height;
177
178 char* src = (char*)data;
179 char* dst = (char*)mapped;
180
181 if ((mappedRow == scanlineSize) && ((mappedSlice == imageInfo->slicePitch) || (imageInfo->depth==0 && imageInfo->arraySize==0))) {
182 // Copy the whole image.
183 memcpy( dst, src, imageSize );
184 }
185 else {
186 // Else copy one scan line at a time.
187 size_t dstPitch2D = 0;
188 switch (imageInfo->type)
189 {
190 case CL_MEM_OBJECT_IMAGE3D:
191 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
192 case CL_MEM_OBJECT_IMAGE2D:
193 dstPitch2D = mappedRow;
194 break;
195 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
196 case CL_MEM_OBJECT_IMAGE1D:
197 dstPitch2D = mappedSlice;
198 break;
199 }
200
201 for ( size_t z = 0; z < depth; z++ )
202 {
203 for ( size_t y = 0; y < height; y++ )
204 {
205 memcpy( dst, src, imageInfo->width * get_pixel_size(imageInfo->format) );
206 dst += dstPitch2D;
207 src += scanlineSize;
208 }
209
210 // mappedSlicePad is incorrect for 2D images here, but we will exit the z loop before this is a problem.
211 dst += mappedSlicePad;
212 src += sliceSize;
213 }
214 }
215
216 // Unmap the image.
217 *error = clEnqueueUnmapMemObject(queue, img, mapped, 0, NULL, NULL);
218 if (*error != CL_SUCCESS)
219 {
220 log_error( "ERROR: Unable to unmap image after writing: %s\n", IGetErrorString( *error ) );
221 return NULL;
222 }
223
224 return img;
225 }
226
fill_region_with_value(image_descriptor * imageInfo,void * imageValues,void * value,const size_t origin[],const size_t region[])227 static void fill_region_with_value( image_descriptor *imageInfo, void *imageValues,
228 void *value, const size_t origin[], const size_t region[] )
229 {
230 size_t pixelSize = get_pixel_size( imageInfo->format );
231
232 // Get initial pointer
233 char *destPtr = (char *)imageValues + origin[ 2 ] * imageInfo->slicePitch
234 + origin[ 1 ] * imageInfo->rowPitch + pixelSize * origin[ 0 ];
235
236 char *fillColor = (char *)malloc(pixelSize);
237 memcpy(fillColor, value, pixelSize);
238
239 // Use pixel at origin to fill region.
240 for( size_t z = 0; z < ( region[ 2 ] > 0 ? region[ 2 ] : 1 ); z++ ) {
241 char *rowDestPtr = destPtr;
242 for( size_t y = 0; y < region[ 1 ]; y++ ) {
243 char *pixelDestPtr = rowDestPtr;
244
245 for( size_t x = 0; x < region[ 0 ]; x++ ) {
246 memcpy( pixelDestPtr, fillColor, pixelSize );
247 pixelDestPtr += pixelSize;
248 }
249 rowDestPtr += imageInfo->rowPitch;
250 }
251 destPtr += imageInfo->slicePitch;
252 }
253
254 free(fillColor);
255 }
256
test_fill_image_generic(cl_context context,cl_command_queue queue,image_descriptor * imageInfo,const size_t origin[],const size_t region[],ExplicitType outputType,MTdata d)257 int test_fill_image_generic( cl_context context, cl_command_queue queue, image_descriptor *imageInfo,
258 const size_t origin[], const size_t region[], ExplicitType outputType, MTdata d )
259 {
260 BufferOwningPtr<char> imgData;
261 BufferOwningPtr<char> imgHost;
262
263 int error;
264 clMemWrapper image;
265
266 if ( gDebugTrace )
267 log_info( " ++ Entering inner test loop...\n" );
268
269 // Generate some data to test against
270 size_t dataBytes = 0;
271
272 switch (imageInfo->type)
273 {
274 case CL_MEM_OBJECT_IMAGE1D:
275 dataBytes = imageInfo->rowPitch;
276 break;
277 case CL_MEM_OBJECT_IMAGE2D:
278 dataBytes = imageInfo->height * imageInfo->rowPitch;
279 break;
280 case CL_MEM_OBJECT_IMAGE3D:
281 dataBytes = imageInfo->depth * imageInfo->slicePitch;
282 break;
283 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
284 dataBytes = imageInfo->arraySize * imageInfo->slicePitch;
285 break;
286 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
287 dataBytes = imageInfo->arraySize * imageInfo->slicePitch;
288 break;
289 }
290
291 if (dataBytes > imgData.getSize())
292 {
293 if ( gDebugTrace )
294 log_info( " - Resizing random image data...\n" );
295
296 generate_random_image_data( imageInfo, imgData, d );
297
298 imgHost.reset( NULL ); // Free previously allocated memory first.
299 imgHost.reset(malloc(dataBytes),NULL,0,dataBytes);
300 if (imgHost == NULL)
301 {
302 log_error( "ERROR: Unable to malloc %lu bytes for imgHost\n", dataBytes );
303 return -1;
304 }
305 }
306
307 // Reset the host verification copy of the data.
308 memcpy(imgHost, imgData, dataBytes);
309
310 // Construct testing sources
311 if ( gDebugTrace )
312 log_info( " - Creating image...\n" );
313
314 image = create_image( context, queue, imgData, imageInfo, &error );
315 if ( image == NULL )
316 return error;
317
318 // Now fill the region defined by origin, region with the pixel value found at origin.
319 if ( gDebugTrace )
320 log_info( " - Filling at %d,%d,%d size %d,%d,%d\n", (int)origin[ 0 ], (int)origin[ 1 ], (int)origin[ 2 ],
321 (int)region[ 0 ], (int)region[ 1 ], (int)region[ 2 ] );
322
323 // We need to know the rounding mode, in the case of half to allow the
324 // pixel pack that generates the verification value to succeed.
325 if (imageInfo->format->image_channel_data_type == CL_HALF_FLOAT)
326 DetectFloatToHalfRoundingMode(queue);
327
328 if( outputType == kFloat )
329 {
330 cl_float fillColor[ 4 ];
331 read_image_pixel_float( imgHost, imageInfo, origin[ 0 ], origin[ 1 ], origin[ 2 ], fillColor );
332 if ( gDebugTrace )
333 log_info( " - with value %g, %g, %g, %g\n", fillColor[ 0 ], fillColor[ 1 ], fillColor[ 2 ], fillColor[ 3 ] );
334 error = clEnqueueFillImage ( queue, image, fillColor, origin, region, 0, NULL, NULL );
335 if ( error != CL_SUCCESS )
336 {
337 log_error( "ERROR: Unable to fill image at %d,%d,%d size %d,%d,%d! (%s)\n",
338 (int)origin[ 0 ], (int)origin[ 1 ], (int)origin[ 2 ],
339 (int)region[ 0 ], (int)region[ 1 ], (int)region[ 2 ], IGetErrorString( error ) );
340 return error;
341 }
342
343 // Write the approriate verification value to the correct region.
344 void* verificationValue = malloc(get_pixel_size(imageInfo->format));
345 pack_image_pixel(fillColor, imageInfo->format, verificationValue);
346 fill_region_with_value( imageInfo, imgHost, verificationValue, origin, region );
347 free(verificationValue);
348 }
349 else if( outputType == kInt )
350 {
351 cl_int fillColor[ 4 ];
352 read_image_pixel<cl_int>( imgHost, imageInfo, origin[ 0 ], origin[ 1 ], origin[ 2 ], fillColor );
353 if ( gDebugTrace )
354 log_info( " - with value %d, %d, %d, %d\n", fillColor[ 0 ], fillColor[ 1 ], fillColor[ 2 ], fillColor[ 3 ] );
355 error = clEnqueueFillImage ( queue, image, fillColor, origin, region, 0, NULL, NULL );
356 if ( error != CL_SUCCESS )
357 {
358 log_error( "ERROR: Unable to fill image at %d,%d,%d size %d,%d,%d! (%s)\n",
359 (int)origin[ 0 ], (int)origin[ 1 ], (int)origin[ 2 ],
360 (int)region[ 0 ], (int)region[ 1 ], (int)region[ 2 ], IGetErrorString( error ) );
361 return error;
362 }
363
364 // Write the approriate verification value to the correct region.
365 void* verificationValue = malloc(get_pixel_size(imageInfo->format));
366 pack_image_pixel(fillColor, imageInfo->format, verificationValue);
367 fill_region_with_value( imageInfo, imgHost, verificationValue, origin, region );
368 free(verificationValue);
369 }
370 else // if( outputType == kUInt )
371 {
372 cl_uint fillColor[ 4 ];
373 read_image_pixel<cl_uint>( imgHost, imageInfo, origin[ 0 ], origin[ 1 ], origin[ 2 ], fillColor );
374 if ( gDebugTrace )
375 log_info( " - with value %u, %u, %u, %u\n", fillColor[ 0 ], fillColor[ 1 ], fillColor[ 2 ], fillColor[ 3 ] );
376 error = clEnqueueFillImage ( queue, image, fillColor, origin, region, 0, NULL, NULL );
377 if ( error != CL_SUCCESS )
378 {
379 log_error( "ERROR: Unable to fill image at %d,%d,%d size %d,%d,%d! (%s)\n",
380 (int)origin[ 0 ], (int)origin[ 1 ], (int)origin[ 2 ],
381 (int)region[ 0 ], (int)region[ 1 ], (int)region[ 2 ], IGetErrorString( error ) );
382 return error;
383 }
384
385 // Write the approriate verification value to the correct region.
386 void* verificationValue = malloc(get_pixel_size(imageInfo->format));
387 pack_image_pixel(fillColor, imageInfo->format, verificationValue);
388 fill_region_with_value( imageInfo, imgHost, verificationValue, origin, region );
389 free(verificationValue);
390 }
391
392 // Map the destination image to verify the results with the host
393 // copy. The contents of the entire buffer are compared.
394 if ( gDebugTrace )
395 log_info( " - Mapping results...\n" );
396
397 size_t imageOrigin[ 3 ] = { 0, 0, 0 };
398 size_t imageRegion[ 3 ] = { imageInfo->width, 1, 1 };
399 switch (imageInfo->type)
400 {
401 case CL_MEM_OBJECT_IMAGE1D:
402 break;
403 case CL_MEM_OBJECT_IMAGE2D:
404 imageRegion[ 1 ] = imageInfo->height;
405 break;
406 case CL_MEM_OBJECT_IMAGE3D:
407 imageRegion[ 1 ] = imageInfo->height;
408 imageRegion[ 2 ] = imageInfo->depth;
409 break;
410 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
411 imageRegion[ 1 ] = imageInfo->arraySize;
412 break;
413 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
414 imageRegion[ 1 ] = imageInfo->height;
415 imageRegion[ 2 ] = imageInfo->arraySize;
416 break;
417 }
418
419 size_t mappedRow, mappedSlice;
420 void* mapped = (char*)clEnqueueMapImage(queue, image, CL_TRUE, CL_MAP_READ, imageOrigin, imageRegion, &mappedRow, &mappedSlice, 0, NULL, NULL, &error);
421 if (error != CL_SUCCESS)
422 {
423 log_error( "ERROR: Unable to map image for verification: %s\n", IGetErrorString( error ) );
424 return -1;
425 }
426
427 // Verify scanline by scanline, since the pitches are different
428 char *sourcePtr = imgHost;
429 char *destPtr = (char*)mapped;
430
431 size_t scanlineSize = imageInfo->width * get_pixel_size( imageInfo->format );
432
433 if ( gDebugTrace )
434 log_info( " - Scanline verification...\n" );
435
436 size_t thirdDim = 1;
437 size_t secondDim = 1;
438
439 switch (imageInfo->type) {
440 case CL_MEM_OBJECT_IMAGE1D:
441 secondDim = 1;
442 thirdDim = 1;
443 break;
444 case CL_MEM_OBJECT_IMAGE2D:
445 secondDim = imageInfo->height;
446 thirdDim = 1;
447 break;
448 case CL_MEM_OBJECT_IMAGE3D:
449 secondDim = imageInfo->height;
450 thirdDim = imageInfo->depth;
451 break;
452 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
453 secondDim = imageInfo->arraySize;
454 thirdDim = 1;
455 break;
456 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
457 secondDim = imageInfo->height;
458 thirdDim = imageInfo->arraySize;
459 break;
460 default:
461 log_error("Test error: unhandled image type at %s:%d\n",__FILE__,__LINE__);
462 };
463
464 // Count the number of bytes successfully matched
465 size_t total_matched = 0;
466
467 for ( size_t z = 0; z < thirdDim; z++ )
468 {
469 for ( size_t y = 0; y < secondDim; y++ )
470 {
471 // If the data type is 101010 ignore bits 31 and 32 when comparing the row
472 if (imageInfo->format->image_channel_data_type == CL_UNORM_INT_101010) {
473 for (size_t w=0;w!=scanlineSize/4;++w) {
474 ((cl_uint*)sourcePtr)[w] &= 0x3FFFFFFF;
475 ((cl_uint*)destPtr)[w] &= 0x3FFFFFFF;
476 }
477 }
478
479 if (memcmp( sourcePtr, destPtr, scanlineSize ) != 0)
480 {
481 // Find the first missing pixel
482 size_t pixel_size = get_pixel_size( imageInfo->format );
483 size_t where = 0;
484 for ( where = 0; where < imageInfo->width; where++ )
485 if ( memcmp( sourcePtr + pixel_size * where, destPtr + pixel_size * where, pixel_size) )
486 break;
487
488 print_first_pixel_difference_error(
489 where, sourcePtr + pixel_size * where,
490 destPtr + pixel_size * where, imageInfo, y, thirdDim);
491 return -1;
492 }
493
494 total_matched += scanlineSize;
495 sourcePtr += imageInfo->rowPitch;
496 if((imageInfo->type == CL_MEM_OBJECT_IMAGE1D_ARRAY || imageInfo->type == CL_MEM_OBJECT_IMAGE1D))
497 destPtr += mappedSlice;
498 else
499 destPtr += mappedRow;
500 }
501
502 sourcePtr += imageInfo->slicePitch - ( imageInfo->rowPitch * (imageInfo->height > 0 ? imageInfo->height : 1) );
503 destPtr += mappedSlice - ( mappedRow * (imageInfo->height > 0 ? imageInfo->height : 1) );
504 }
505
506 // Unmap the image.
507 error = clEnqueueUnmapMemObject(queue, image, mapped, 0, NULL, NULL);
508 if (error != CL_SUCCESS)
509 {
510 log_error( "ERROR: Unable to unmap image after verify: %s\n", IGetErrorString( error ) );
511 return -1;
512 }
513
514 imgHost.reset(0x0);
515 imgData.reset(0x0);
516
517 size_t expected_bytes = scanlineSize * imageRegion[1] * imageRegion[2];
518 return (total_matched == expected_bytes) ? 0 : -1;
519 }
520