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