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 <string.h>
20
21 #if !defined(_WIN32)
22 #include <unistd.h>
23 #include <sys/time.h>
24 #endif
25
26 #include "../testBase.h"
27 #include "../harness/fpcontrol.h"
28 #include "../harness/parseParameters.h"
29
30 #include <vector>
31
32 #if defined(__PPC__)
33 // Global varaiable used to hold the FPU control register state. The FPSCR register can not
34 // be used because not all Power implementations retain or observed the NI (non-IEEE
35 // mode) bit.
36 __thread fpu_control_t fpu_control = 0;
37 #endif
38
39 bool gDebugTrace;
40 bool gExtraValidateInfo;
41 bool gDisableOffsets;
42 bool gTestSmallImages;
43 bool gTestMaxImages;
44 bool gTestImage2DFromBuffer;
45 bool gTestMipmaps;
46 bool gDeviceLt20 = false;
47 cl_filter_mode gFilterModeToUse = (cl_filter_mode)-1;
48 // Default is CL_MEM_USE_HOST_PTR for the test
49 cl_mem_flags gMemFlagsToUse = CL_MEM_USE_HOST_PTR;
50 bool gUseKernelSamplers = false;
51 int gTypesToTest = 0;
52 cl_addressing_mode gAddressModeToUse = (cl_addressing_mode)-1;
53 int gNormalizedModeToUse = 7;
54 cl_channel_type gChannelTypeToUse = (cl_channel_type)-1;
55 cl_channel_order gChannelOrderToUse = (cl_channel_order)-1;
56 bool gEnablePitch = false;
57
58 int gtestTypesToRun = 0;
59 static int testTypesToRun;
60
61 #define MAX_ALLOWED_STD_DEVIATION_IN_MB 8.0
62
63 static void printUsage( const char *execName );
64
65 extern int test_image_set( cl_device_id device, cl_context context, cl_command_queue queue, test_format_set_fn formatTestFn, cl_mem_object_type imageType );
66
67 /** read_write images only support sampler-less read buildt-ins which require special settings
68 * for some global parameters. This pair of functions temporarily overwrite those global parameters
69 * and then recover them after completing a read_write test.
70 */
overwrite_global_params_for_read_write_test(bool * tTestMipmaps,bool * tDisableOffsets,bool * tNormalizedModeToUse,cl_filter_mode * tFilterModeToUse)71 static void overwrite_global_params_for_read_write_test( bool *tTestMipmaps,
72 bool *tDisableOffsets,
73 bool *tNormalizedModeToUse,
74 cl_filter_mode *tFilterModeToUse)
75 {
76 log_info("Overwrite global settings for read_write image tests. The overwritten values:\n");
77 log_info("gTestMipmaps = false, gDisableOffsets = true, gNormalizedModeToUse = false, gFilterModeToUse = CL_FILTER_NEAREST\n" );
78 // mipmap images only support sampler read built-in while read_write images only support
79 // sampler-less read built-in. Hence we cannot test mipmap for read_write image.
80 *tTestMipmaps = gTestMipmaps;
81 gTestMipmaps = false;
82
83 // Read_write images are read by sampler-less read which does not handle out-of-bound read
84 // It's application responsibility to make sure that the read happens in-bound
85 // Therefore we should not enable offset in testing read_write images because it will cause out-of-bound
86 *tDisableOffsets = gDisableOffsets;
87 gDisableOffsets = true;
88
89 // The sampler-less read image functions behave exactly as the corresponding read image functions
90
91
92 *tNormalizedModeToUse = gNormalizedModeToUse;
93 gNormalizedModeToUse = false;
94 *tFilterModeToUse = gFilterModeToUse;
95 gFilterModeToUse = CL_FILTER_NEAREST;
96 }
97
98 /** Recover the global settings overwritten for read_write tests. This is necessary because
99 * there may be other tests (i.e. read or write) are called together with read_write test.
100 */
recover_global_params_from_read_write_test(bool tTestMipmaps,bool tDisableOffsets,bool tNormalizedModeToUse,cl_filter_mode tFilterModeToUse)101 static void recover_global_params_from_read_write_test(bool tTestMipmaps,
102 bool tDisableOffsets,
103 bool tNormalizedModeToUse,
104 cl_filter_mode tFilterModeToUse)
105 {
106 gTestMipmaps = tTestMipmaps;
107 gDisableOffsets = tDisableOffsets;
108 gNormalizedModeToUse = tNormalizedModeToUse;
109 gFilterModeToUse = tFilterModeToUse;
110 }
111
doTest(cl_device_id device,cl_context context,cl_command_queue queue,cl_mem_object_type imageType)112 static int doTest( cl_device_id device, cl_context context, cl_command_queue queue, cl_mem_object_type imageType )
113 {
114 int ret = 0;
115 bool is_2d_image = imageType == CL_MEM_OBJECT_IMAGE2D;
116 bool tTestMipMaps = false;
117 bool tDisableOffsets = false;
118 bool tNormalizedModeToUse = false;
119 cl_filter_mode tFilterModeToUse = (cl_filter_mode)-1;
120 auto version = get_device_cl_version(device);
121 if (version < Version(2, 0)) {
122 gDeviceLt20 = true;
123 }
124
125 if( testTypesToRun & kReadTests )
126 {
127 gtestTypesToRun = kReadTests;
128 ret += test_image_set( device, context, queue, test_read_image_formats, imageType );
129
130 if( is_2d_image && is_extension_available( device, "cl_khr_image2d_from_buffer" ) )
131 {
132 log_info( "Testing read_image{f | i | ui} for 2D image from buffer\n" );
133
134 // NOTE: for 2D image from buffer test, gTestSmallImages, gTestMaxImages, gTestRounding and gTestMipmaps must be false
135 if( gTestSmallImages == false && gTestMaxImages == false && gTestRounding == false && gTestMipmaps == false )
136 {
137 cl_mem_flags saved_gMemFlagsToUse = gMemFlagsToUse;
138 gTestImage2DFromBuffer = true;
139
140 // disable CL_MEM_USE_HOST_PTR for 1.2 extension but enable this for 2.0
141 gMemFlagsToUse = CL_MEM_COPY_HOST_PTR;
142
143 ret += test_image_set( device, context, queue, test_read_image_formats, imageType );
144
145 gTestImage2DFromBuffer = false;
146 gMemFlagsToUse = saved_gMemFlagsToUse;
147 }
148 }
149 }
150
151 if( testTypesToRun & kWriteTests )
152 {
153 gtestTypesToRun = kWriteTests;
154 ret += test_image_set( device, context, queue, test_write_image_formats, imageType );
155
156 if( is_2d_image && is_extension_available( device, "cl_khr_image2d_from_buffer" ) )
157 {
158 log_info( "Testing write_image{f | i | ui} for 2D image from buffer\n" );
159
160 // NOTE: for 2D image from buffer test, gTestSmallImages, gTestMaxImages,gTestRounding and gTestMipmaps must be false
161 if( gTestSmallImages == false && gTestMaxImages == false && gTestRounding == false && gTestMipmaps == false )
162 {
163 bool saved_gEnablePitch = gEnablePitch;
164 cl_mem_flags saved_gMemFlagsToUse = gMemFlagsToUse;
165 gEnablePitch = true;
166
167 // disable CL_MEM_USE_HOST_PTR for 1.2 extension but enable this for 2.0
168 gMemFlagsToUse = CL_MEM_COPY_HOST_PTR;
169 gTestImage2DFromBuffer = true;
170
171 ret += test_image_set( device, context, queue, test_write_image_formats, imageType );
172
173 gTestImage2DFromBuffer = false;
174 gMemFlagsToUse = saved_gMemFlagsToUse;
175 gEnablePitch = saved_gEnablePitch;
176 }
177 }
178 }
179
180 if (testTypesToRun & kReadWriteTests) {
181 if (gDeviceLt20) {
182 log_info("TEST skipped, Opencl 2.0 + requried for this test");
183 return ret;
184 }
185 }
186
187 if( ( testTypesToRun & kReadWriteTests ) && !gTestMipmaps )
188 {
189 gtestTypesToRun = kReadWriteTests;
190 overwrite_global_params_for_read_write_test(&tTestMipMaps, &tDisableOffsets, &tNormalizedModeToUse, &tFilterModeToUse);
191 ret += test_image_set( device, context, queue, test_read_image_formats, imageType );
192
193 if( is_2d_image && is_extension_available( device, "cl_khr_image2d_from_buffer" ) )
194 {
195 log_info("Testing read_image{f | i | ui} for 2D image from buffer\n");
196
197 // NOTE: for 2D image from buffer test, gTestSmallImages, gTestMaxImages, gTestRounding and gTestMipmaps must be false
198 if( gTestSmallImages == false && gTestMaxImages == false && gTestRounding == false && gTestMipmaps == false )
199 {
200 cl_mem_flags saved_gMemFlagsToUse = gMemFlagsToUse;
201 gTestImage2DFromBuffer = true;
202
203 // disable CL_MEM_USE_HOST_PTR for 1.2 extension but enable this for 2.0
204 gMemFlagsToUse = CL_MEM_COPY_HOST_PTR;
205
206 ret += test_image_set( device, context, queue, test_read_image_formats, imageType );
207
208 gTestImage2DFromBuffer = false;
209 gMemFlagsToUse = saved_gMemFlagsToUse;
210 }
211 }
212
213 ret += test_image_set( device, context, queue, test_write_image_formats, imageType );
214
215 if( is_2d_image && is_extension_available( device, "cl_khr_image2d_from_buffer" ) )
216 {
217 log_info("Testing write_image{f | i | ui} for 2D image from buffer\n");
218
219 // NOTE: for 2D image from buffer test, gTestSmallImages, gTestMaxImages,gTestRounding and gTestMipmaps must be false
220 if( gTestSmallImages == false && gTestMaxImages == false && gTestRounding == false && gTestMipmaps == false )
221 {
222 bool saved_gEnablePitch = gEnablePitch;
223 cl_mem_flags saved_gMemFlagsToUse = gMemFlagsToUse;
224 gEnablePitch = true;
225
226 // disable CL_MEM_USE_HOST_PTR for 1.2 extension but enable this for 2.0
227 gMemFlagsToUse = CL_MEM_COPY_HOST_PTR;
228 gTestImage2DFromBuffer = true;
229
230 ret += test_image_set( device, context, queue, test_write_image_formats, imageType );
231
232 gTestImage2DFromBuffer = false;
233 gMemFlagsToUse = saved_gMemFlagsToUse;
234 gEnablePitch = saved_gEnablePitch;
235 }
236 }
237
238 recover_global_params_from_read_write_test( tTestMipMaps, tDisableOffsets, tNormalizedModeToUse, tFilterModeToUse );
239 }
240
241 return ret;
242 }
243
test_1D(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)244 int test_1D(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
245 {
246 return doTest( device, context, queue, CL_MEM_OBJECT_IMAGE1D );
247 }
test_2D(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)248 int test_2D(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
249 {
250 return doTest( device, context, queue, CL_MEM_OBJECT_IMAGE2D );
251 }
test_3D(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)252 int test_3D(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
253 {
254 return doTest( device, context, queue, CL_MEM_OBJECT_IMAGE3D );
255 }
test_1Darray(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)256 int test_1Darray(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
257 {
258 return doTest( device, context, queue, CL_MEM_OBJECT_IMAGE1D_ARRAY );
259 }
test_2Darray(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)260 int test_2Darray(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
261 {
262 return doTest( device, context, queue, CL_MEM_OBJECT_IMAGE2D_ARRAY );
263 }
264
265 test_definition test_list[] = {
266 ADD_TEST( 1D ),
267 ADD_TEST( 2D ),
268 ADD_TEST( 3D ),
269 ADD_TEST( 1Darray ),
270 ADD_TEST( 2Darray ),
271 };
272
273 const int test_num = ARRAY_SIZE( test_list );
274
main(int argc,const char * argv[])275 int main(int argc, const char *argv[])
276 {
277 cl_channel_type chanType;
278 cl_channel_order chanOrder;
279
280 argc = parseCustomParam(argc, argv);
281 if (argc == -1)
282 {
283 return -1;
284 }
285
286 const char ** argList = (const char **)calloc( argc, sizeof( char*) );
287
288 if( NULL == argList )
289 {
290 log_error( "Failed to allocate memory for argList array.\n" );
291 return 1;
292 }
293
294 argList[0] = argv[0];
295 size_t argCount = 1;
296
297 // Parse arguments
298 for( int i = 1; i < argc; i++ )
299 {
300 if( strcmp( argv[i], "debug_trace" ) == 0 )
301 gDebugTrace = true;
302
303 else if( strcmp( argv[i], "CL_FILTER_NEAREST" ) == 0 || strcmp( argv[i], "NEAREST" ) == 0 )
304 gFilterModeToUse = CL_FILTER_NEAREST;
305 else if( strcmp( argv[i], "CL_FILTER_LINEAR" ) == 0 || strcmp( argv[i], "LINEAR" ) == 0 )
306 gFilterModeToUse = CL_FILTER_LINEAR;
307
308 else if( strcmp( argv[i], "CL_ADDRESS_NONE" ) == 0 )
309 gAddressModeToUse = CL_ADDRESS_NONE;
310 else if( strcmp( argv[i], "CL_ADDRESS_CLAMP" ) == 0 )
311 gAddressModeToUse = CL_ADDRESS_CLAMP;
312 else if( strcmp( argv[i], "CL_ADDRESS_CLAMP_TO_EDGE" ) == 0 )
313 gAddressModeToUse = CL_ADDRESS_CLAMP_TO_EDGE;
314 else if( strcmp( argv[i], "CL_ADDRESS_REPEAT" ) == 0 )
315 gAddressModeToUse = CL_ADDRESS_REPEAT;
316 else if( strcmp( argv[i], "CL_ADDRESS_MIRRORED_REPEAT" ) == 0 )
317 gAddressModeToUse = CL_ADDRESS_MIRRORED_REPEAT;
318
319 else if( strcmp( argv[i], "NORMALIZED" ) == 0 )
320 gNormalizedModeToUse = true;
321 else if( strcmp( argv[i], "UNNORMALIZED" ) == 0 )
322 gNormalizedModeToUse = false;
323
324
325 else if( strcmp( argv[i], "no_offsets" ) == 0 )
326 gDisableOffsets = true;
327 else if( strcmp( argv[i], "small_images" ) == 0 )
328 gTestSmallImages = true;
329 else if( strcmp( argv[i], "max_images" ) == 0 )
330 gTestMaxImages = true;
331 else if( strcmp( argv[i], "use_pitches" ) == 0 )
332 gEnablePitch = true;
333 else if( strcmp( argv[i], "rounding" ) == 0 )
334 gTestRounding = true;
335 else if( strcmp( argv[i], "extra_validate" ) == 0 )
336 gExtraValidateInfo = true;
337 else if( strcmp( argv[i], "test_mipmaps" ) == 0 ) {
338 // 2.0 Spec does not allow using mem flags, unnormalized coordinates with mipmapped images
339 gTestMipmaps = true;
340 gMemFlagsToUse = 0;
341 gNormalizedModeToUse = true;
342 }
343
344 else if( strcmp( argv[i], "read" ) == 0 )
345 testTypesToRun |= kReadTests;
346 else if( strcmp( argv[i], "write" ) == 0 )
347 testTypesToRun |= kWriteTests;
348 else if( strcmp( argv[i], "read_write" ) == 0 )
349 {
350 testTypesToRun |= kReadWriteTests;
351 }
352
353 else if( strcmp( argv[i], "local_samplers" ) == 0 )
354 gUseKernelSamplers = true;
355
356 else if( strcmp( argv[i], "int" ) == 0 )
357 gTypesToTest |= kTestInt;
358 else if( strcmp( argv[i], "uint" ) == 0 )
359 gTypesToTest |= kTestUInt;
360 else if( strcmp( argv[i], "float" ) == 0 )
361 gTypesToTest |= kTestFloat;
362
363 else if( strcmp( argv[i], "CL_MEM_COPY_HOST_PTR" ) == 0 || strcmp( argv[i], "COPY_HOST_PTR" ) == 0 )
364 gMemFlagsToUse = CL_MEM_COPY_HOST_PTR;
365 else if( strcmp( argv[i], "CL_MEM_USE_HOST_PTR" ) == 0 || strcmp( argv[i], "USE_HOST_PTR" ) == 0 )
366 gMemFlagsToUse = CL_MEM_USE_HOST_PTR;
367 else if( strcmp( argv[i], "CL_MEM_ALLOC_HOST_PTR" ) == 0 || strcmp( argv[i], "ALLOC_HOST_PTR" ) == 0 )
368 gMemFlagsToUse = CL_MEM_ALLOC_HOST_PTR;
369 else if( strcmp( argv[i], "NO_HOST_PTR" ) == 0 )
370 gMemFlagsToUse = 0;
371
372 else if( strcmp( argv[i], "--help" ) == 0 || strcmp( argv[i], "-h" ) == 0 )
373 {
374 printUsage( argv[ 0 ] );
375 return -1;
376 }
377
378 else if( ( chanType = get_channel_type_from_name( argv[i] ) ) != (cl_channel_type)-1 )
379 gChannelTypeToUse = chanType;
380
381 else if( ( chanOrder = get_channel_order_from_name( argv[i] ) ) != (cl_channel_order)-1 )
382 gChannelOrderToUse = chanOrder;
383 else
384 {
385 argList[argCount] = argv[i];
386 argCount++;
387 }
388 }
389
390 if( testTypesToRun == 0 )
391 testTypesToRun = kAllTests;
392 if( gTypesToTest == 0 )
393 gTypesToTest = kTestAllTypes;
394
395 if( gTestSmallImages )
396 log_info( "Note: Using small test images\n" );
397
398 // On most platforms which support denorm, default is FTZ off. However,
399 // on some hardware where the reference is computed, default might be flush denorms to zero e.g. arm.
400 // This creates issues in result verification. Since spec allows the implementation to either flush or
401 // not flush denorms to zero, an implementation may choose not to flush i.e. return denorm result whereas
402 // reference result may be zero (flushed denorm). Hence we need to disable denorm flushing on host side
403 // where reference is being computed to make sure we get non-flushed reference result. If implementation
404 // returns flushed result, we correctly take care of that in verification code.
405
406 FPU_mode_type oldMode;
407 DisableFTZ(&oldMode);
408
409 int ret = runTestHarness( argCount, argList, test_num, test_list, true, false, 0 );
410
411 // Restore FP state before leaving
412 RestoreFPState(&oldMode);
413
414 free(argList);
415 return ret;
416 }
417
printUsage(const char * execName)418 static void printUsage( const char *execName )
419 {
420 const char *p = strrchr( execName, '/' );
421 if( p != NULL )
422 execName = p + 1;
423
424 log_info( "Usage: %s [options] [test_names]\n", execName );
425 log_info( "Options:\n" );
426 log_info( "\n" );
427 log_info( "\tThe following flags specify what kinds of operations to test. They can be combined; if none are specified, all are tested:\n" );
428 log_info( "\t\tread - Tests reading from an image\n" );
429 log_info( "\t\twrite - Tests writing to an image (can be specified with read to run both; default is both)\n" );
430 log_info( "\n" );
431 log_info( "\tThe following flags specify the types to test. They can be combined; if none are specified, all are tested:\n" );
432 log_info( "\t\tint - Test integer I/O (read_imagei, write_imagei)\n" );
433 log_info( "\t\tuint - Test unsigned integer I/O (read_imageui, write_imageui)\n" );
434 log_info( "\t\tfloat - Test float I/O (read_imagef, write_imagef)\n" );
435 log_info( "\n" );
436 log_info( "\tCL_FILTER_LINEAR - Only tests formats with CL_FILTER_LINEAR filtering\n" );
437 log_info( "\tCL_FILTER_NEAREST - Only tests formats with CL_FILTER_NEAREST filtering\n" );
438 log_info( "\n" );
439 log_info( "\tNORMALIZED - Only tests formats with NORMALIZED coordinates\n" );
440 log_info( "\tUNNORMALIZED - Only tests formats with UNNORMALIZED coordinates\n" );
441 log_info( "\n" );
442 log_info( "\tCL_ADDRESS_CLAMP - Only tests formats with CL_ADDRESS_CLAMP addressing\n" );
443 log_info( "\tCL_ADDRESS_CLAMP_TO_EDGE - Only tests formats with CL_ADDRESS_CLAMP_TO_EDGE addressing\n" );
444 log_info( "\tCL_ADDRESS_REPEAT - Only tests formats with CL_ADDRESS_REPEAT addressing\n" );
445 log_info( "\tCL_ADDRESS_MIRRORED_REPEAT - Only tests formats with CL_ADDRESS_MIRRORED_REPEAT addressing\n" );
446 log_info( "\n" );
447 log_info( "You may also use appropriate CL_ channel type and ordering constants.\n" );
448 log_info( "\n" );
449 log_info( "\tlocal_samplers - Use samplers declared in the kernel functions instead of passed in as arguments\n" );
450 log_info( "\n" );
451 log_info( "\tThe following specify to use the specific flag to allocate images to use in the tests:\n" );
452 log_info( "\t\tCL_MEM_COPY_HOST_PTR\n" );
453 log_info( "\t\tCL_MEM_USE_HOST_PTR (default)\n" );
454 log_info( "\t\tCL_MEM_ALLOC_HOST_PTR\n" );
455 log_info( "\t\tNO_HOST_PTR - Specifies to use none of the above flags\n" );
456 log_info( "\n" );
457 log_info( "\tThe following modify the types of images tested:\n" );
458 log_info( "\t\tsmall_images - Runs every format through a loop of widths 1-13 and heights 1-9, instead of random sizes\n" );
459 log_info( "\t\tmax_images - Runs every format through a set of size combinations with the max values, max values - 1, and max values / 128\n" );
460 log_info( "\t\trounding - Runs every format through a single image filled with every possible value for that image format, to verify rounding works properly\n" );
461 log_info( "\n" );
462 log_info( "\tno_offsets - Disables offsets when testing reads (can be good for diagnosing address repeating/clamping problems)\n" );
463 log_info( "\tdebug_trace - Enables additional debug info logging\n" );
464 log_info( "\textra_validate - Enables additional validation failure debug information\n" );
465 log_info( "\tuse_pitches - Enables row and slice pitches\n" );
466 log_info( "\ttest_mipmaps - Enables mipmapped images\n");
467 log_info( "\n" );
468 log_info( "Test names:\n" );
469 for( int i = 0; i < test_num; i++ )
470 {
471 log_info( "\t%s\n", test_list[i].name );
472 }
473 }
474