xref: /aosp_15_r20/external/OpenCL-CTS/test_conformance/images/clCopyImage/test_copy_generic.cpp (revision 6467f958c7de8070b317fc65bcb0f6472e388d82)
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 
free_pitch_buffer(cl_mem image,void * buf)18 static void CL_CALLBACK free_pitch_buffer( cl_mem image, void *buf )
19 {
20     free( buf );
21 }
22 
create_image(cl_context context,cl_command_queue queue,BufferOwningPtr<char> & data,image_descriptor * imageInfo,int * error)23 cl_mem create_image( cl_context context, cl_command_queue queue, BufferOwningPtr<char>& data, image_descriptor *imageInfo, int *error )
24 {
25     cl_mem img;
26     cl_image_desc imageDesc;
27     cl_mem_flags mem_flags = CL_MEM_READ_ONLY;
28     void *host_ptr = NULL;
29 
30     memset(&imageDesc, 0x0, sizeof(cl_image_desc));
31     imageDesc.image_type = imageInfo->type;
32     imageDesc.image_width = imageInfo->width;
33     imageDesc.image_height = imageInfo->height;
34     imageDesc.image_depth = imageInfo->depth;
35     imageDesc.image_array_size = imageInfo->arraySize;
36     imageDesc.image_row_pitch = gEnablePitch ? imageInfo->rowPitch : 0;
37     imageDesc.image_slice_pitch = gEnablePitch ? imageInfo->slicePitch : 0;
38     imageDesc.num_mip_levels = gTestMipmaps ? imageInfo->num_mip_levels : 0;
39 
40     switch (imageInfo->type)
41     {
42         case CL_MEM_OBJECT_IMAGE1D:
43             if ( gDebugTrace )
44                 log_info( " - Creating 1D image %d ...\n", (int)imageInfo->width );
45             if ( gEnablePitch )
46                 host_ptr = malloc( imageInfo->rowPitch );
47             break;
48         case CL_MEM_OBJECT_IMAGE2D:
49             if ( gDebugTrace )
50                 log_info( " - Creating 2D image %d by %d ...\n", (int)imageInfo->width, (int)imageInfo->height );
51             if ( gEnablePitch )
52                 host_ptr = malloc( imageInfo->height * imageInfo->rowPitch );
53             break;
54         case CL_MEM_OBJECT_IMAGE3D:
55             if ( gDebugTrace )
56                 log_info( " - Creating 3D image %d by %d by %d...\n", (int)imageInfo->width, (int)imageInfo->height, (int)imageInfo->depth );
57             if ( gEnablePitch )
58                 host_ptr = malloc( imageInfo->depth * imageInfo->slicePitch );
59             break;
60         case CL_MEM_OBJECT_IMAGE1D_ARRAY:
61             if ( gDebugTrace )
62                 log_info( " - Creating 1D image array %d by %d...\n", (int)imageInfo->width, (int)imageInfo->arraySize );
63             if ( gEnablePitch )
64                 host_ptr = malloc( imageInfo->arraySize * imageInfo->slicePitch );
65             break;
66         case CL_MEM_OBJECT_IMAGE2D_ARRAY:
67             if ( gDebugTrace )
68                 log_info( " - Creating 2D image array %d by %d by %d...\n", (int)imageInfo->width, (int)imageInfo->height, (int)imageInfo->arraySize );
69             if ( gEnablePitch )
70                 host_ptr = malloc( imageInfo->arraySize * imageInfo->slicePitch );
71             break;
72     }
73 
74     if ( gDebugTrace && gTestMipmaps )
75         log_info(" - with %llu mip levels\n", (unsigned long long) imageInfo->num_mip_levels);
76 
77     if (gEnablePitch)
78     {
79         if ( NULL == host_ptr )
80         {
81             log_error( "ERROR: Unable to create backing store for pitched 3D image. %ld bytes\n",  imageInfo->depth * imageInfo->slicePitch );
82             return NULL;
83         }
84         mem_flags = CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR;
85     }
86 
87     img = clCreateImage(context, mem_flags, imageInfo->format, &imageDesc, host_ptr, error);
88 
89     if (gEnablePitch)
90     {
91         if ( *error == CL_SUCCESS )
92         {
93             int callbackError = clSetMemObjectDestructorCallback( img, free_pitch_buffer, host_ptr );
94             if ( CL_SUCCESS != callbackError )
95             {
96                 free( host_ptr );
97                 log_error( "ERROR: Unable to attach destructor callback to pitched 3D image. Err: %d\n", callbackError );
98                 clReleaseMemObject( img );
99                 return NULL;
100             }
101         }
102         else
103             free(host_ptr);
104     }
105 
106     if ( *error != CL_SUCCESS )
107     {
108         long long unsigned imageSize = get_image_size_mb(imageInfo);
109         switch (imageInfo->type)
110         {
111             case CL_MEM_OBJECT_IMAGE1D:
112                 log_error("ERROR: Unable to create 1D image of size %d (%llu "
113                           "MB):(%s)",
114                           (int)imageInfo->width, imageSize,
115                           IGetErrorString(*error));
116                 break;
117             case CL_MEM_OBJECT_IMAGE2D:
118                 log_error("ERROR: Unable to create 2D image of size %d x %d "
119                           "(%llu MB):(%s)",
120                           (int)imageInfo->width, (int)imageInfo->height,
121                           imageSize, IGetErrorString(*error));
122                 break;
123             case CL_MEM_OBJECT_IMAGE3D:
124                 log_error("ERROR: Unable to create 3D image of size %d x %d x "
125                           "%d (%llu MB):(%s)",
126                           (int)imageInfo->width, (int)imageInfo->height,
127                           (int)imageInfo->depth, imageSize,
128                           IGetErrorString(*error));
129                 break;
130             case CL_MEM_OBJECT_IMAGE1D_ARRAY:
131                 log_error("ERROR: Unable to create 1D image array of size %d x "
132                           "%d (%llu MB):(%s)",
133                           (int)imageInfo->width, (int)imageInfo->arraySize,
134                           imageSize, IGetErrorString(*error));
135                 break;
136                 break;
137             case CL_MEM_OBJECT_IMAGE2D_ARRAY:
138                 log_error("ERROR: Unable to create 2D image array of size %d x "
139                           "%d x %d (%llu MB):(%s)",
140                           (int)imageInfo->width, (int)imageInfo->height,
141                           (int)imageInfo->arraySize, imageSize,
142                           IGetErrorString(*error));
143                 break;
144         }
145         log_error("ERROR: and %llu mip levels\n", (unsigned long long) imageInfo->num_mip_levels);
146         return NULL;
147     }
148 
149     // Copy the specified data to the image via a Map operation.
150     size_t mappedRow, mappedSlice;
151     size_t width = imageInfo->width;
152     size_t height = 1;
153     size_t depth = 1;
154     size_t row_pitch_lod, slice_pitch_lod;
155     row_pitch_lod = imageInfo->rowPitch;
156     slice_pitch_lod = imageInfo->slicePitch;
157 
158     switch (imageInfo->type)
159     {
160         case CL_MEM_OBJECT_IMAGE1D_ARRAY:
161             height = imageInfo->arraySize;
162             depth = 1;
163             break;
164         case CL_MEM_OBJECT_IMAGE1D:
165             height = depth = 1;
166             break;
167         case CL_MEM_OBJECT_IMAGE2D:
168             height = imageInfo->height;
169             depth = 1;
170             break;
171         case CL_MEM_OBJECT_IMAGE2D_ARRAY:
172             height = imageInfo->height;
173             depth = imageInfo->arraySize;
174             break;
175         case CL_MEM_OBJECT_IMAGE3D:
176             height = imageInfo->height;
177             depth = imageInfo->depth;
178             break;
179     }
180 
181     size_t origin[ 4 ] = { 0, 0, 0, 0 };
182     size_t region[ 3 ] = { imageInfo->width, height, depth };
183 
184     for ( size_t lod = 0; (gTestMipmaps && (lod < imageInfo->num_mip_levels)) || (!gTestMipmaps && (lod < 1)); lod++)
185     {
186         // Map the appropriate miplevel to copy the specified data.
187         if(gTestMipmaps)
188         {
189             switch (imageInfo->type)
190             {
191                 case CL_MEM_OBJECT_IMAGE3D:
192                 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
193                     origin[ 3 ] = lod;
194                     break;
195                 case CL_MEM_OBJECT_IMAGE2D:
196                 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
197                     origin[ 2 ] =  lod;
198                     break;
199                 case CL_MEM_OBJECT_IMAGE1D:
200                     origin[ 1 ] = lod;
201                     break;
202             }
203 
204             //Adjust image dimensions as per miplevel
205             switch (imageInfo->type)
206             {
207                 case CL_MEM_OBJECT_IMAGE3D:
208                     depth = ( imageInfo->depth >> lod ) ? (imageInfo->depth >> lod) : 1;
209                 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
210                 case CL_MEM_OBJECT_IMAGE2D:
211                     height = ( imageInfo->height >> lod ) ? (imageInfo->height >> lod) : 1;
212                 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
213                 case CL_MEM_OBJECT_IMAGE1D:
214                     width = ( imageInfo->width >> lod ) ? (imageInfo->width >> lod) : 1;
215             }
216             row_pitch_lod = width * get_pixel_size(imageInfo->format);
217             slice_pitch_lod = row_pitch_lod * height;
218             region[0] = width;
219             region[1] = height;
220             region[2] = depth;
221         }
222 
223         void* mapped = (char*)clEnqueueMapImage(queue, img, CL_TRUE, CL_MAP_WRITE, origin, region, &mappedRow, &mappedSlice, 0, NULL, NULL, error);
224         if (*error != CL_SUCCESS)
225         {
226             log_error( "ERROR: Unable to map image for writing: %s\n", IGetErrorString( *error ) );
227             return NULL;
228         }
229         size_t mappedSlicePad = mappedSlice - (mappedRow * height);
230 
231         // For 1Darray, the height variable actually contains the arraysize,
232         // so it can't be used for calculating the slice padding.
233         if (imageInfo->type == CL_MEM_OBJECT_IMAGE1D_ARRAY)
234             mappedSlicePad = mappedSlice - (mappedRow * 1);
235 
236         // Copy the image.
237         size_t scanlineSize = row_pitch_lod;
238         size_t sliceSize = slice_pitch_lod - scanlineSize * height;
239         size_t imageSize = scanlineSize * height * depth;
240         size_t data_lod_offset = 0;
241         if( gTestMipmaps )
242             data_lod_offset = compute_mip_level_offset(imageInfo, lod);
243 
244         char* src = (char*)data + data_lod_offset;
245         char* dst = (char*)mapped;
246 
247         if ((mappedRow == scanlineSize) && (mappedSlicePad==0 || (imageInfo->depth==0 && imageInfo->arraySize==0))) {
248             // Copy the whole image.
249             memcpy( dst, src, imageSize );
250         }
251         else {
252             // Else copy one scan line at a time.
253             size_t dstPitch2D = 0;
254             switch (imageInfo->type)
255             {
256                 case CL_MEM_OBJECT_IMAGE3D:
257                 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
258                 case CL_MEM_OBJECT_IMAGE2D:
259                     dstPitch2D = mappedRow;
260                     break;
261                 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
262                 case CL_MEM_OBJECT_IMAGE1D:
263                     dstPitch2D = mappedSlice;
264                     break;
265             }
266             for ( size_t z = 0; z < depth; z++ )
267             {
268                 for ( size_t y = 0; y < height; y++ )
269                 {
270                     memcpy( dst, src, scanlineSize );
271                     dst += dstPitch2D;
272                     src += scanlineSize;
273                 }
274 
275                 // mappedSlicePad is incorrect for 2D images here, but we will exit the z loop before this is a problem.
276                 dst += mappedSlicePad;
277                 src += sliceSize;
278             }
279         }
280 
281         // Unmap the image.
282         *error = clEnqueueUnmapMemObject(queue, img, mapped, 0, NULL, NULL);
283         if (*error != CL_SUCCESS)
284         {
285             log_error( "ERROR: Unable to unmap image after writing: %s\n", IGetErrorString( *error ) );
286             return NULL;
287         }
288     }
289     return img;
290 }
291 
test_copy_image_generic(cl_context context,cl_command_queue queue,image_descriptor * srcImageInfo,image_descriptor * dstImageInfo,const size_t sourcePos[],const size_t destPos[],const size_t regionSize[],MTdata d)292 int test_copy_image_generic( cl_context context, cl_command_queue queue, image_descriptor *srcImageInfo, image_descriptor *dstImageInfo,
293                             const size_t sourcePos[], const size_t destPos[], const size_t regionSize[], MTdata d )
294 {
295     int error;
296 
297     clMemWrapper srcImage, dstImage;
298 
299     BufferOwningPtr<char> srcData;
300     BufferOwningPtr<char> dstData;
301     BufferOwningPtr<char> srcHost;
302     BufferOwningPtr<char> dstHost;
303 
304     if( gDebugTrace )
305         log_info( " ++ Entering inner test loop...\n" );
306 
307     // Generate some data to test against
308     size_t srcBytes = 0;
309     if( gTestMipmaps )
310     {
311         srcBytes = (size_t)compute_mipmapped_image_size( *srcImageInfo );
312     }
313     else
314     {
315         srcBytes = get_image_size(srcImageInfo);
316     }
317 
318     if (srcBytes > srcData.getSize())
319     {
320         if( gDebugTrace )
321             log_info( " - Resizing random image data...\n" );
322 
323         generate_random_image_data( srcImageInfo, srcData, d  );
324 
325         // Update the host verification copy of the data.
326         srcHost.reset(malloc(srcBytes),NULL,0,srcBytes);
327         if (srcHost == NULL) {
328             log_error( "ERROR: Unable to malloc %lu bytes for srcHost\n", srcBytes );
329             return -1;
330         }
331         memcpy(srcHost,srcData,srcBytes);
332     }
333 
334     // Construct testing sources
335     if( gDebugTrace )
336         log_info( " - Writing source image...\n" );
337 
338     srcImage = create_image( context, queue, srcData, srcImageInfo, &error );
339     if( srcImage == NULL )
340         return error;
341 
342 
343     // Initialize the destination to empty
344     size_t destImageSize = 0;
345     if( gTestMipmaps )
346     {
347         destImageSize = (size_t)compute_mipmapped_image_size( *dstImageInfo );
348     }
349     else
350     {
351         destImageSize = get_image_size(dstImageInfo);
352     }
353 
354     if (destImageSize > dstData.getSize())
355     {
356         if( gDebugTrace )
357             log_info( " - Resizing destination buffer...\n" );
358         dstData.reset(malloc(destImageSize),NULL,0,destImageSize);
359         if (dstData == NULL) {
360             log_error( "ERROR: Unable to malloc %lu bytes for dstData\n", destImageSize );
361             return -1;
362         }
363     }
364 
365     if (destImageSize > dstHost.getSize())
366     {
367         dstHost.reset(NULL);
368         dstHost.reset(malloc(destImageSize),NULL,0,destImageSize);
369         if (dstHost == NULL) {
370             dstData.reset(NULL);
371             log_error( "ERROR: Unable to malloc %lu bytes for dstHost\n", destImageSize );
372             return -1;
373         }
374     }
375     memset( dstData, 0xff, destImageSize );
376     memset( dstHost, 0xff, destImageSize );
377 
378     if( gDebugTrace )
379         log_info( " - Writing destination image...\n" );
380 
381     dstImage = create_image( context, queue, dstData, dstImageInfo, &error );
382     if( dstImage == NULL )
383         return error;
384 
385     size_t dstRegion[ 3 ] = { dstImageInfo->width, 1, 1};
386     size_t dst_lod = 0;
387     size_t origin[ 4 ] = { 0, 0, 0, 0 };
388 
389     if(gTestMipmaps)
390     {
391         switch(dstImageInfo->type)
392         {
393             case CL_MEM_OBJECT_IMAGE1D:
394                 dst_lod = destPos[1];
395                 break;
396             case CL_MEM_OBJECT_IMAGE1D_ARRAY:
397             case CL_MEM_OBJECT_IMAGE2D:
398                 dst_lod = destPos[2];
399                 break;
400             case CL_MEM_OBJECT_IMAGE2D_ARRAY:
401             case CL_MEM_OBJECT_IMAGE3D:
402                 dst_lod = destPos[3];
403                 break;
404         }
405 
406         dstRegion[ 0 ] = (dstImageInfo->width >> dst_lod)?(dstImageInfo->width >> dst_lod) : 1;
407     }
408     switch (dstImageInfo->type)
409     {
410         case CL_MEM_OBJECT_IMAGE1D:
411             if( gTestMipmaps )
412                 origin[ 1 ] = dst_lod;
413             break;
414         case CL_MEM_OBJECT_IMAGE2D:
415             dstRegion[ 1 ] = dstImageInfo->height;
416             if( gTestMipmaps )
417             {
418                 dstRegion[ 1 ] = (dstImageInfo->height >> dst_lod) ?(dstImageInfo->height >> dst_lod): 1;
419                 origin[ 2 ] = dst_lod;
420             }
421             break;
422         case CL_MEM_OBJECT_IMAGE3D:
423             dstRegion[ 1 ] = dstImageInfo->height;
424             dstRegion[ 2 ] = dstImageInfo->depth;
425             if( gTestMipmaps )
426             {
427                 dstRegion[ 1 ] = (dstImageInfo->height >> dst_lod) ?(dstImageInfo->height >> dst_lod): 1;
428                 dstRegion[ 2 ] = (dstImageInfo->depth >> dst_lod) ?(dstImageInfo->depth >> dst_lod): 1;
429                 origin[ 3 ] = dst_lod;
430             }
431             break;
432         case CL_MEM_OBJECT_IMAGE1D_ARRAY:
433             dstRegion[ 1 ] = dstImageInfo->arraySize;
434             if( gTestMipmaps )
435                 origin[ 2 ] = dst_lod;
436             break;
437         case CL_MEM_OBJECT_IMAGE2D_ARRAY:
438             dstRegion[ 1 ] = dstImageInfo->height;
439             dstRegion[ 2 ] = dstImageInfo->arraySize;
440             if( gTestMipmaps )
441             {
442                 dstRegion[ 1 ] = (dstImageInfo->height >> dst_lod) ?(dstImageInfo->height >> dst_lod): 1;
443                 origin[ 3 ] = dst_lod;
444             }
445             break;
446     }
447 
448     size_t region[ 3 ] = { dstRegion[ 0 ], dstRegion[ 1 ], dstRegion[ 2 ] };
449 
450     // Now copy a subset to the destination image. This is the meat of what we're testing
451     if( gDebugTrace )
452     {
453         if( gTestMipmaps )
454         {
455             log_info( " - Copying from %d,%d,%d,%d to %d,%d,%d,%d size %d,%d,%d\n", (int)sourcePos[ 0 ], (int)sourcePos[ 1 ], (int)sourcePos[ 2 ],(int)sourcePos[ 3 ],
456                      (int)destPos[ 0 ], (int)destPos[ 1 ], (int)destPos[ 2 ],(int)destPos[ 3 ],
457                      (int)regionSize[ 0 ], (int)regionSize[ 1 ], (int)regionSize[ 2 ] );
458         }
459         else
460         {
461             log_info( " - Copying from %d,%d,%d to %d,%d,%d size %d,%d,%d\n", (int)sourcePos[ 0 ], (int)sourcePos[ 1 ], (int)sourcePos[ 2 ],
462                      (int)destPos[ 0 ], (int)destPos[ 1 ], (int)destPos[ 2 ],
463                      (int)regionSize[ 0 ], (int)regionSize[ 1 ], (int)regionSize[ 2 ] );
464         }
465     }
466 
467     error = clEnqueueCopyImage( queue, srcImage, dstImage, sourcePos, destPos, regionSize, 0, NULL, NULL );
468     if( error != CL_SUCCESS )
469     {
470         log_error( "ERROR: Unable to copy image from pos %d,%d,%d to %d,%d,%d size %d,%d,%d! (%s)\n",
471                   (int)sourcePos[ 0 ], (int)sourcePos[ 1 ], (int)sourcePos[ 2 ], (int)destPos[ 0 ], (int)destPos[ 1 ], (int)destPos[ 2 ],
472                   (int)regionSize[ 0 ], (int)regionSize[ 1 ], (int)regionSize[ 2 ], IGetErrorString( error ) );
473         return error;
474     }
475 
476     // Construct the final dest image values to test against
477     if( gDebugTrace )
478         log_info( " - Host verification copy...\n" );
479 
480     copy_image_data( srcImageInfo, dstImageInfo, srcHost, dstHost, sourcePos, destPos, regionSize );
481 
482     // Map the destination image to verify the results with the host
483     // copy. The contents of the entire buffer are compared.
484     if( gDebugTrace )
485         log_info( " - Mapping results...\n" );
486 
487     size_t mappedRow, mappedSlice;
488     void* mapped = (char*)clEnqueueMapImage(queue, dstImage, CL_TRUE, CL_MAP_READ, origin, region, &mappedRow, &mappedSlice, 0, NULL, NULL, &error);
489     if (error != CL_SUCCESS)
490     {
491         log_error( "ERROR: Unable to map image for verification: %s\n", IGetErrorString( error ) );
492         return error;
493     }
494 
495     // Verify scanline by scanline, since the pitches are different
496     char *sourcePtr = dstHost;
497     size_t cur_lod_offset = 0;
498     char *destPtr = (char*)mapped;
499 
500     if( gTestMipmaps )
501     {
502         cur_lod_offset = compute_mip_level_offset(dstImageInfo, dst_lod);
503         sourcePtr += cur_lod_offset;
504     }
505 
506     size_t scanlineSize = dstImageInfo->width * get_pixel_size( dstImageInfo->format );
507     size_t rowPitch = dstImageInfo->rowPitch;
508     size_t slicePitch = dstImageInfo->slicePitch;
509     size_t dst_height_lod = dstImageInfo->height;
510     if(gTestMipmaps)
511     {
512         size_t dst_width_lod = (dstImageInfo->width >> dst_lod)?(dstImageInfo->width >> dst_lod) : 1;
513         dst_height_lod = (dstImageInfo->height >> dst_lod)?(dstImageInfo->height >> dst_lod) : 1;
514         scanlineSize = dst_width_lod * get_pixel_size(dstImageInfo->format);
515         rowPitch = scanlineSize;
516         slicePitch = rowPitch * dst_height_lod;
517     }
518 
519     if( gDebugTrace )
520         log_info( " - Scanline verification...\n" );
521 
522     size_t thirdDim = 1;
523     size_t secondDim = 1;
524 
525     switch (dstImageInfo->type)
526     {
527         case CL_MEM_OBJECT_IMAGE1D_ARRAY: {
528             secondDim = dstImageInfo->arraySize;
529             break;
530         }
531         case CL_MEM_OBJECT_IMAGE2D_ARRAY: {
532             secondDim = dstImageInfo->height;
533             thirdDim = dstImageInfo->arraySize;
534             break;
535         }
536         case CL_MEM_OBJECT_IMAGE3D: {
537             secondDim = dstImageInfo->height;
538             thirdDim = dstImageInfo->depth;
539             break;
540         }
541         case CL_MEM_OBJECT_IMAGE2D: {
542             secondDim = dstImageInfo->height;
543             break;
544         }
545         case CL_MEM_OBJECT_IMAGE1D: {
546             break;
547         }
548         default: {
549             log_error("ERROR: Unsupported Image type. \n");
550             return error;
551             break;
552         }
553     }
554     if (gTestMipmaps)
555     {
556         switch (dstImageInfo->type)
557         {
558             case CL_MEM_OBJECT_IMAGE3D:
559                 thirdDim = (dstImageInfo->depth >> dst_lod) ? (dstImageInfo->depth >> dst_lod):1;
560                 /* Fallthrough */
561             case CL_MEM_OBJECT_IMAGE2D:
562             case CL_MEM_OBJECT_IMAGE2D_ARRAY:
563                 secondDim = (dstImageInfo->height >> dst_lod)
564                     ? (dstImageInfo->height >> dst_lod)
565                     : 1;
566                 break;
567         }
568     }
569     for( size_t z = 0; z < thirdDim; z++ )
570     {
571         for( size_t y = 0; y < secondDim; y++ )
572         {
573             if( memcmp( sourcePtr, destPtr, scanlineSize ) != 0 )
574             {
575                 // Find the first differing pixel
576                 size_t pixel_size = get_pixel_size( dstImageInfo->format );
577                 size_t where =
578                     compare_scanlines(dstImageInfo, sourcePtr, destPtr);
579 
580                 if (where < dstImageInfo->width)
581                 {
582                     print_first_pixel_difference_error(
583                         where, sourcePtr + pixel_size * where,
584                         destPtr + pixel_size * where, dstImageInfo, y,
585                         dstImageInfo->depth);
586                     return -1;
587                 }
588             }
589             sourcePtr += rowPitch;
590             if((dstImageInfo->type == CL_MEM_OBJECT_IMAGE1D_ARRAY || dstImageInfo->type == CL_MEM_OBJECT_IMAGE1D))
591             destPtr += mappedSlice;
592             else
593             destPtr += mappedRow;
594         }
595         sourcePtr += slicePitch - rowPitch * dst_height_lod;
596         destPtr += mappedSlice - mappedRow * dst_height_lod;
597     }
598 
599     // Unmap the image.
600     error = clEnqueueUnmapMemObject(queue, dstImage, mapped, 0, NULL, NULL);
601     if (error != CL_SUCCESS)
602     {
603         log_error( "ERROR: Unable to unmap image after verify: %s\n", IGetErrorString( error ) );
604         return error;
605     }
606 
607     // Ensure the unmap call completes.
608     error = clFinish(queue);
609     if (error != CL_SUCCESS)
610     {
611         log_error("ERROR: clFinish() failed to return CL_SUCCESS: %s\n",
612                   IGetErrorString(error));
613         return error;
614     }
615 
616     return 0;
617 }
618