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 "harness/compat.h"
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23
24 #include "procs.h"
25
26 #define CL_EXIT_ERROR(cmd,format,...) \
27 { \
28 if ((cmd) != CL_SUCCESS) { \
29 log_error("CL ERROR: %s %u: ", __FILE__,__LINE__); \
30 log_error(format,## __VA_ARGS__ ); \
31 log_error("\n"); \
32 /*abort();*/ \
33 } \
34 }
35
36 typedef unsigned char BufferType;
37
38 // Globals for test
39 cl_command_queue queue;
40
41 // Width and height of each pair of images.
42 enum { TotalImages = 8 };
43 size_t width [TotalImages];
44 size_t height [TotalImages];
45 size_t depth [TotalImages];
46
47 // cl buffer and host buffer.
48 cl_mem buffer [TotalImages];
49 BufferType* verify[TotalImages];
50 BufferType* backing[TotalImages];
51
52 // Temporary buffer used for read and write operations.
53 BufferType* tmp_buffer;
54 size_t tmp_buffer_size;
55
56 size_t num_tries = 50; // Number of randomly selected operations to perform.
57 size_t alloc_scale = 2; // Scale term applied buffer allocation size.
58 MTdata mt;
59
60 // Initialize a buffer in host memory containing random values of the specified size.
initialize_image(BufferType * ptr,size_t w,size_t h,size_t d,MTdata mt)61 static void initialize_image(BufferType* ptr, size_t w, size_t h, size_t d, MTdata mt)
62 {
63 enum { ElementSize = sizeof(BufferType)/sizeof(unsigned char) };
64
65 unsigned char* buf = (unsigned char*)ptr;
66 size_t size = w*h*d*ElementSize;
67
68 for (size_t i = 0; i != size; i++) {
69 buf[i] = (unsigned char)(genrand_int32(mt) % 0xff);
70 }
71 }
72
73 // This function prints the contents of a buffer to standard error.
print_buffer(BufferType * buf,size_t w,size_t h,size_t d)74 void print_buffer(BufferType* buf, size_t w, size_t h, size_t d) {
75 log_error("Size = %lux%lux%lu (%lu total)\n",w,h,d,w*h*d);
76 for (unsigned k=0; k!=d;++k) {
77 log_error("Slice: %u\n",k);
78 for (unsigned j=0; j!=h;++j) {
79 for (unsigned i=0;i!=w;++i) {
80 log_error("%02x",buf[k*(w*h)+j*w+i]);
81 }
82 log_error("\n");
83 }
84 log_error("\n");
85 }
86 }
87
88 // Returns true if the two specified regions overlap.
check_overlap_rect(size_t src_offset[3],size_t dst_offset[3],size_t region[3],size_t row_pitch,size_t slice_pitch)89 bool check_overlap_rect(size_t src_offset[3],
90 size_t dst_offset[3],
91 size_t region[3],
92 size_t row_pitch,
93 size_t slice_pitch)
94 {
95 const size_t src_min[] = { src_offset[0], src_offset[1], src_offset[2] };
96 const size_t src_max[] = { src_offset[0] + region[0], src_offset[1] + region[1], src_offset[2] + region[2] };
97
98 const size_t dst_min[] = { dst_offset[0], dst_offset[1], dst_offset[2] };
99 const size_t dst_max[] = { dst_offset[0] + region[0],
100 dst_offset[1] + region[1],
101 dst_offset[2] + region[2]};
102 // Check for overlap
103 bool overlap = true;
104 unsigned i;
105 for (i = 0; i != 3; ++i)
106 {
107 overlap = overlap && (src_min[i] < dst_max[i]) && (src_max[i] > dst_min[i]);
108 }
109
110 size_t dst_start = dst_offset[2] * slice_pitch + dst_offset[1] * row_pitch + dst_offset[0];
111 size_t dst_end = dst_start + (region[2] * slice_pitch +
112 region[1] * row_pitch + region[0]);
113 size_t src_start = src_offset[2] * slice_pitch + src_offset[1] * row_pitch + src_offset[0];
114 size_t src_end = src_start + (region[2] * slice_pitch +
115 region[1] * row_pitch + region[0]);
116 if (!overlap) {
117 size_t delta_src_x = (src_offset[0] + region[0] > row_pitch) ?
118 src_offset[0] + region[0] - row_pitch : 0; size_t delta_dst_x = (dst_offset[0] + region[0] > row_pitch) ?
119 dst_offset[0] + region[0] - row_pitch : 0;
120 if ((delta_src_x > 0 && delta_src_x > dst_offset[0]) ||
121 (delta_dst_x > 0 && delta_dst_x > src_offset[0])) {
122 if ((src_start <= dst_start && dst_start < src_end) || (dst_start <= src_start && src_start < dst_end)) overlap = true;
123 }
124 if (region[2] > 1) {
125 size_t src_height = slice_pitch / row_pitch; size_t dst_height = slice_pitch / row_pitch;
126 size_t delta_src_y = (src_offset[1] + region[1] > src_height) ? src_offset[1] + region[1] - src_height : 0;
127 size_t delta_dst_y = (dst_offset[1] + region[1] > dst_height) ? dst_offset[1] + region[1] - dst_height : 0;
128 if ((delta_src_y > 0 && delta_src_y > dst_offset[1]) ||
129 (delta_dst_y > 0 && delta_dst_y > src_offset[1])) {
130 if ((src_start <= dst_start && dst_start < src_end) || (dst_start <= src_start && src_start < dst_end))
131 overlap = true;
132 }
133 }
134 }
135 return overlap;
136 }
137
138
139
140 // This function invokes the CopyBufferRect CL command and then mirrors the operation on the host side verify buffers.
copy_region(size_t src,size_t soffset[3],size_t sregion[3],size_t dst,size_t doffset[3],size_t dregion[3])141 int copy_region(size_t src, size_t soffset[3], size_t sregion[3], size_t dst, size_t doffset[3], size_t dregion[3]) {
142
143 // Copy between cl buffers.
144 size_t src_slice_pitch = (width[src]*height[src] != 1) ? width[src]*height[src] : 0;
145 size_t dst_slice_pitch = (width[dst]*height[dst] != 1) ? width[dst]*height[dst] : 0;
146 size_t src_row_pitch = width[src];
147
148 cl_int err;
149 if (check_overlap_rect(soffset,doffset,sregion,src_row_pitch, src_slice_pitch)) {
150 log_info( "Copy overlap reported, skipping copy buffer rect\n" );
151 return CL_SUCCESS;
152 } else {
153 if ((err = clEnqueueCopyBufferRect(queue,
154 buffer[src],buffer[dst],
155 soffset, doffset,
156 sregion,/*dregion,*/
157 width[src], src_slice_pitch,
158 width[dst], dst_slice_pitch,
159 0, NULL, NULL)) != CL_SUCCESS)
160 {
161 CL_EXIT_ERROR(err, "clEnqueueCopyBufferRect failed between %u and %u",(unsigned)src,(unsigned)dst);
162 }
163 }
164
165 // Copy between host buffers.
166 size_t total = sregion[0] * sregion[1] * sregion[2];
167
168 size_t spitch = width[src];
169 size_t sslice = width[src]*height[src];
170
171 size_t dpitch = width[dst];
172 size_t dslice = width[dst]*height[dst];
173
174 for (size_t i = 0; i != total; ++i) {
175
176 // Compute the coordinates of the element within the source and destination regions.
177 size_t rslice = sregion[0]*sregion[1];
178 size_t sz = i / rslice;
179 size_t sy = (i % rslice) / sregion[0];
180 size_t sx = (i % rslice) % sregion[0];
181
182 size_t dz = sz;
183 size_t dy = sy;
184 size_t dx = sx;
185
186 // Compute the offset in bytes of the source and destination.
187 size_t s_idx = (soffset[2]+sz)*sslice + (soffset[1]+sy)*spitch + soffset[0]+sx;
188 size_t d_idx = (doffset[2]+dz)*dslice + (doffset[1]+dy)*dpitch + doffset[0]+dx;
189
190 verify[dst][d_idx] = verify[src][s_idx];
191 }
192
193 return 0;
194 }
195
196 // This function compares the destination region in the buffer pointed
197 // to by device, to the source region of the specified verify buffer.
verify_region(BufferType * device,size_t src,size_t soffset[3],size_t sregion[3],size_t dst,size_t doffset[3])198 int verify_region(BufferType* device, size_t src, size_t soffset[3], size_t sregion[3], size_t dst, size_t doffset[3]) {
199
200 // Copy between host buffers.
201 size_t spitch = width[src];
202 size_t sslice = width[src]*height[src];
203
204 size_t dpitch = width[dst];
205 size_t dslice = width[dst]*height[dst];
206
207 size_t total = sregion[0] * sregion[1] * sregion[2];
208 for (size_t i = 0; i != total; ++i) {
209
210 // Compute the coordinates of the element within the source and destination regions.
211 size_t rslice = sregion[0]*sregion[1];
212 size_t sz = i / rslice;
213 size_t sy = (i % rslice) / sregion[0];
214 size_t sx = (i % rslice) % sregion[0];
215
216 // Compute the offset in bytes of the source and destination.
217 size_t s_idx = (soffset[2]+sz)*sslice + (soffset[1]+sy)*spitch + soffset[0]+sx;
218 size_t d_idx = (doffset[2]+sz)*dslice + (doffset[1]+sy)*dpitch + doffset[0]+sx;
219
220 if (device[d_idx] != verify[src][s_idx]) {
221 log_error("Verify failed on comparsion %lu: coordinate (%lu, %lu, %lu) of region\n",i,sx,sy,sz);
222 log_error("0x%02x != 0x%02x\n", device[d_idx], verify[src][s_idx]);
223 #if 0
224 // Uncomment this section to print buffers.
225 log_error("Device (copy): [%lu]\n",dst);
226 print_buffer(device,width[dst],height[dst],depth[dst]);
227 log_error("\n");
228 log_error("Verify: [%lu]\n",src);
229 print_buffer(verify[src],width[src],height[src],depth[src]);
230 log_error("\n");
231 abort();
232 #endif
233 return -1;
234 }
235 }
236
237 return 0;
238 }
239
240
241 // This function invokes ReadBufferRect to read a region from the
242 // specified source buffer into a temporary destination buffer. The
243 // contents of the temporary buffer are then compared to the source
244 // region of the corresponding verify buffer.
read_verify_region(size_t src,size_t soffset[3],size_t sregion[3],size_t dst,size_t doffset[3],size_t dregion[3])245 int read_verify_region(size_t src, size_t soffset[3], size_t sregion[3], size_t dst, size_t doffset[3], size_t dregion[3]) {
246
247 // Clear the temporary destination host buffer.
248 memset(tmp_buffer, 0xff, tmp_buffer_size);
249
250 size_t src_slice_pitch = (width[src]*height[src] != 1) ? width[src]*height[src] : 0;
251 size_t dst_slice_pitch = (width[dst]*height[dst] != 1) ? width[dst]*height[dst] : 0;
252
253 // Copy the source region of the cl buffer, to the destination region of the temporary buffer.
254 CL_EXIT_ERROR(clEnqueueReadBufferRect(queue,
255 buffer[src],
256 CL_TRUE,
257 soffset,doffset,
258 sregion,
259 width[src], src_slice_pitch,
260 width[dst], dst_slice_pitch,
261 tmp_buffer,
262 0, NULL, NULL), "clEnqueueCopyBufferRect failed between %u and %u",(unsigned)src,(unsigned)dst);
263
264 return verify_region(tmp_buffer,src,soffset,sregion,dst,doffset);
265 }
266
267 // This function performs the same verification check as
268 // read_verify_region, except a MapBuffer command is used to access the
269 // device buffer data instead of a ReadBufferRect, and the whole
270 // buffer is checked.
map_verify_region(size_t src)271 int map_verify_region(size_t src) {
272
273 size_t size_bytes = width[src]*height[src]*depth[src]*sizeof(BufferType);
274
275 // Copy the source region of the cl buffer, to the destination region of the temporary buffer.
276 cl_int err;
277 BufferType* mapped = (BufferType*)clEnqueueMapBuffer(queue,buffer[src],CL_TRUE,CL_MAP_READ,0,size_bytes,0,NULL,NULL,&err);
278 CL_EXIT_ERROR(err, "clEnqueueMapBuffer failed for buffer %u",(unsigned)src);
279
280 size_t soffset[] = { 0, 0, 0 };
281 size_t sregion[] = { width[src], height[src], depth[src] };
282
283 int ret = verify_region(mapped,src,soffset,sregion,src,soffset);
284
285 CL_EXIT_ERROR(clEnqueueUnmapMemObject(queue,buffer[src],mapped,0,NULL,NULL),
286 "clEnqueueUnmapMemObject failed for buffer %u",(unsigned)src);
287
288 return ret;
289 }
290
291 // This function generates a new temporary buffer and then writes a
292 // region of it to a region in the specified destination buffer.
write_region(size_t src,size_t soffset[3],size_t sregion[3],size_t dst,size_t doffset[3],size_t dregion[3])293 int write_region(size_t src, size_t soffset[3], size_t sregion[3], size_t dst, size_t doffset[3], size_t dregion[3]) {
294
295 initialize_image(tmp_buffer, tmp_buffer_size, 1, 1, mt);
296 // memset(tmp_buffer, 0xf0, tmp_buffer_size);
297
298 size_t src_slice_pitch = (width[src]*height[src] != 1) ? width[src]*height[src] : 0;
299 size_t dst_slice_pitch = (width[dst]*height[dst] != 1) ? width[dst]*height[dst] : 0;
300
301 // Copy the source region of the cl buffer, to the destination region of the temporary buffer.
302 CL_EXIT_ERROR(clEnqueueWriteBufferRect(queue,
303 buffer[dst],
304 CL_TRUE,
305 doffset,soffset,
306 /*sregion,*/dregion,
307 width[dst], dst_slice_pitch,
308 width[src], src_slice_pitch,
309 tmp_buffer,
310 0, NULL, NULL), "clEnqueueWriteBufferRect failed between %u and %u",(unsigned)src,(unsigned)dst);
311
312 // Copy from the temporary buffer to the host buffer.
313 size_t spitch = width[src];
314 size_t sslice = width[src]*height[src];
315 size_t dpitch = width[dst];
316 size_t dslice = width[dst]*height[dst];
317
318 size_t total = sregion[0] * sregion[1] * sregion[2];
319 for (size_t i = 0; i != total; ++i) {
320
321 // Compute the coordinates of the element within the source and destination regions.
322 size_t rslice = sregion[0]*sregion[1];
323 size_t sz = i / rslice;
324 size_t sy = (i % rslice) / sregion[0];
325 size_t sx = (i % rslice) % sregion[0];
326
327 size_t dz = sz;
328 size_t dy = sy;
329 size_t dx = sx;
330
331 // Compute the offset in bytes of the source and destination.
332 size_t s_idx = (soffset[2]+sz)*sslice + (soffset[1]+sy)*spitch + soffset[0]+sx;
333 size_t d_idx = (doffset[2]+dz)*dslice + (doffset[1]+dy)*dpitch + doffset[0]+dx;
334
335 verify[dst][d_idx] = tmp_buffer[s_idx];
336 }
337 return 0;
338 }
339
mem_obj_destructor_callback(cl_mem,void * data)340 void CL_CALLBACK mem_obj_destructor_callback( cl_mem, void *data )
341 {
342 free( data );
343 }
344
345 // This is the main test function for the conformance test.
346 int
test_bufferreadwriterect(cl_device_id device,cl_context context,cl_command_queue queue_,int num_elements)347 test_bufferreadwriterect(cl_device_id device, cl_context context, cl_command_queue queue_, int num_elements)
348 {
349 queue = queue_;
350 cl_int err;
351
352 // Initialize the random number generator.
353 mt = init_genrand( gRandomSeed );
354
355 // Compute a maximum buffer size based on the number of test images and the device maximum.
356 cl_ulong max_mem_alloc_size = 0;
357 CL_EXIT_ERROR(clGetDeviceInfo(device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &max_mem_alloc_size, NULL),"Could not get device info");
358 log_info("CL_DEVICE_MAX_MEM_ALLOC_SIZE = %llu bytes.\n", max_mem_alloc_size);
359
360 // Confirm that the maximum allocation size is not zero.
361 if (max_mem_alloc_size == 0) {
362 log_error("Error: CL_DEVICE_MAX_MEM_ALLOC_SIZE is zero bytes\n");
363 return -1;
364 }
365
366 // Guess at a reasonable maximum dimension.
367 size_t max_mem_alloc_dim = (size_t)cbrt((double)(max_mem_alloc_size/sizeof(BufferType)))/alloc_scale;
368 if (max_mem_alloc_dim == 0) {
369 max_mem_alloc_dim = max_mem_alloc_size;
370 }
371
372 log_info("Using maximum dimension = %lu.\n", max_mem_alloc_dim);
373
374 // Create pairs of cl buffers and host buffers on which operations will be mirrored.
375 log_info("Creating %u pairs of random sized host and cl buffers.\n", TotalImages);
376
377 size_t max_size = 0;
378 size_t total_bytes = 0;
379
380 for (unsigned i=0; i != TotalImages; ++i) {
381
382 // Determine a width and height for this buffer.
383 size_t size_bytes;
384 size_t tries = 0;
385 size_t max_tries = 1048576;
386 do {
387 width[i] = get_random_size_t(1, max_mem_alloc_dim, mt);
388 height[i] = get_random_size_t(1, max_mem_alloc_dim, mt);
389 depth[i] = get_random_size_t(1, max_mem_alloc_dim, mt);
390 ++tries;
391 } while ((tries < max_tries) && (size_bytes = width[i]*height[i]*depth[i]*sizeof(BufferType)) > max_mem_alloc_size);
392
393 // Check to see if adequately sized buffers were found.
394 if (tries >= max_tries) {
395 log_error("Error: Could not find random buffer sized less than %llu bytes in %lu tries.\n",
396 max_mem_alloc_size, max_tries);
397 return -1;
398 }
399
400 // Keep track of the dimensions of the largest buffer.
401 max_size = (size_bytes > max_size) ? size_bytes : max_size;
402 total_bytes += size_bytes;
403
404 log_info("Buffer[%u] is (%lu,%lu,%lu) = %lu MB (truncated)\n",i,width[i],height[i],depth[i],(size_bytes)/1048576);
405 }
406
407 log_info( "Total size: %lu MB (truncated)\n", total_bytes/1048576 );
408
409 // Allocate a temporary buffer for read and write operations.
410 tmp_buffer_size = max_size;
411 tmp_buffer = (BufferType*)malloc(tmp_buffer_size);
412
413 // Initialize cl buffers
414 log_info( "Initializing buffers\n" );
415 for (unsigned i=0; i != TotalImages; ++i) {
416
417 size_t size_bytes = width[i]*height[i]*depth[i]*sizeof(BufferType);
418
419 // Allocate a host copy of the buffer for verification.
420 verify[i] = (BufferType*)malloc(size_bytes);
421 CL_EXIT_ERROR(verify[i] ? CL_SUCCESS : -1, "malloc of host buffer failed for buffer %u", i);
422
423 // Allocate the buffer in host memory.
424 backing[i] = (BufferType*)malloc(size_bytes);
425 CL_EXIT_ERROR(backing[i] ? CL_SUCCESS : -1, "malloc of backing buffer failed for buffer %u", i);
426
427 // Generate a random buffer.
428 log_info( "Initializing buffer %u\n", i );
429 initialize_image(verify[i], width[i], height[i], depth[i], mt);
430
431 // Copy the image into a buffer which will passed to CL.
432 memcpy(backing[i], verify[i], size_bytes);
433
434 // Create the CL buffer.
435 buffer[i] = clCreateBuffer (context, CL_MEM_USE_HOST_PTR | CL_MEM_READ_WRITE, size_bytes, backing[i], &err);
436 CL_EXIT_ERROR(err,"clCreateBuffer failed for buffer %u", i);
437
438 // Make sure buffer is cleaned up appropriately if we encounter an error in the rest of the calls.
439 err = clSetMemObjectDestructorCallback( buffer[i], mem_obj_destructor_callback, backing[i] );
440 CL_EXIT_ERROR(err, "Unable to set mem object destructor callback" );
441 }
442
443 // Main test loop, run num_tries times.
444 log_info( "Executing %u test operations selected at random.\n", (unsigned)num_tries );
445 for (size_t iter = 0; iter < num_tries; ++iter) {
446
447 // Determine a source and a destination.
448 size_t src = get_random_size_t(0,TotalImages,mt);
449 size_t dst = get_random_size_t(0,TotalImages,mt);
450
451 // Determine the minimum dimensions.
452 size_t min_width = width[src] < width[dst] ? width[src] : width[dst];
453 size_t min_height = height[src] < height[dst] ? height[src] : height[dst];
454 size_t min_depth = depth[src] < depth[dst] ? depth[src] : depth[dst];
455
456 // Generate a random source rectangle within the minimum dimensions.
457 size_t mx = get_random_size_t(0, min_width-1, mt);
458 size_t my = get_random_size_t(0, min_height-1, mt);
459 size_t mz = get_random_size_t(0, min_depth-1, mt);
460
461 size_t sw = get_random_size_t(1, (min_width - mx), mt);
462 size_t sh = get_random_size_t(1, (min_height - my), mt);
463 size_t sd = get_random_size_t(1, (min_depth - mz), mt);
464
465 size_t sx = get_random_size_t(0, width[src]-sw, mt);
466 size_t sy = get_random_size_t(0, height[src]-sh, mt);
467 size_t sz = get_random_size_t(0, depth[src]-sd, mt);
468
469 size_t soffset[] = { sx, sy, sz };
470 size_t sregion[] = { sw, sh, sd };
471
472 // Generate a destination rectangle of the same size.
473 size_t dw = sw;
474 size_t dh = sh;
475 size_t dd = sd;
476
477 // Generate a random destination offset within the buffer.
478 size_t dx = get_random_size_t(0, (width[dst] - dw), mt);
479 size_t dy = get_random_size_t(0, (height[dst] - dh), mt);
480 size_t dz = get_random_size_t(0, (depth[dst] - dd), mt);
481 size_t doffset[] = { dx, dy, dz };
482 size_t dregion[] = { dw, dh, dd };
483
484 // Execute one of three operations:
485 // - Copy: Copies between src and dst within each set of host, buffer, and images.
486 // - Read & verify: Reads src region from buffer and image, and compares to host.
487 // - Write: Generates new buffer with src dimensions, and writes to cl buffer and image.
488
489 enum { TotalOperations = 3 };
490 size_t operation = get_random_size_t(0,TotalOperations,mt);
491
492 switch (operation) {
493 case 0:
494 log_info("%lu Copy %lu offset (%lu,%lu,%lu) -> %lu offset (%lu,%lu,%lu) region (%lux%lux%lu = %lu)\n",
495 iter,
496 src, soffset[0], soffset[1], soffset[2],
497 dst, doffset[0], doffset[1], doffset[2],
498 sregion[0], sregion[1], sregion[2],
499 sregion[0]*sregion[1]*sregion[2]);
500 if ((err = copy_region(src, soffset, sregion, dst, doffset, dregion)))
501 return err;
502 break;
503 case 1:
504 log_info("%lu Read %lu offset (%lu,%lu,%lu) -> %lu offset (%lu,%lu,%lu) region (%lux%lux%lu = %lu)\n",
505 iter,
506 src, soffset[0], soffset[1], soffset[2],
507 dst, doffset[0], doffset[1], doffset[2],
508 sregion[0], sregion[1], sregion[2],
509 sregion[0]*sregion[1]*sregion[2]);
510 if ((err = read_verify_region(src, soffset, sregion, dst, doffset, dregion)))
511 return err;
512 break;
513 case 2:
514 log_info("%lu Write %lu offset (%lu,%lu,%lu) -> %lu offset (%lu,%lu,%lu) region (%lux%lux%lu = %lu)\n",
515 iter,
516 src, soffset[0], soffset[1], soffset[2],
517 dst, doffset[0], doffset[1], doffset[2],
518 sregion[0], sregion[1], sregion[2],
519 sregion[0]*sregion[1]*sregion[2]);
520 if ((err = write_region(src, soffset, sregion, dst, doffset, dregion)))
521 return err;
522 break;
523 }
524
525 #if 0
526 // Uncomment this section to verify each operation.
527 // If commented out, verification won't occur until the end of the
528 // test, and it will not be possible to determine which operation failed.
529 log_info("Verify src %lu offset (%u,%u,%u) region (%lux%lux%lu)\n", src, 0, 0, 0, width[src], height[src], depth[src]);
530 if (err = map_verify_region(src))
531 return err;
532
533 log_info("Verify dst %lu offset (%u,%u,%u) region (%lux%lux%lu)\n", dst, 0, 0, 0, width[dst], height[dst], depth[dst]);
534 if (err = map_verify_region(dst))
535 return err;
536
537
538 #endif
539
540 } // end main for loop.
541
542 for (unsigned i=0;i<TotalImages;++i) {
543 log_info("Verify %u offset (%u,%u,%u) region (%lux%lux%lu)\n", i, 0, 0, 0, width[i], height[i], depth[i]);
544 if ((err = map_verify_region(i)))
545 return err;
546 }
547
548 // Clean-up.
549 free_mtdata(mt);
550 for (unsigned i=0;i<TotalImages;++i) {
551 free( verify[i] );
552 clReleaseMemObject( buffer[i] );
553 }
554 free( tmp_buffer );
555
556 if (!err) {
557 log_info("RECT read, write test passed\n");
558 }
559
560 return err;
561 }
562
563
564
565