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         // Copy the image.
232         size_t scanlineSize = row_pitch_lod;
233         size_t sliceSize = slice_pitch_lod - scanlineSize * height;
234         size_t imageSize = scanlineSize * height * depth;
235         size_t data_lod_offset = 0;
236         if( gTestMipmaps )
237             data_lod_offset = compute_mip_level_offset(imageInfo, lod);
238 
239         char* src = (char*)data + data_lod_offset;
240         char* dst = (char*)mapped;
241 
242         if ((mappedRow == scanlineSize) && (mappedSlicePad==0 || (imageInfo->depth==0 && imageInfo->arraySize==0))) {
243             // Copy the whole image.
244             memcpy( dst, src, imageSize );
245         }
246         else {
247             // Else copy one scan line at a time.
248             size_t dstPitch2D = 0;
249             switch (imageInfo->type)
250             {
251                 case CL_MEM_OBJECT_IMAGE3D:
252                 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
253                 case CL_MEM_OBJECT_IMAGE2D:
254                     dstPitch2D = mappedRow;
255                     break;
256                 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
257                 case CL_MEM_OBJECT_IMAGE1D:
258                     dstPitch2D = mappedSlice;
259                     break;
260             }
261             for ( size_t z = 0; z < depth; z++ )
262             {
263                 for ( size_t y = 0; y < height; y++ )
264                 {
265                     memcpy( dst, src, scanlineSize );
266                     dst += dstPitch2D;
267                     src += scanlineSize;
268                 }
269 
270                 // mappedSlicePad is incorrect for 2D images here, but we will exit the z loop before this is a problem.
271                 dst += mappedSlicePad;
272                 src += sliceSize;
273             }
274         }
275 
276         // Unmap the image.
277         *error = clEnqueueUnmapMemObject(queue, img, mapped, 0, NULL, NULL);
278         if (*error != CL_SUCCESS)
279         {
280             log_error( "ERROR: Unable to unmap image after writing: %s\n", IGetErrorString( *error ) );
281             return NULL;
282         }
283     }
284     return img;
285 }
286 
287 // WARNING -- not thread safe
288 BufferOwningPtr<char> srcData;
289 BufferOwningPtr<char> dstData;
290 BufferOwningPtr<char> srcHost;
291 BufferOwningPtr<char> dstHost;
292 
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)293 int test_copy_image_generic( cl_context context, cl_command_queue queue, image_descriptor *srcImageInfo, image_descriptor *dstImageInfo,
294                             const size_t sourcePos[], const size_t destPos[], const size_t regionSize[], MTdata d )
295 {
296     int error;
297 
298     clMemWrapper srcImage, dstImage;
299 
300     if( gDebugTrace )
301         log_info( " ++ Entering inner test loop...\n" );
302 
303     // Generate some data to test against
304     size_t srcBytes = 0;
305     if( gTestMipmaps )
306     {
307         srcBytes = (size_t)compute_mipmapped_image_size( *srcImageInfo );
308     }
309     else
310     {
311         srcBytes = get_image_size(srcImageInfo);
312     }
313 
314     if (srcBytes > srcData.getSize())
315     {
316         if( gDebugTrace )
317             log_info( " - Resizing random image data...\n" );
318 
319         generate_random_image_data( srcImageInfo, srcData, d  );
320 
321         // Update the host verification copy of the data.
322         srcHost.reset(malloc(srcBytes),NULL,0,srcBytes);
323         if (srcHost == NULL) {
324             log_error( "ERROR: Unable to malloc %lu bytes for srcHost\n", srcBytes );
325             return -1;
326         }
327         memcpy(srcHost,srcData,srcBytes);
328     }
329 
330     // Construct testing sources
331     if( gDebugTrace )
332         log_info( " - Writing source image...\n" );
333 
334     srcImage = create_image( context, queue, srcData, srcImageInfo, &error );
335     if( srcImage == NULL )
336         return error;
337 
338 
339     // Initialize the destination to empty
340     size_t destImageSize = 0;
341     if( gTestMipmaps )
342     {
343         destImageSize = (size_t)compute_mipmapped_image_size( *dstImageInfo );
344     }
345     else
346     {
347         destImageSize = get_image_size(dstImageInfo);
348     }
349 
350     if (destImageSize > dstData.getSize())
351     {
352         if( gDebugTrace )
353             log_info( " - Resizing destination buffer...\n" );
354         dstData.reset(malloc(destImageSize),NULL,0,destImageSize);
355         if (dstData == NULL) {
356             log_error( "ERROR: Unable to malloc %lu bytes for dstData\n", destImageSize );
357             return -1;
358         }
359     }
360 
361     if (destImageSize > dstHost.getSize())
362     {
363         dstHost.reset(NULL);
364         dstHost.reset(malloc(destImageSize),NULL,0,destImageSize);
365         if (dstHost == NULL) {
366             dstData.reset(NULL);
367             log_error( "ERROR: Unable to malloc %lu bytes for dstHost\n", destImageSize );
368             return -1;
369         }
370     }
371     memset( dstData, 0xff, destImageSize );
372     memset( dstHost, 0xff, destImageSize );
373 
374     if( gDebugTrace )
375         log_info( " - Writing destination image...\n" );
376 
377     dstImage = create_image( context, queue, dstData, dstImageInfo, &error );
378     if( dstImage == NULL )
379         return error;
380 
381     size_t dstRegion[ 3 ] = { dstImageInfo->width, 1, 1};
382     size_t dst_lod = 0;
383     size_t origin[ 4 ] = { 0, 0, 0, 0 };
384 
385     if(gTestMipmaps)
386     {
387         switch(dstImageInfo->type)
388         {
389             case CL_MEM_OBJECT_IMAGE1D:
390                 dst_lod = destPos[1];
391                 break;
392             case CL_MEM_OBJECT_IMAGE1D_ARRAY:
393             case CL_MEM_OBJECT_IMAGE2D:
394                 dst_lod = destPos[2];
395                 break;
396             case CL_MEM_OBJECT_IMAGE2D_ARRAY:
397             case CL_MEM_OBJECT_IMAGE3D:
398                 dst_lod = destPos[3];
399                 break;
400         }
401 
402         dstRegion[ 0 ] = (dstImageInfo->width >> dst_lod)?(dstImageInfo->width >> dst_lod) : 1;
403     }
404     switch (dstImageInfo->type)
405     {
406         case CL_MEM_OBJECT_IMAGE1D:
407             if( gTestMipmaps )
408                 origin[ 1 ] = dst_lod;
409             break;
410         case CL_MEM_OBJECT_IMAGE2D:
411             dstRegion[ 1 ] = dstImageInfo->height;
412             if( gTestMipmaps )
413             {
414                 dstRegion[ 1 ] = (dstImageInfo->height >> dst_lod) ?(dstImageInfo->height >> dst_lod): 1;
415                 origin[ 2 ] = dst_lod;
416             }
417             break;
418         case CL_MEM_OBJECT_IMAGE3D:
419             dstRegion[ 1 ] = dstImageInfo->height;
420             dstRegion[ 2 ] = dstImageInfo->depth;
421             if( gTestMipmaps )
422             {
423                 dstRegion[ 1 ] = (dstImageInfo->height >> dst_lod) ?(dstImageInfo->height >> dst_lod): 1;
424                 dstRegion[ 2 ] = (dstImageInfo->depth >> dst_lod) ?(dstImageInfo->depth >> dst_lod): 1;
425                 origin[ 3 ] = dst_lod;
426             }
427             break;
428         case CL_MEM_OBJECT_IMAGE1D_ARRAY:
429             dstRegion[ 1 ] = dstImageInfo->arraySize;
430             if( gTestMipmaps )
431                 origin[ 2 ] = dst_lod;
432             break;
433         case CL_MEM_OBJECT_IMAGE2D_ARRAY:
434             dstRegion[ 1 ] = dstImageInfo->height;
435             dstRegion[ 2 ] = dstImageInfo->arraySize;
436             if( gTestMipmaps )
437             {
438                 dstRegion[ 1 ] = (dstImageInfo->height >> dst_lod) ?(dstImageInfo->height >> dst_lod): 1;
439                 origin[ 3 ] = dst_lod;
440             }
441             break;
442     }
443 
444     size_t region[ 3 ] = { dstRegion[ 0 ], dstRegion[ 1 ], dstRegion[ 2 ] };
445 
446     // Now copy a subset to the destination image. This is the meat of what we're testing
447     if( gDebugTrace )
448     {
449         if( gTestMipmaps )
450         {
451             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 ],
452                      (int)destPos[ 0 ], (int)destPos[ 1 ], (int)destPos[ 2 ],(int)destPos[ 3 ],
453                      (int)regionSize[ 0 ], (int)regionSize[ 1 ], (int)regionSize[ 2 ] );
454         }
455         else
456         {
457             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 ],
458                      (int)destPos[ 0 ], (int)destPos[ 1 ], (int)destPos[ 2 ],
459                      (int)regionSize[ 0 ], (int)regionSize[ 1 ], (int)regionSize[ 2 ] );
460         }
461     }
462 
463     error = clEnqueueCopyImage( queue, srcImage, dstImage, sourcePos, destPos, regionSize, 0, NULL, NULL );
464     if( error != CL_SUCCESS )
465     {
466         log_error( "ERROR: Unable to copy image from pos %d,%d,%d to %d,%d,%d size %d,%d,%d! (%s)\n",
467                   (int)sourcePos[ 0 ], (int)sourcePos[ 1 ], (int)sourcePos[ 2 ], (int)destPos[ 0 ], (int)destPos[ 1 ], (int)destPos[ 2 ],
468                   (int)regionSize[ 0 ], (int)regionSize[ 1 ], (int)regionSize[ 2 ], IGetErrorString( error ) );
469         return error;
470     }
471 
472     // Construct the final dest image values to test against
473     if( gDebugTrace )
474         log_info( " - Host verification copy...\n" );
475 
476     copy_image_data( srcImageInfo, dstImageInfo, srcHost, dstHost, sourcePos, destPos, regionSize );
477 
478     // Map the destination image to verify the results with the host
479     // copy. The contents of the entire buffer are compared.
480     if( gDebugTrace )
481         log_info( " - Mapping results...\n" );
482 
483     size_t mappedRow, mappedSlice;
484     void* mapped = (char*)clEnqueueMapImage(queue, dstImage, CL_TRUE, CL_MAP_READ, origin, region, &mappedRow, &mappedSlice, 0, NULL, NULL, &error);
485     if (error != CL_SUCCESS)
486     {
487         log_error( "ERROR: Unable to map image for verification: %s\n", IGetErrorString( error ) );
488         return error;
489     }
490 
491     // Verify scanline by scanline, since the pitches are different
492     char *sourcePtr = dstHost;
493     size_t cur_lod_offset = 0;
494     char *destPtr = (char*)mapped;
495 
496     if( gTestMipmaps )
497     {
498         cur_lod_offset = compute_mip_level_offset(dstImageInfo, dst_lod);
499         sourcePtr += cur_lod_offset;
500     }
501 
502     size_t scanlineSize = dstImageInfo->width * get_pixel_size( dstImageInfo->format );
503     size_t rowPitch = dstImageInfo->rowPitch;
504     size_t slicePitch = dstImageInfo->slicePitch;
505     size_t dst_height_lod = dstImageInfo->height;
506     if(gTestMipmaps)
507     {
508         size_t dst_width_lod = (dstImageInfo->width >> dst_lod)?(dstImageInfo->width >> dst_lod) : 1;
509         dst_height_lod = (dstImageInfo->height >> dst_lod)?(dstImageInfo->height >> dst_lod) : 1;
510         scanlineSize = dst_width_lod * get_pixel_size(dstImageInfo->format);
511         rowPitch = scanlineSize;
512         slicePitch = rowPitch * dst_height_lod;
513     }
514 
515     if( gDebugTrace )
516         log_info( " - Scanline verification...\n" );
517 
518     size_t thirdDim;
519     size_t secondDim;
520     if (dstImageInfo->type == CL_MEM_OBJECT_IMAGE1D_ARRAY)
521     {
522         secondDim = dstImageInfo->arraySize;
523         thirdDim = 1;
524     }
525     else if (dstImageInfo->type == CL_MEM_OBJECT_IMAGE2D_ARRAY)
526     {
527         secondDim = dstImageInfo->height;
528         if( gTestMipmaps )
529             secondDim = (dstImageInfo->height >> dst_lod) ? (dstImageInfo->height >> dst_lod):1;
530         thirdDim = dstImageInfo->arraySize;
531     }
532     else
533     {
534         secondDim = dstImageInfo->height;
535         thirdDim = dstImageInfo->depth;
536         if( gTestMipmaps )
537         {
538             secondDim = (dstImageInfo->height >> dst_lod) ? (dstImageInfo->height >> dst_lod):1;
539             if(dstImageInfo->type == CL_MEM_OBJECT_IMAGE3D)
540                 thirdDim = (dstImageInfo->depth >> dst_lod) ? (dstImageInfo->depth >> dst_lod):1;
541         }
542     }
543 
544     for( size_t z = 0; z < thirdDim; z++ )
545     {
546         for( size_t y = 0; y < secondDim; y++ )
547         {
548             if( memcmp( sourcePtr, destPtr, scanlineSize ) != 0 )
549             {
550                 // Find the first missing pixel
551                 size_t pixel_size = get_pixel_size( dstImageInfo->format );
552                 size_t where = 0;
553                 for( where = 0; where < dstImageInfo->width; where++ )
554                     if( memcmp( sourcePtr + pixel_size * where, destPtr + pixel_size * where, pixel_size) )
555                         break;
556 
557                 print_first_pixel_difference_error(
558                     where, sourcePtr + pixel_size * where,
559                     destPtr + pixel_size * where, dstImageInfo, y,
560                     dstImageInfo->depth);
561                 return -1;
562             }
563             sourcePtr += rowPitch;
564             if((dstImageInfo->type == CL_MEM_OBJECT_IMAGE1D_ARRAY || dstImageInfo->type == CL_MEM_OBJECT_IMAGE1D))
565             destPtr += mappedSlice;
566             else
567             destPtr += mappedRow;
568         }
569         sourcePtr += slicePitch - rowPitch * dst_height_lod;
570         destPtr += mappedSlice - mappedRow * dst_height_lod;
571     }
572 
573     // Unmap the image.
574     error = clEnqueueUnmapMemObject(queue, dstImage, mapped, 0, NULL, NULL);
575     if (error != CL_SUCCESS)
576     {
577         log_error( "ERROR: Unable to unmap image after verify: %s\n", IGetErrorString( error ) );
578         return error;
579     }
580 
581     // Ensure the unmap call completes.
582     error = clFinish(queue);
583     if (error != CL_SUCCESS)
584     {
585         log_error("ERROR: clFinish() failed to return CL_SUCCESS: %s\n",
586                   IGetErrorString(error));
587         return error;
588     }
589 
590     return 0;
591 }
592