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 <iostream>
13 #include <map>
14
15 #include "angle_gl.h"
16 #include "common/platform.h"
17 #include "gpu_info_util/SystemInfo.h"
18 #include "test_utils/angle_test_configs.h"
19 #include "util/EGLWindow.h"
20 #include "util/OSWindow.h"
21 #include "util/system_utils.h"
22
23 #if defined(ANGLE_PLATFORM_WINDOWS)
24 # include "util/windows/WGLWindow.h"
25 #endif // defined(ANGLE_PLATFORM_WINDOWS)
26
27 namespace angle
28 {
29 namespace
30 {
IsANGLEConfigSupported(const PlatformParameters & param,OSWindow * osWindow)31 bool IsANGLEConfigSupported(const PlatformParameters ¶m, OSWindow *osWindow)
32 {
33 std::unique_ptr<angle::Library> eglLibrary;
34
35 #if defined(ANGLE_USE_UTIL_LOADER)
36 eglLibrary.reset(
37 angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ApplicationDir));
38 #endif
39
40 EGLWindow *eglWindow = EGLWindow::New(param.majorVersion, param.minorVersion);
41 ConfigParameters configParams;
42 bool result =
43 eglWindow->initializeGL(osWindow, eglLibrary.get(), param.eglParameters, configParams);
44 eglWindow->destroyGL();
45 EGLWindow::Delete(&eglWindow);
46 return result;
47 }
48
IsWGLConfigSupported(const PlatformParameters & param,OSWindow * osWindow)49 bool IsWGLConfigSupported(const PlatformParameters ¶m, OSWindow *osWindow)
50 {
51 #if defined(ANGLE_PLATFORM_WINDOWS) && defined(ANGLE_USE_UTIL_LOADER)
52 std::unique_ptr<angle::Library> openglLibrary(
53 angle::OpenSharedLibrary("opengl32", angle::SearchType::SystemDir));
54
55 WGLWindow *wglWindow = WGLWindow::New(param.majorVersion, param.minorVersion);
56 ConfigParameters configParams;
57 bool result =
58 wglWindow->initializeGL(osWindow, openglLibrary.get(), param.eglParameters, configParams);
59 wglWindow->destroyGL();
60 WGLWindow::Delete(&wglWindow);
61 return result;
62 #else
63 return false;
64 #endif // defined(ANGLE_PLATFORM_WINDOWS) && defined(ANGLE_USE_UTIL_LOADER)
65 }
66
IsNativeConfigSupported(const PlatformParameters & param,OSWindow * osWindow)67 bool IsNativeConfigSupported(const PlatformParameters ¶m, OSWindow *osWindow)
68 {
69 // Not yet implemented.
70 return false;
71 }
72
73 std::map<PlatformParameters, bool> gParamAvailabilityCache;
74
IsAndroidDevice(const std::string & deviceName)75 bool IsAndroidDevice(const std::string &deviceName)
76 {
77 if (!IsAndroid())
78 {
79 return false;
80 }
81 SystemInfo *systemInfo = GetTestSystemInfo();
82 if (systemInfo->machineModelName == deviceName)
83 {
84 return true;
85 }
86 return false;
87 }
88
HasSystemVendorID(VendorID vendorID)89 bool HasSystemVendorID(VendorID vendorID)
90 {
91 SystemInfo *systemInfo = GetTestSystemInfo();
92 // Unfortunately sometimes GPU info collection can fail.
93 if (systemInfo->activeGPUIndex < 0 || systemInfo->gpus.empty())
94 {
95 return false;
96 }
97 return systemInfo->gpus[systemInfo->activeGPUIndex].vendorId == vendorID;
98 }
99 } // namespace
100
101 std::string gSelectedConfig;
102 bool gSeparateProcessPerConfig = false;
103
GetTestSystemInfo()104 SystemInfo *GetTestSystemInfo()
105 {
106 static SystemInfo *sSystemInfo = nullptr;
107 if (sSystemInfo == nullptr)
108 {
109 sSystemInfo = new SystemInfo;
110 if (!GetSystemInfo(sSystemInfo))
111 {
112 std::cerr << "Warning: incomplete system info collection.\n";
113 }
114
115 // Print complete system info when available.
116 // Seems to trip up Android test expectation parsing.
117 // Also don't print info when a config is selected to prevent test spam.
118 if (!IsAndroid() && gSelectedConfig.empty())
119 {
120 PrintSystemInfo(*sSystemInfo);
121 }
122 }
123 return sSystemInfo;
124 }
125
IsAndroid()126 bool IsAndroid()
127 {
128 #if defined(ANGLE_PLATFORM_ANDROID)
129 return true;
130 #else
131 return false;
132 #endif
133 }
134
IsLinux()135 bool IsLinux()
136 {
137 #if defined(ANGLE_PLATFORM_LINUX)
138 return true;
139 #else
140 return false;
141 #endif
142 }
143
IsOSX()144 bool IsOSX()
145 {
146 #if defined(ANGLE_PLATFORM_APPLE)
147 return true;
148 #else
149 return false;
150 #endif
151 }
152
IsOzone()153 bool IsOzone()
154 {
155 #if defined(USE_OZONE)
156 return true;
157 #else
158 return false;
159 #endif
160 }
161
IsWindows()162 bool IsWindows()
163 {
164 #if defined(ANGLE_PLATFORM_WINDOWS)
165 return true;
166 #else
167 return false;
168 #endif
169 }
170
IsFuchsia()171 bool IsFuchsia()
172 {
173 #if defined(ANGLE_PLATFORM_FUCHSIA)
174 return true;
175 #else
176 return false;
177 #endif
178 }
179
IsNexus5X()180 bool IsNexus5X()
181 {
182 return IsAndroidDevice("Nexus 5X");
183 }
184
IsNexus6P()185 bool IsNexus6P()
186 {
187 return IsAndroidDevice("Nexus 6P");
188 }
189
IsNexus9()190 bool IsNexus9()
191 {
192 return IsAndroidDevice("Nexus 9");
193 }
194
IsPixelXL()195 bool IsPixelXL()
196 {
197 return IsAndroidDevice("Pixel XL");
198 }
199
IsPixel2()200 bool IsPixel2()
201 {
202 return IsAndroidDevice("Pixel 2");
203 }
204
IsNVIDIAShield()205 bool IsNVIDIAShield()
206 {
207 return IsAndroidDevice("SHIELD Android TV");
208 }
209
IsIntel()210 bool IsIntel()
211 {
212 return HasSystemVendorID(kVendorID_Intel);
213 }
214
IsAMD()215 bool IsAMD()
216 {
217 return HasSystemVendorID(kVendorID_AMD);
218 }
219
IsNVIDIA()220 bool IsNVIDIA()
221 {
222 #if defined(ANGLE_PLATFORM_ANDROID)
223 // NVIDIA Shield cannot detect vendor ID (http://anglebug.com/3541)
224 if (IsNVIDIAShield())
225 {
226 return true;
227 }
228 #endif
229 return HasSystemVendorID(kVendorID_NVIDIA);
230 }
231
IsConfigWhitelisted(const SystemInfo & systemInfo,const PlatformParameters & param)232 bool IsConfigWhitelisted(const SystemInfo &systemInfo, const PlatformParameters ¶m)
233 {
234 VendorID vendorID = systemInfo.gpus[systemInfo.activeGPUIndex].vendorId;
235
236 // We support the default and null back-ends on every platform.
237 if (param.driver == GLESDriverType::AngleEGL)
238 {
239 if (param.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
240 return true;
241 if (param.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE)
242 return true;
243 }
244
245 if (IsWindows())
246 {
247 switch (param.driver)
248 {
249 case GLESDriverType::AngleEGL:
250 switch (param.getRenderer())
251 {
252 case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
253 case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
254 case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
255 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
256 return true;
257 case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
258 // ES 3.1+ back-end is not supported properly.
259 if (param.eglParameters.majorVersion == 3 &&
260 param.eglParameters.minorVersion > 0)
261 {
262 return false;
263 }
264
265 // Win ES emulation is currently only supported on NVIDIA.
266 return IsNVIDIA(vendorID);
267 default:
268 return false;
269 }
270 case GLESDriverType::SystemWGL:
271 // AMD does not support the ES compatibility extensions.
272 return !IsAMD(vendorID);
273 default:
274 return false;
275 }
276 }
277
278 if (IsOSX())
279 {
280 // We do not support non-ANGLE bindings on OSX.
281 if (param.driver != GLESDriverType::AngleEGL)
282 {
283 return false;
284 }
285
286 // OSX does not support ES 3.1 features.
287 if (param.majorVersion == 3 && param.minorVersion > 0)
288 {
289 return false;
290 }
291
292 // Currently we only support the OpenGL back-end on OSX.
293 return (param.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE);
294 }
295
296 if (IsFuchsia())
297 {
298 // We do not support non-ANGLE bindings on Fuchsia.
299 if (param.driver != GLESDriverType::AngleEGL)
300 {
301 return false;
302 }
303
304 // Currently we only support the Vulkan back-end on Fuchsia.
305 return (param.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE);
306 }
307
308 if (IsOzone())
309 {
310 // We do not support non-ANGLE bindings on Ozone.
311 if (param.driver != GLESDriverType::AngleEGL)
312 return false;
313
314 // ES 3 configs do not work properly on Ozone.
315 if (param.majorVersion > 2)
316 return false;
317
318 // Currently we only support the GLES back-end on Ozone.
319 return (param.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE);
320 }
321
322 if (IsLinux())
323 {
324 // We do not support non-ANGLE bindings on Linux.
325 if (param.driver != GLESDriverType::AngleEGL)
326 {
327 return false;
328 }
329
330 // Currently we support the OpenGL and Vulkan back-ends on Linux.
331 switch (param.getRenderer())
332 {
333 case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
334 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
335 // Note that system info collection depends on Vulkan support.
336 return true;
337 default:
338 return false;
339 }
340 }
341
342 if (IsAndroid())
343 {
344 // We do not support non-ANGLE bindings on Android.
345 if (param.driver != GLESDriverType::AngleEGL)
346 {
347 return false;
348 }
349
350 // Nexus Android devices don't support backing 3.2 contexts
351 if (param.eglParameters.majorVersion == 3 && param.eglParameters.minorVersion == 2)
352 {
353 if (IsNexus5X() || IsNexus6P())
354 {
355 return false;
356 }
357 }
358
359 // Currently we support the GLES and Vulkan back-ends on Android.
360 switch (param.getRenderer())
361 {
362 case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
363 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
364 return true;
365 default:
366 return false;
367 }
368 }
369
370 // Unknown platform.
371 return false;
372 }
373
IsConfigSupported(const PlatformParameters & param)374 bool IsConfigSupported(const PlatformParameters ¶m)
375 {
376 OSWindow *osWindow = OSWindow::New();
377 bool result = false;
378 if (osWindow->initialize("CONFIG_TESTER", 1, 1))
379 {
380 switch (param.driver)
381 {
382 case GLESDriverType::AngleEGL:
383 result = IsANGLEConfigSupported(param, osWindow);
384 break;
385 case GLESDriverType::SystemEGL:
386 result = IsNativeConfigSupported(param, osWindow);
387 break;
388 case GLESDriverType::SystemWGL:
389 result = IsWGLConfigSupported(param, osWindow);
390 break;
391 }
392
393 osWindow->destroy();
394 }
395
396 OSWindow::Delete(&osWindow);
397 return result;
398 }
399
IsPlatformAvailable(const PlatformParameters & param)400 bool IsPlatformAvailable(const PlatformParameters ¶m)
401 {
402 switch (param.getRenderer())
403 {
404 case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
405 break;
406
407 case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
408 #if !defined(ANGLE_ENABLE_D3D9)
409 return false;
410 #else
411 break;
412 #endif
413
414 case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
415 #if !defined(ANGLE_ENABLE_D3D11)
416 return false;
417 #else
418 break;
419 #endif
420
421 case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
422 case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
423 #if !defined(ANGLE_ENABLE_OPENGL)
424 return false;
425 #else
426 break;
427 #endif
428
429 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
430 #if !defined(ANGLE_ENABLE_VULKAN)
431 return false;
432 #else
433 break;
434 #endif
435
436 case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE:
437 #ifndef ANGLE_ENABLE_NULL
438 return false;
439 #endif
440 break;
441
442 default:
443 std::cout << "Unknown test platform: " << param << std::endl;
444 return false;
445 }
446
447 bool result = false;
448
449 auto iter = gParamAvailabilityCache.find(param);
450 if (iter != gParamAvailabilityCache.end())
451 {
452 result = iter->second;
453 }
454 else
455 {
456 if (!gSelectedConfig.empty())
457 {
458 std::stringstream strstr;
459 strstr << param;
460 if (strstr.str() == gSelectedConfig)
461 {
462 result = true;
463 }
464 }
465 else
466 {
467 const SystemInfo *systemInfo = GetTestSystemInfo();
468
469 if (systemInfo)
470 {
471 result = IsConfigWhitelisted(*systemInfo, param);
472 }
473 else
474 {
475 result = IsConfigSupported(param);
476 }
477 }
478
479 gParamAvailabilityCache[param] = result;
480
481 // Enable this unconditionally to print available platforms.
482 if (!gSelectedConfig.empty())
483 {
484 if (result)
485 {
486 std::cout << "Test Config: " << param << "\n";
487 }
488 }
489 else if (!result)
490 {
491 std::cout << "Skipping tests using configuration " << param
492 << " because it is not available.\n";
493 }
494 }
495
496 // Disable all tests in the parent process when running child processes.
497 if (gSeparateProcessPerConfig)
498 {
499 return false;
500 }
501 return result;
502 }
503
GetAvailableTestPlatformNames()504 std::vector<std::string> GetAvailableTestPlatformNames()
505 {
506 std::vector<std::string> platformNames;
507
508 for (const auto &iter : gParamAvailabilityCache)
509 {
510 if (iter.second)
511 {
512 std::stringstream strstr;
513 strstr << iter.first;
514 platformNames.push_back(strstr.str());
515 }
516 }
517
518 // Keep the list sorted.
519 std::sort(platformNames.begin(), platformNames.end());
520
521 return platformNames;
522 }
523 } // namespace angle
524