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