• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &param, 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 &param, 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 &param, 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 &param)
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 &param)
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 &param)
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