1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // angle_test_instantiate.cpp: Adds support for filtering parameterized
8 // tests by platform, so we skip unsupported configs.
9
10 #include "test_utils/angle_test_instantiate.h"
11
12 #include <array>
13 #include <iostream>
14 #include <map>
15
16 #include "angle_gl.h"
17 #include "common/platform.h"
18 #include "common/system_utils.h"
19 #include "common/third_party/base/anglebase/no_destructor.h"
20 #include "gpu_info_util/SystemInfo.h"
21 #include "test_utils/angle_test_configs.h"
22 #include "util/EGLWindow.h"
23 #include "util/OSWindow.h"
24 #include "util/test_utils.h"
25
26 #if defined(ANGLE_PLATFORM_WINDOWS)
27 # include <VersionHelpers.h>
28 # include "util/windows/WGLWindow.h"
29 #endif // defined(ANGLE_PLATFORM_WINDOWS)
30
31 #if defined(ANGLE_PLATFORM_APPLE)
32 # include "test_utils/angle_test_instantiate_apple.h"
33 #endif
34
35 namespace angle
36 {
37 namespace
38 {
IsANGLEConfigSupported(const PlatformParameters & param,OSWindow * osWindow)39 bool IsANGLEConfigSupported(const PlatformParameters ¶m, OSWindow *osWindow)
40 {
41 std::unique_ptr<angle::Library> eglLibrary;
42
43 #if defined(ANGLE_USE_UTIL_LOADER)
44 eglLibrary.reset(
45 angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ApplicationDir));
46 #endif
47
48 EGLWindow *eglWindow = EGLWindow::New(param.majorVersion, param.minorVersion);
49 ConfigParameters configParams;
50 bool result =
51 eglWindow->initializeGL(osWindow, eglLibrary.get(), param.eglParameters, configParams);
52 eglWindow->destroyGL();
53 EGLWindow::Delete(&eglWindow);
54 return result;
55 }
56
IsWGLConfigSupported(const PlatformParameters & param,OSWindow * osWindow)57 bool IsWGLConfigSupported(const PlatformParameters ¶m, OSWindow *osWindow)
58 {
59 #if defined(ANGLE_PLATFORM_WINDOWS) && defined(ANGLE_USE_UTIL_LOADER)
60 std::unique_ptr<angle::Library> openglLibrary(
61 angle::OpenSharedLibrary("opengl32", angle::SearchType::SystemDir));
62
63 WGLWindow *wglWindow = WGLWindow::New(param.majorVersion, param.minorVersion);
64 ConfigParameters configParams;
65 bool result =
66 wglWindow->initializeGL(osWindow, openglLibrary.get(), param.eglParameters, configParams);
67 wglWindow->destroyGL();
68 WGLWindow::Delete(&wglWindow);
69 return result;
70 #else
71 return false;
72 #endif // defined(ANGLE_PLATFORM_WINDOWS) && defined(ANGLE_USE_UTIL_LOADER)
73 }
74
IsNativeConfigSupported(const PlatformParameters & param,OSWindow * osWindow)75 bool IsNativeConfigSupported(const PlatformParameters ¶m, OSWindow *osWindow)
76 {
77 // Not yet implemented.
78 return false;
79 }
80
IsAndroidDevice(const std::string & deviceName)81 bool IsAndroidDevice(const std::string &deviceName)
82 {
83 if (!IsAndroid())
84 {
85 return false;
86 }
87 SystemInfo *systemInfo = GetTestSystemInfo();
88 if (systemInfo->machineModelName == deviceName)
89 {
90 return true;
91 }
92 return false;
93 }
94
HasSystemVendorID(VendorID vendorID)95 bool HasSystemVendorID(VendorID vendorID)
96 {
97 SystemInfo *systemInfo = GetTestSystemInfo();
98 // Unfortunately sometimes GPU info collection can fail.
99 if (systemInfo->gpus.empty())
100 {
101 return false;
102 }
103 return systemInfo->gpus[systemInfo->activeGPUIndex].vendorId == vendorID;
104 }
105
106 using ParamAvailabilityCache = std::map<PlatformParameters, bool>;
107
GetAvailabilityCache()108 ParamAvailabilityCache &GetAvailabilityCache()
109 {
110 static angle::base::NoDestructor<std::unique_ptr<ParamAvailabilityCache>>
111 sParamAvailabilityCache(new ParamAvailabilityCache());
112 return **sParamAvailabilityCache;
113 }
114
115 constexpr size_t kMaxConfigNameLen = 100;
116 std::array<char, kMaxConfigNameLen> gSelectedConfig;
117 } // namespace
118
119 bool gSeparateProcessPerConfig = false;
120
IsConfigSelected()121 bool IsConfigSelected()
122 {
123 return gSelectedConfig[0] != 0;
124 }
125
GetTestSystemInfo()126 SystemInfo *GetTestSystemInfo()
127 {
128 static SystemInfo *sSystemInfo = nullptr;
129 if (sSystemInfo == nullptr)
130 {
131 sSystemInfo = new SystemInfo;
132 if (!GetSystemInfo(sSystemInfo))
133 {
134 std::cerr << "Warning: incomplete system info collection.\n";
135 }
136
137 // On dual-GPU Macs we want the active GPU to always appear to be the
138 // high-performance GPU for tests.
139 // We can call the generic GPU info collector which selects the
140 // non-Intel GPU as the active one on dual-GPU machines.
141 if (IsOSX())
142 {
143 GetDualGPUInfo(sSystemInfo);
144 }
145
146 // Print complete system info when available.
147 // Seems to trip up Android test expectation parsing.
148 // Also don't print info when a config is selected to prevent test spam.
149 if (!IsAndroid() && !IsConfigSelected())
150 {
151 PrintSystemInfo(*sSystemInfo);
152 }
153 }
154 return sSystemInfo;
155 }
156
IsAndroid()157 bool IsAndroid()
158 {
159 #if defined(ANGLE_PLATFORM_ANDROID)
160 return true;
161 #else
162 return false;
163 #endif
164 }
165
IsLinux()166 bool IsLinux()
167 {
168 #if defined(ANGLE_PLATFORM_LINUX)
169 return true;
170 #else
171 return false;
172 #endif
173 }
174
IsOSX()175 bool IsOSX()
176 {
177 #if defined(ANGLE_PLATFORM_APPLE)
178 return true;
179 #else
180 return false;
181 #endif
182 }
183
IsOzone()184 bool IsOzone()
185 {
186 #if defined(USE_OZONE)
187 return true;
188 #else
189 return false;
190 #endif
191 }
192
IsWindows()193 bool IsWindows()
194 {
195 #if defined(ANGLE_PLATFORM_WINDOWS)
196 return true;
197 #else
198 return false;
199 #endif
200 }
201
IsWindows7()202 bool IsWindows7()
203 {
204 #if defined(ANGLE_PLATFORM_WINDOWS)
205 return ::IsWindows7OrGreater() && !::IsWindows8OrGreater();
206 #else
207 return false;
208 #endif
209 }
210
IsFuchsia()211 bool IsFuchsia()
212 {
213 #if defined(ANGLE_PLATFORM_FUCHSIA)
214 return true;
215 #else
216 return false;
217 #endif
218 }
219
IsNexus5X()220 bool IsNexus5X()
221 {
222 return IsAndroidDevice("Nexus 5X");
223 }
224
IsNexus6P()225 bool IsNexus6P()
226 {
227 return IsAndroidDevice("Nexus 6P");
228 }
229
IsNexus9()230 bool IsNexus9()
231 {
232 return IsAndroidDevice("Nexus 9");
233 }
234
IsPixelXL()235 bool IsPixelXL()
236 {
237 return IsAndroidDevice("Pixel XL");
238 }
239
IsPixel2()240 bool IsPixel2()
241 {
242 return IsAndroidDevice("Pixel 2");
243 }
244
IsPixel2XL()245 bool IsPixel2XL()
246 {
247 return IsAndroidDevice("Pixel 2 XL");
248 }
249
IsNVIDIAShield()250 bool IsNVIDIAShield()
251 {
252 return IsAndroidDevice("SHIELD Android TV");
253 }
254
IsIntel()255 bool IsIntel()
256 {
257 return HasSystemVendorID(kVendorID_Intel);
258 }
259
IsAMD()260 bool IsAMD()
261 {
262 return HasSystemVendorID(kVendorID_AMD);
263 }
264
IsARM()265 bool IsARM()
266 {
267 return HasSystemVendorID(kVendorID_ARM);
268 }
269
IsNVIDIA()270 bool IsNVIDIA()
271 {
272 #if defined(ANGLE_PLATFORM_ANDROID)
273 // NVIDIA Shield cannot detect vendor ID (http://anglebug.com/3541)
274 if (IsNVIDIAShield())
275 {
276 return true;
277 }
278 #endif
279 return HasSystemVendorID(kVendorID_NVIDIA);
280 }
281
IsARM64()282 bool IsARM64()
283 {
284 #if defined(_M_ARM64)
285 return true;
286 #else
287 return false;
288 #endif
289 }
290
IsConfigWhitelisted(const SystemInfo & systemInfo,const PlatformParameters & param)291 bool IsConfigWhitelisted(const SystemInfo &systemInfo, const PlatformParameters ¶m)
292 {
293 VendorID vendorID =
294 systemInfo.gpus.empty() ? 0 : systemInfo.gpus[systemInfo.activeGPUIndex].vendorId;
295
296 // We support the default and null back-ends on every platform.
297 if (param.driver == GLESDriverType::AngleEGL)
298 {
299 if (param.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
300 return true;
301 if (param.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE)
302 return true;
303 }
304
305 if (IsWindows())
306 {
307 switch (param.driver)
308 {
309 case GLESDriverType::AngleEGL:
310 switch (param.getRenderer())
311 {
312 case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
313 case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
314 case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
315 return true;
316 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
317 if (IsARM64())
318 {
319 return param.getDeviceType() ==
320 EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE;
321 }
322 return true;
323 case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
324 // ES 3.1+ back-end is not supported properly.
325 if (param.eglParameters.majorVersion == 3 &&
326 param.eglParameters.minorVersion > 0)
327 {
328 return false;
329 }
330
331 // Win ES emulation is currently only supported on NVIDIA.
332 return IsNVIDIA(vendorID);
333 default:
334 return false;
335 }
336 case GLESDriverType::SystemWGL:
337 // AMD does not support the ES compatibility extensions.
338 return !IsAMD(vendorID);
339 default:
340 return false;
341 }
342 }
343
344 #if defined(ANGLE_PLATFORM_APPLE)
345 if (IsOSX())
346 {
347 // We do not support non-ANGLE bindings on OSX.
348 if (param.driver != GLESDriverType::AngleEGL)
349 {
350 return false;
351 }
352
353 switch (param.getRenderer())
354 {
355 case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
356 // ES 3.1+ back-end is not supported properly.
357 if (param.majorVersion == 3 && param.minorVersion > 0)
358 {
359 return false;
360 }
361 return true;
362 case EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE:
363 if (!IsMetalRendererAvailable() || IsIntel(vendorID))
364 {
365 // TODO(hqle): Intel metal tests seem to have problems. Disable for now.
366 // http://anglebug.com/4133
367 return false;
368 }
369 return true;
370 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
371 // OSX does not support native vulkan
372 return param.getDeviceType() == EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE;
373 default:
374 return false;
375 }
376 }
377 #endif // #if defined(ANGLE_PLATFORM_APPLE)
378
379 if (IsFuchsia())
380 {
381 // We do not support non-ANGLE bindings on Fuchsia.
382 if (param.driver != GLESDriverType::AngleEGL)
383 {
384 return false;
385 }
386
387 // ES 3 configs do not work properly on Fuchsia ARM.
388 // TODO(anglebug.com/4352): Investigate missing features.
389 if (param.majorVersion > 2 && IsARM())
390 return false;
391
392 // Loading swiftshader is not brought up on Fuchsia.
393 // TODO(anglebug.com/4353): Support loading swiftshader vulkan ICD.
394 if (param.getDeviceType() == EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE)
395 return false;
396
397 // Currently we only support the Vulkan back-end on Fuchsia.
398 return (param.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE);
399 }
400
401 if (IsOzone())
402 {
403 // We do not support non-ANGLE bindings on Ozone.
404 if (param.driver != GLESDriverType::AngleEGL)
405 return false;
406
407 // ES 3 configs do not work properly on Ozone.
408 if (param.majorVersion > 2)
409 return false;
410
411 // Currently we only support the GLES back-end on Ozone.
412 return (param.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE);
413 }
414
415 if (IsLinux())
416 {
417 // We do not support non-ANGLE bindings on Linux.
418 if (param.driver != GLESDriverType::AngleEGL)
419 {
420 return false;
421 }
422
423 // Currently we support the OpenGL and Vulkan back-ends on Linux.
424 switch (param.getRenderer())
425 {
426 case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
427 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
428 // Note that system info collection depends on Vulkan support.
429 return true;
430 default:
431 return false;
432 }
433 }
434
435 if (IsAndroid())
436 {
437 // We do not support non-ANGLE bindings on Android.
438 if (param.driver != GLESDriverType::AngleEGL)
439 {
440 return false;
441 }
442
443 // Nexus Android devices don't support backing 3.2 contexts
444 if (param.eglParameters.majorVersion == 3 && param.eglParameters.minorVersion == 2)
445 {
446 if (IsNexus5X() || IsNexus6P())
447 {
448 return false;
449 }
450 }
451
452 // TODO: http://crbug.com/swiftshader/145
453 // Swiftshader does not currently have all the robustness features
454 // we need for ANGLE. In particular, it is unable to detect and recover
455 // from infinitely looping shaders. That bug is the tracker for fixing
456 // that and when resolved we can remove the following code.
457 // This test will disable tests marked with the config WithRobustness
458 // when run with the swiftshader Vulkan driver and on Android.
459 DeviceID deviceID =
460 systemInfo.gpus.empty() ? 0 : systemInfo.gpus[systemInfo.activeGPUIndex].deviceId;
461 if ((param.isSwiftshader() || (IsGoogle(vendorID) && deviceID == kDeviceID_Swiftshader)) &&
462 param.eglParameters.robustness)
463 {
464 return false;
465 }
466
467 // Currently we support the GLES and Vulkan back-ends on Android.
468 switch (param.getRenderer())
469 {
470 case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
471 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
472 // Swiftshader's vulkan frontend doesn't build on Android.
473 if (param.getDeviceType() == EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE)
474 {
475 return false;
476 }
477 return true;
478 default:
479 return false;
480 }
481 }
482
483 // Unknown platform.
484 return false;
485 }
486
IsConfigSupported(const PlatformParameters & param)487 bool IsConfigSupported(const PlatformParameters ¶m)
488 {
489 OSWindow *osWindow = OSWindow::New();
490 bool result = false;
491 if (osWindow->initialize("CONFIG_TESTER", 1, 1))
492 {
493 switch (param.driver)
494 {
495 case GLESDriverType::AngleEGL:
496 result = IsANGLEConfigSupported(param, osWindow);
497 break;
498 case GLESDriverType::SystemEGL:
499 result = IsNativeConfigSupported(param, osWindow);
500 break;
501 case GLESDriverType::SystemWGL:
502 result = IsWGLConfigSupported(param, osWindow);
503 break;
504 }
505
506 osWindow->destroy();
507 }
508
509 OSWindow::Delete(&osWindow);
510 return result;
511 }
512
IsPlatformAvailable(const PlatformParameters & param)513 bool IsPlatformAvailable(const PlatformParameters ¶m)
514 {
515 // Disable "null" device when not on ANGLE or in D3D9.
516 if (param.getDeviceType() == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE)
517 {
518 if (param.driver != GLESDriverType::AngleEGL)
519 return false;
520 if (param.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE)
521 return false;
522 }
523
524 switch (param.getRenderer())
525 {
526 case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
527 break;
528
529 case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
530 #if !defined(ANGLE_ENABLE_D3D9)
531 return false;
532 #else
533 break;
534 #endif
535
536 case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
537 #if !defined(ANGLE_ENABLE_D3D11)
538 return false;
539 #else
540 break;
541 #endif
542
543 case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
544 case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
545 #if !defined(ANGLE_ENABLE_OPENGL)
546 return false;
547 #else
548 break;
549 #endif
550
551 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
552 #if !defined(ANGLE_ENABLE_VULKAN)
553 return false;
554 #else
555 break;
556 #endif
557
558 case EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE:
559 #if !defined(ANGLE_ENABLE_METAL)
560 return false;
561 #else
562 break;
563 #endif
564
565 case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE:
566 #ifndef ANGLE_ENABLE_NULL
567 return false;
568 #endif
569 break;
570
571 default:
572 std::cout << "Unknown test platform: " << param << std::endl;
573 return false;
574 }
575
576 bool result = false;
577
578 auto iter = GetAvailabilityCache().find(param);
579 if (iter != GetAvailabilityCache().end())
580 {
581 result = iter->second;
582 }
583 else
584 {
585 if (IsConfigSelected())
586 {
587 std::stringstream strstr;
588 strstr << param;
589 if (strstr.str() == std::string(gSelectedConfig.data()))
590 {
591 result = true;
592 }
593 }
594 else
595 {
596 const SystemInfo *systemInfo = GetTestSystemInfo();
597
598 if (systemInfo)
599 {
600 result = IsConfigWhitelisted(*systemInfo, param);
601 }
602 else
603 {
604 result = IsConfigSupported(param);
605 }
606 }
607
608 GetAvailabilityCache()[param] = result;
609
610 // Enable this unconditionally to print available platforms.
611 if (IsConfigSelected())
612 {
613 if (result)
614 {
615 std::cout << "Test Config: " << param << "\n";
616 }
617 }
618 else if (!result)
619 {
620 std::cout << "Skipping tests using configuration " << param
621 << " because it is not available.\n";
622 }
623 }
624
625 // Disable all tests in the parent process when running child processes.
626 if (gSeparateProcessPerConfig)
627 {
628 return false;
629 }
630 return result;
631 }
632
GetAvailableTestPlatformNames()633 std::vector<std::string> GetAvailableTestPlatformNames()
634 {
635 std::vector<std::string> platformNames;
636
637 for (const auto &iter : GetAvailabilityCache())
638 {
639 if (iter.second)
640 {
641 std::stringstream strstr;
642 strstr << iter.first;
643 platformNames.push_back(strstr.str());
644 }
645 }
646
647 // Keep the list sorted.
648 std::sort(platformNames.begin(), platformNames.end());
649
650 return platformNames;
651 }
652
SetSelectedConfig(const char * selectedConfig)653 void SetSelectedConfig(const char *selectedConfig)
654 {
655 gSelectedConfig.fill(0);
656 strncpy(gSelectedConfig.data(), selectedConfig, kMaxConfigNameLen - 1);
657 }
658 } // namespace angle
659