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