• 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/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 &param, 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 &param, 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 &param, 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 &param)
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 &param)
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 &param)
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