1 //
2 // Copyright 2002 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 // Display.cpp: Implements the egl::Display class, representing the abstract
8 // display on which graphics are drawn. Implements EGLDisplay.
9 // [EGL 1.4] section 2.1.2 page 3.
10
11 #include "libANGLE/Display.h"
12
13 #include <algorithm>
14 #include <iterator>
15 #include <map>
16 #include <sstream>
17 #include <vector>
18
19 #include <EGL/eglext.h>
20 #include <platform/Platform.h>
21
22 #include "anglebase/no_destructor.h"
23 #include "common/android_util.h"
24 #include "common/debug.h"
25 #include "common/mathutil.h"
26 #include "common/platform.h"
27 #include "common/string_utils.h"
28 #include "common/system_utils.h"
29 #include "common/tls.h"
30 #include "common/utilities.h"
31 #include "gpu_info_util/SystemInfo.h"
32 #include "libANGLE/Context.h"
33 #include "libANGLE/Device.h"
34 #include "libANGLE/EGLSync.h"
35 #include "libANGLE/Image.h"
36 #include "libANGLE/ResourceManager.h"
37 #include "libANGLE/Stream.h"
38 #include "libANGLE/Surface.h"
39 #include "libANGLE/Thread.h"
40 #include "libANGLE/capture/FrameCapture.h"
41 #include "libANGLE/histogram_macros.h"
42 #include "libANGLE/renderer/DeviceImpl.h"
43 #include "libANGLE/renderer/DisplayImpl.h"
44 #include "libANGLE/renderer/ImageImpl.h"
45 #include "libANGLE/trace.h"
46
47 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
48 # include <versionhelpers.h>
49
50 # include "libANGLE/renderer/d3d/DisplayD3D.h"
51 #endif
52
53 #if defined(ANGLE_ENABLE_OPENGL)
54 # if defined(ANGLE_PLATFORM_WINDOWS)
55 # include "libANGLE/renderer/gl/wgl/DisplayWGL.h"
56 # elif defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_IOS)
57 # include "libANGLE/renderer/gl/apple/DisplayApple_api.h"
58 # elif defined(ANGLE_PLATFORM_LINUX)
59 # include "libANGLE/renderer/gl/egl/DisplayEGL.h"
60 # if defined(ANGLE_USE_GBM)
61 # include "libANGLE/renderer/gl/egl/gbm/DisplayGbm.h"
62 # endif
63 # if defined(ANGLE_USE_X11)
64 # include "libANGLE/renderer/gl/glx/DisplayGLX.h"
65 # endif
66 # elif defined(ANGLE_PLATFORM_ANDROID)
67 # include "libANGLE/renderer/gl/egl/android/DisplayAndroid.h"
68 # else
69 # error Unsupported OpenGL platform.
70 # endif
71 #endif
72
73 #if defined(ANGLE_ENABLE_NULL)
74 # include "libANGLE/renderer/null/DisplayNULL.h"
75 #endif // defined(ANGLE_ENABLE_NULL)
76
77 #if defined(ANGLE_ENABLE_VULKAN)
78 # include "libANGLE/renderer/vulkan/DisplayVk_api.h"
79 #endif // defined(ANGLE_ENABLE_VULKAN)
80
81 #if defined(ANGLE_ENABLE_METAL)
82 # include "libANGLE/renderer/metal/DisplayMtl_api.h"
83 #endif // defined(ANGLE_ENABLE_METAL)
84
85 namespace egl
86 {
87
88 namespace
89 {
90
91 constexpr angle::SubjectIndex kGPUSwitchedSubjectIndex = 0;
92
93 typedef std::map<EGLNativeWindowType, Surface *> WindowSurfaceMap;
94 // Get a map of all EGL window surfaces to validate that no window has more than one EGL surface
95 // associated with it.
GetWindowSurfaces()96 static WindowSurfaceMap *GetWindowSurfaces()
97 {
98 static angle::base::NoDestructor<WindowSurfaceMap> windowSurfaces;
99 return windowSurfaces.get();
100 }
101
102 typedef std::map<EGLNativeDisplayType, Display *> ANGLEPlatformDisplayMap;
GetANGLEPlatformDisplayMap()103 static ANGLEPlatformDisplayMap *GetANGLEPlatformDisplayMap()
104 {
105 static angle::base::NoDestructor<ANGLEPlatformDisplayMap> displays;
106 return displays.get();
107 }
108
109 typedef std::map<Device *, Display *> DevicePlatformDisplayMap;
GetDevicePlatformDisplayMap()110 static DevicePlatformDisplayMap *GetDevicePlatformDisplayMap()
111 {
112 static angle::base::NoDestructor<DevicePlatformDisplayMap> displays;
113 return displays.get();
114 }
115
CreateDisplayFromDevice(Device * eglDevice,const DisplayState & state)116 rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice, const DisplayState &state)
117 {
118 rx::DisplayImpl *impl = nullptr;
119
120 switch (eglDevice->getType())
121 {
122 #if defined(ANGLE_ENABLE_D3D11)
123 case EGL_D3D11_DEVICE_ANGLE:
124 impl = new rx::DisplayD3D(state);
125 break;
126 #endif
127 #if defined(ANGLE_ENABLE_D3D9)
128 case EGL_D3D9_DEVICE_ANGLE:
129 // Currently the only way to get EGLDeviceEXT representing a D3D9 device
130 // is to retrieve one from an already-existing EGLDisplay.
131 // When eglGetPlatformDisplayEXT is called with a D3D9 EGLDeviceEXT,
132 // the already-existing display should be returned.
133 // Therefore this codepath to create a new display from the device
134 // should never be hit.
135 UNREACHABLE();
136 break;
137 #endif
138 default:
139 UNREACHABLE();
140 break;
141 }
142
143 ASSERT(impl != nullptr);
144 return impl;
145 }
146
147 // On platforms with support for multiple back-ends, allow an environment variable to control
148 // the default. This is useful to run angle with benchmarks without having to modify the
149 // benchmark source. Possible values for this environment variable (ANGLE_DEFAULT_PLATFORM)
150 // are: vulkan, gl, d3d11, null.
GetDisplayTypeFromEnvironment()151 EGLAttrib GetDisplayTypeFromEnvironment()
152 {
153 std::string angleDefaultEnv = angle::GetEnvironmentVar("ANGLE_DEFAULT_PLATFORM");
154 angle::ToLower(&angleDefaultEnv);
155
156 #if defined(ANGLE_ENABLE_VULKAN)
157 if ((angleDefaultEnv == "vulkan") || (angleDefaultEnv == "vulkan-null") ||
158 (angleDefaultEnv == "swiftshader"))
159 {
160 return EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
161 }
162 #endif
163
164 #if defined(ANGLE_ENABLE_OPENGL)
165 if (angleDefaultEnv == "gl")
166 {
167 return EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
168 }
169 #endif
170
171 #if defined(ANGLE_ENABLE_D3D11)
172 if (angleDefaultEnv == "d3d11")
173 {
174 return EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
175 }
176 #endif
177
178 #if defined(ANGLE_ENABLE_METAL)
179 if (angleDefaultEnv == "metal")
180 {
181 return EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE;
182 }
183 #endif
184
185 #if defined(ANGLE_ENABLE_NULL)
186 if (angleDefaultEnv == "null")
187 {
188 return EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE;
189 }
190 #endif
191 #if defined(ANGLE_ENABLE_METAL)
192 if (angleDefaultEnv == "metal")
193 {
194 return EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE;
195 }
196
197 #endif
198 #if defined(ANGLE_ENABLE_D3D11)
199 return EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
200 #elif defined(ANGLE_ENABLE_D3D9)
201 return EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
202 #elif defined(ANGLE_ENABLE_VULKAN) && defined(ANGLE_PLATFORM_ANDROID)
203 return EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
204 #elif defined(ANGLE_ENABLE_OPENGL)
205 # if defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_USE_GBM)
206 return EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
207 # else
208 return EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
209 # endif
210 #elif defined(ANGLE_ENABLE_METAL)
211 return EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE;
212 #elif defined(ANGLE_ENABLE_VULKAN)
213 return EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
214 #elif defined(ANGLE_ENABLE_NULL)
215 return EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE;
216 #else
217 # error No default ANGLE platform type
218 #endif
219 }
220
GetDeviceTypeFromEnvironment()221 EGLAttrib GetDeviceTypeFromEnvironment()
222 {
223 std::string angleDefaultEnv = angle::GetEnvironmentVar("ANGLE_DEFAULT_PLATFORM");
224 angle::ToLower(&angleDefaultEnv);
225
226 #if defined(ANGLE_ENABLE_VULKAN)
227 if (angleDefaultEnv == "vulkan-null")
228 {
229 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE;
230 }
231 else if (angleDefaultEnv == "swiftshader")
232 {
233 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE;
234 }
235 #endif
236 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
237 }
238
GetPlatformTypeFromEnvironment()239 EGLAttrib GetPlatformTypeFromEnvironment()
240 {
241 #if defined(ANGLE_USE_OZONE)
242 return 0;
243 #elif defined(ANGLE_USE_X11)
244 return EGL_PLATFORM_X11_EXT;
245 #elif defined(ANGLE_USE_VULKAN_DISPLAY) && defined(ANGLE_VULKAN_DISPLAY_MODE_SIMPLE)
246 return EGL_PLATFORM_VULKAN_DISPLAY_MODE_SIMPLE_ANGLE;
247 #elif defined(ANGLE_USE_VULKAN_DISPLAY) && defined(ANGLE_VULKAN_DISPLAY_MODE_HEADLESS)
248 return EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE;
249 #else
250 return 0;
251 #endif // defined(ANGLE_USE_OZONE)
252 }
253
CreateDisplayFromAttribs(EGLAttrib displayType,EGLAttrib deviceType,EGLAttrib platformType,const DisplayState & state)254 rx::DisplayImpl *CreateDisplayFromAttribs(EGLAttrib displayType,
255 EGLAttrib deviceType,
256 EGLAttrib platformType,
257 const DisplayState &state)
258 {
259 ASSERT(displayType != EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
260 rx::DisplayImpl *impl = nullptr;
261
262 switch (displayType)
263 {
264 case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
265 UNREACHABLE();
266 #if !UNREACHABLE_IS_NORETURN
267 break;
268 #endif
269
270 case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
271 case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
272 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
273 impl = new rx::DisplayD3D(state);
274 break;
275 #else
276 // A D3D display was requested on a platform that doesn't support it
277 UNREACHABLE();
278 # if !UNREACHABLE_IS_NORETURN
279 break;
280 # endif
281 #endif
282
283 case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
284 #if defined(ANGLE_ENABLE_OPENGL)
285 # if defined(ANGLE_PLATFORM_WINDOWS)
286 impl = new rx::DisplayWGL(state);
287 break;
288
289 # elif defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_IOS)
290 impl = rx::CreateDisplayCGLOrEAGL(state);
291 break;
292
293 # elif defined(ANGLE_PLATFORM_LINUX)
294 # if defined(ANGLE_USE_GBM)
295 if (platformType == 0)
296 {
297 // If platformType is unknown, use DisplayGbm now. In the future, it should use
298 // DisplayEGL letting native EGL decide what display to use.
299 impl = new rx::DisplayGbm(state);
300 break;
301 }
302 # endif
303 if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE)
304 {
305 impl = new rx::DisplayEGL(state);
306 break;
307 }
308 # if defined(ANGLE_USE_X11)
309 if (platformType == EGL_PLATFORM_X11_EXT)
310 {
311 impl = new rx::DisplayGLX(state);
312 break;
313 }
314 # endif
315 break;
316
317 # elif defined(ANGLE_PLATFORM_ANDROID)
318 // No GL support on this platform, fail display creation.
319 impl = nullptr;
320 break;
321
322 # else
323 # error Unsupported OpenGL platform.
324 # endif
325 #else
326 // No display available
327 UNREACHABLE();
328 # if !UNREACHABLE_IS_NORETURN
329 break;
330 # endif
331
332 #endif // defined(ANGLE_ENABLE_OPENGL)
333
334 case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
335 #if defined(ANGLE_ENABLE_OPENGL)
336 # if defined(ANGLE_PLATFORM_WINDOWS)
337 impl = new rx::DisplayWGL(state);
338 # elif defined(ANGLE_PLATFORM_LINUX)
339 # if defined(ANGLE_USE_GBM)
340 if (platformType == 0)
341 {
342 // If platformType is unknown, use DisplayGbm now. In the future, it should use
343 // DisplayEGL letting native EGL decide what display to use.
344 impl = new rx::DisplayGbm(state);
345 break;
346 }
347 # endif
348 if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE)
349 {
350 impl = new rx::DisplayEGL(state);
351 break;
352 }
353 else
354 {
355 # if defined(ANGLE_USE_X11)
356 if (platformType == EGL_PLATFORM_X11_EXT)
357 {
358 impl = new rx::DisplayGLX(state);
359 break;
360 }
361 # endif
362 }
363 # elif defined(ANGLE_PLATFORM_ANDROID)
364 impl = new rx::DisplayAndroid(state);
365 # else
366 // No GLES support on this platform, fail display creation.
367 impl = nullptr;
368 # endif
369 #endif // defined(ANGLE_ENABLE_OPENGL)
370 break;
371
372 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
373 #if defined(ANGLE_ENABLE_VULKAN)
374 # if defined(ANGLE_USE_VULKAN_NULL_DISPLAY)
375 if (rx::IsVulkanNullDisplayAvailable())
376 {
377 impl = rx::CreateVulkanNullDisplay(state);
378 }
379 break;
380 # elif defined(ANGLE_PLATFORM_WINDOWS)
381 if (rx::IsVulkanWin32DisplayAvailable())
382 {
383 impl = rx::CreateVulkanWin32Display(state);
384 }
385 break;
386 # elif defined(ANGLE_PLATFORM_LINUX)
387 # if defined(ANGLE_USE_X11)
388 if (platformType == EGL_PLATFORM_X11_EXT && rx::IsVulkanXcbDisplayAvailable())
389 {
390 impl = rx::CreateVulkanXcbDisplay(state);
391 break;
392 }
393 break;
394 # elif defined(ANGLE_USE_VULKAN_DISPLAY)
395 if (platformType == EGL_PLATFORM_VULKAN_DISPLAY_MODE_SIMPLE_ANGLE &&
396 rx::IsVulkanSimpleDisplayAvailable())
397 {
398 impl = rx::CreateVulkanSimpleDisplay(state);
399 }
400 else if (platformType == EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE &&
401 rx::IsVulkanHeadlessDisplayAvailable())
402 {
403 impl = rx::CreateVulkanHeadlessDisplay(state);
404 }
405 else
406 {
407 // Not supported creation type on vulkan display, fail display creation.
408 impl = nullptr;
409 }
410 break;
411 # endif
412 # elif defined(ANGLE_PLATFORM_ANDROID)
413 if (rx::IsVulkanAndroidDisplayAvailable())
414 {
415 impl = rx::CreateVulkanAndroidDisplay(state);
416 }
417 break;
418 # elif defined(ANGLE_PLATFORM_FUCHSIA)
419 if (rx::IsVulkanFuchsiaDisplayAvailable())
420 {
421 impl = rx::CreateVulkanFuchsiaDisplay(state);
422 }
423 break;
424 # elif defined(ANGLE_PLATFORM_GGP)
425 if (rx::IsVulkanGGPDisplayAvailable())
426 {
427 impl = rx::CreateVulkanGGPDisplay(state);
428 }
429 break;
430 # elif defined(ANGLE_PLATFORM_APPLE)
431 if (rx::IsVulkanMacDisplayAvailable())
432 {
433 impl = rx::CreateVulkanMacDisplay(state);
434 }
435 break;
436 # else
437 # error Unsupported Vulkan platform.
438 # endif
439 #else
440 // No display available
441 UNREACHABLE();
442 # if !UNREACHABLE_IS_NORETURN
443 break;
444 # endif
445 #endif // defined(ANGLE_ENABLE_VULKAN)
446
447 case EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE:
448 #if defined(ANGLE_ENABLE_METAL)
449 if (rx::IsMetalDisplayAvailable())
450 {
451 impl = rx::CreateMetalDisplay(state);
452 break;
453 }
454 #endif
455 // No display available
456 UNREACHABLE();
457 #if !UNREACHABLE_IS_NORETURN
458 break;
459 #endif
460
461 case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE:
462 #if defined(ANGLE_ENABLE_NULL)
463 impl = new rx::DisplayNULL(state);
464 break;
465 #else
466 // No display available
467 UNREACHABLE();
468 # if !UNREACHABLE_IS_NORETURN
469 break;
470 # endif
471 #endif // defined(ANGLE_ENABLE_NULL)
472
473 default:
474 UNREACHABLE();
475 #if !UNREACHABLE_IS_NORETURN
476 break;
477 #endif
478 }
479
480 return impl;
481 }
482
Display_logError(angle::PlatformMethods * platform,const char * errorMessage)483 void Display_logError(angle::PlatformMethods *platform, const char *errorMessage)
484 {
485 gl::Trace(gl::LOG_ERR, errorMessage);
486 }
487
Display_logWarning(angle::PlatformMethods * platform,const char * warningMessage)488 void Display_logWarning(angle::PlatformMethods *platform, const char *warningMessage)
489 {
490 gl::Trace(gl::LOG_WARN, warningMessage);
491 }
492
Display_logInfo(angle::PlatformMethods * platform,const char * infoMessage)493 void Display_logInfo(angle::PlatformMethods *platform, const char *infoMessage)
494 {
495 // Uncomment to get info spam
496 #if defined(ANGLE_ENABLE_DEBUG_TRACE)
497 gl::Trace(gl::LOG_INFO, infoMessage);
498 #endif
499 }
500
EGLStringArrayToStringVector(const char ** ary)501 const std::vector<std::string> EGLStringArrayToStringVector(const char **ary)
502 {
503 std::vector<std::string> vec;
504 if (ary != nullptr)
505 {
506 for (; *ary != nullptr; ary++)
507 {
508 vec.push_back(std::string(*ary));
509 }
510 }
511 return vec;
512 }
513
ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display)514 void ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display)
515 {
516 angle::PlatformMethods *platformMethods = ANGLEPlatformCurrent();
517
518 ANGLEResetDisplayPlatform(display);
519 platformMethods->logError = Display_logError;
520 platformMethods->logWarning = Display_logWarning;
521 platformMethods->logInfo = Display_logInfo;
522 }
523
524 static constexpr uint32_t kScratchBufferLifetime = 64u;
525
526 } // anonymous namespace
527
528 // ShareGroup
ShareGroup(rx::EGLImplFactory * factory)529 ShareGroup::ShareGroup(rx::EGLImplFactory *factory)
530 : mRefCount(1),
531 mImplementation(factory->createShareGroup()),
532 mFrameCaptureShared(new angle::FrameCaptureShared)
533 {}
534
~ShareGroup()535 ShareGroup::~ShareGroup()
536 {
537 SafeDelete(mImplementation);
538 }
539
addRef()540 void ShareGroup::addRef()
541 {
542 // This is protected by global lock, so no atomic is required
543 mRefCount++;
544 }
545
release(const Display * display)546 void ShareGroup::release(const Display *display)
547 {
548 if (--mRefCount == 0)
549 {
550 if (mImplementation)
551 {
552 mImplementation->onDestroy(display);
553 }
554 delete this;
555 }
556 }
557
558 // DisplayState
DisplayState(EGLNativeDisplayType nativeDisplayId)559 DisplayState::DisplayState(EGLNativeDisplayType nativeDisplayId)
560 : label(nullptr), featuresAllDisabled(false), displayId(nativeDisplayId)
561 {}
562
~DisplayState()563 DisplayState::~DisplayState() {}
564
565 // Note that ANGLE support on Ozone platform is limited. Our prefered support Matrix for
566 // EGL_ANGLE_platform_angle on Linux and Ozone/Linux/Fuchsia platforms should be the following:
567 //
568 // |--------------------------------------------------------|
569 // | ANGLE type | DEVICE type | PLATFORM type | Display |
570 // |--------------------------------------------------------|
571 // | OPENGL | EGL | ANY | EGL |
572 // | OPENGL | HARDWARE | X11_EXT | GLX |
573 // | OPENGLES | HARDWARE | X11_EXT | GLX |
574 // | OPENGLES | EGL | ANY | EGL |
575 // | VULKAN | HARDWARE | X11_EXT | VkXcb |
576 // | VULKAN | SWIFTSHADER | X11_EXT | VkXcb |
577 // | OPENGLES | HARDWARE | SURFACELESS_MESA | EGL* |
578 // | OPENGLES | HARDWARE | DEVICE_EXT | EGL |
579 // | VULKAN | HARDWARE | SURFACELESS_MESA | VkBase** |
580 // | VULKAN | SWIFTSHADER | SURFACELESS_MESA | VkBase** |
581 // |--------------------------------------------------------|
582 //
583 // * No surfaceless support yet.
584 // ** Not implemented yet.
585 //
586 // |-----------------------------------------------|
587 // | OS | BUILD type | Default PLATFORM type |
588 // |-----------------------------------------------|
589 // | Linux | X11 | X11_EXT |
590 // | Linux | Ozone | SURFACELESS_MESA |
591 // | Fuchsia | Ozone | FUCHSIA*** |
592 // |-----------------------------------------------|
593 //
594 // *** Chosen implicitly. No EGLAttrib available.
595 //
596 // For more details, please refer to
597 // https://docs.google.com/document/d/1XjHiDZQISq1AMrg_l1TX1_kIKvDpU76hidn9i4cAjl8/edit?disco=AAAAJl9V_YY
598 //
599 // static
GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay,const AttributeMap & attribMap)600 Display *Display::GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay,
601 const AttributeMap &attribMap)
602 {
603 Display *display = nullptr;
604
605 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
606 const auto &iter = displays->find(nativeDisplay);
607 if (iter != displays->end())
608 {
609 display = iter->second;
610 }
611
612 if (display == nullptr)
613 {
614 // Validate the native display
615 if (!Display::isValidNativeDisplay(nativeDisplay))
616 {
617 return nullptr;
618 }
619
620 display = new Display(EGL_PLATFORM_ANGLE_ANGLE, nativeDisplay, nullptr);
621 displays->insert(std::make_pair(nativeDisplay, display));
622 }
623
624 // Apply new attributes if the display is not initialized yet.
625 if (!display->isInitialized())
626 {
627 display->setAttributes(attribMap);
628
629 display->updateAttribsFromEnvironment(attribMap);
630
631 EGLAttrib displayType = display->mAttributeMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
632 EGLAttrib deviceType = display->mAttributeMap.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
633 EGLAttrib platformType =
634 display->mAttributeMap.get(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE);
635 rx::DisplayImpl *impl =
636 CreateDisplayFromAttribs(displayType, deviceType, platformType, display->getState());
637 if (impl == nullptr)
638 {
639 // No valid display implementation for these attributes
640 return nullptr;
641 }
642
643 #if defined(ANGLE_PLATFORM_ANDROID)
644 angle::gUseAndroidOpenGLTlsSlot = displayType == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
645 #endif // defined(ANGLE_PLATFORM_ANDROID)
646
647 display->setupDisplayPlatform(impl);
648 }
649
650 return display;
651 }
652
653 // static
GetExistingDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay)654 Display *Display::GetExistingDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay)
655 {
656 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
657 const auto &iter = displays->find(nativeDisplay);
658
659 // Check that there is a matching display
660 if (iter == displays->end())
661 {
662 return nullptr;
663 }
664
665 return iter->second;
666 }
667
668 // static
GetDisplayFromDevice(Device * device,const AttributeMap & attribMap)669 Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attribMap)
670 {
671 Display *display = nullptr;
672
673 ASSERT(Device::IsValidDevice(device));
674
675 ANGLEPlatformDisplayMap *anglePlatformDisplays = GetANGLEPlatformDisplayMap();
676 DevicePlatformDisplayMap *devicePlatformDisplays = GetDevicePlatformDisplayMap();
677
678 // First see if this eglDevice is in use by a Display created using ANGLE platform
679 for (auto &displayMapEntry : *anglePlatformDisplays)
680 {
681 egl::Display *iterDisplay = displayMapEntry.second;
682 if (iterDisplay->getDevice() == device)
683 {
684 display = iterDisplay;
685 }
686 }
687
688 if (display == nullptr)
689 {
690 // See if the eglDevice is in use by a Display created using the DEVICE platform
691 const auto &iter = devicePlatformDisplays->find(device);
692 if (iter != devicePlatformDisplays->end())
693 {
694 display = iter->second;
695 }
696 }
697
698 if (display == nullptr)
699 {
700 // Otherwise create a new Display
701 display = new Display(EGL_PLATFORM_DEVICE_EXT, 0, device);
702 devicePlatformDisplays->insert(std::make_pair(device, display));
703 }
704
705 // Apply new attributes if the display is not initialized yet.
706 if (!display->isInitialized())
707 {
708 display->setAttributes(attribMap);
709 rx::DisplayImpl *impl = CreateDisplayFromDevice(device, display->getState());
710 display->setupDisplayPlatform(impl);
711 }
712
713 return display;
714 }
715
Display(EGLenum platform,EGLNativeDisplayType displayId,Device * eglDevice)716 Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice)
717 : mState(displayId),
718 mImplementation(nullptr),
719 mGPUSwitchedBinding(this, kGPUSwitchedSubjectIndex),
720 mAttributeMap(),
721 mConfigSet(),
722 mContextSet(),
723 mStreamSet(),
724 mInitialized(false),
725 mDeviceLost(false),
726 mCaps(),
727 mDisplayExtensions(),
728 mDisplayExtensionString(),
729 mVendorString(),
730 mVersionString(),
731 mDevice(eglDevice),
732 mSurface(nullptr),
733 mPlatform(platform),
734 mTextureManager(nullptr),
735 mSemaphoreManager(nullptr),
736 mBlobCache(gl::kDefaultMaxProgramCacheMemoryBytes),
737 mMemoryProgramCache(mBlobCache),
738 mGlobalTextureShareGroupUsers(0),
739 mGlobalSemaphoreShareGroupUsers(0)
740 {}
741
~Display()742 Display::~Display()
743 {
744 // TODO(jmadill): When is this called?
745 // terminate();
746
747 if (mPlatform == EGL_PLATFORM_ANGLE_ANGLE)
748 {
749 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
750 ANGLEPlatformDisplayMap::iterator iter = displays->find(mState.displayId);
751 if (iter != displays->end())
752 {
753 displays->erase(iter);
754 }
755 }
756 else if (mPlatform == EGL_PLATFORM_DEVICE_EXT)
757 {
758 DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap();
759 DevicePlatformDisplayMap::iterator iter = displays->find(mDevice);
760 if (iter != displays->end())
761 {
762 displays->erase(iter);
763 }
764 }
765 else
766 {
767 UNREACHABLE();
768 }
769
770 SafeDelete(mDevice);
771 SafeDelete(mImplementation);
772 }
773
setLabel(EGLLabelKHR label)774 void Display::setLabel(EGLLabelKHR label)
775 {
776 mState.label = label;
777 }
778
getLabel() const779 EGLLabelKHR Display::getLabel() const
780 {
781 return mState.label;
782 }
783
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)784 void Display::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
785 {
786 ASSERT(index == kGPUSwitchedSubjectIndex);
787 ASSERT(message == angle::SubjectMessage::SubjectChanged);
788 for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
789 {
790 (*ctx)->onGPUSwitch();
791 }
792 }
793
setupDisplayPlatform(rx::DisplayImpl * impl)794 void Display::setupDisplayPlatform(rx::DisplayImpl *impl)
795 {
796 ASSERT(!mInitialized);
797
798 ASSERT(impl != nullptr);
799 SafeDelete(mImplementation);
800 mImplementation = impl;
801
802 // TODO(jmadill): Store Platform in Display and init here.
803 const angle::PlatformMethods *platformMethods =
804 reinterpret_cast<const angle::PlatformMethods *>(
805 mAttributeMap.get(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX, 0));
806 if (platformMethods != nullptr)
807 {
808 *ANGLEPlatformCurrent() = *platformMethods;
809 }
810 else
811 {
812 ANGLESetDefaultDisplayPlatform(this);
813 }
814
815 const char **featuresForceEnabled =
816 reinterpret_cast<const char **>(mAttributeMap.get(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, 0));
817 const char **featuresForceDisabled =
818 reinterpret_cast<const char **>(mAttributeMap.get(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, 0));
819 mState.featureOverridesEnabled = EGLStringArrayToStringVector(featuresForceEnabled);
820 mState.featureOverridesDisabled = EGLStringArrayToStringVector(featuresForceDisabled);
821 mState.featuresAllDisabled =
822 static_cast<bool>(mAttributeMap.get(EGL_FEATURE_ALL_DISABLED_ANGLE, 0));
823 mImplementation->addObserver(&mGPUSwitchedBinding);
824 }
825
updateAttribsFromEnvironment(const AttributeMap & attribMap)826 void Display::updateAttribsFromEnvironment(const AttributeMap &attribMap)
827 {
828 EGLAttrib displayType =
829 attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
830 if (displayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
831 {
832 displayType = GetDisplayTypeFromEnvironment();
833 mAttributeMap.insert(EGL_PLATFORM_ANGLE_TYPE_ANGLE, displayType);
834 }
835 EGLAttrib deviceType = attribMap.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, 0);
836 if (deviceType == 0)
837 {
838 deviceType = GetDeviceTypeFromEnvironment();
839 mAttributeMap.insert(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, deviceType);
840 }
841 EGLAttrib platformType = attribMap.get(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE, 0);
842 if (platformType == 0)
843 {
844 platformType = GetPlatformTypeFromEnvironment();
845 mAttributeMap.insert(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE, platformType);
846 }
847 }
848
initialize()849 Error Display::initialize()
850 {
851 ASSERT(mImplementation != nullptr);
852 mImplementation->setBlobCache(&mBlobCache);
853
854 // Enable shader caching if debug layers are turned on. This allows us to test that shaders are
855 // properly saved & restored on all platforms. The cache won't allocate space until it's used
856 // and will be ignored entirely if the application / system sets it's own cache functions.
857 if (rx::ShouldUseDebugLayers(mAttributeMap))
858 {
859 mBlobCache.resize(1024 * 1024);
860 }
861
862 setGlobalDebugAnnotator();
863
864 gl::InitializeDebugMutexIfNeeded();
865
866 SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.DisplayInitializeMS");
867 ANGLE_TRACE_EVENT0("gpu.angle", "egl::Display::initialize");
868
869 if (isInitialized())
870 {
871 return NoError();
872 }
873
874 Error error = mImplementation->initialize(this);
875 if (error.isError())
876 {
877 // Log extended error message here
878 ERR() << "ANGLE Display::initialize error " << error.getID() << ": " << error.getMessage();
879 return error;
880 }
881
882 mCaps = mImplementation->getCaps();
883
884 mConfigSet = mImplementation->generateConfigs();
885 if (mConfigSet.size() == 0)
886 {
887 mImplementation->terminate();
888 return EglNotInitialized();
889 }
890
891 // OpenGL ES1 is implemented in the frontend, explicitly add ES1 support to all configs
892 for (auto &config : mConfigSet)
893 {
894 // TODO(geofflang): Enable the conformant bit once we pass enough tests
895 // config.second.conformant |= EGL_OPENGL_ES_BIT;
896
897 config.second.renderableType |= EGL_OPENGL_ES_BIT;
898 }
899
900 if (!mState.featuresAllDisabled)
901 {
902 initializeFrontendFeatures();
903 }
904
905 mFeatures.clear();
906 mFrontendFeatures.populateFeatureList(&mFeatures);
907 mImplementation->populateFeatureList(&mFeatures);
908
909 initDisplayExtensions();
910 initVendorString();
911 initVersionString();
912
913 // Populate the Display's EGLDeviceEXT if the Display wasn't created using one
914 if (mPlatform == EGL_PLATFORM_DEVICE_EXT)
915 {
916 // For EGL_PLATFORM_DEVICE_EXT, mDevice should always be populated using
917 // an external device
918 ASSERT(mDevice != nullptr);
919 }
920 else if (GetClientExtensions().deviceQueryEXT)
921 {
922 std::unique_ptr<rx::DeviceImpl> impl(mImplementation->createDevice());
923 ASSERT(impl);
924 error = impl->initialize();
925 if (error.isError())
926 {
927 ERR() << "Failed to initialize display because device creation failed: "
928 << error.getMessage();
929 mImplementation->terminate();
930 return error;
931 }
932 mDevice = new Device(this, impl.release());
933 }
934 else
935 {
936 mDevice = nullptr;
937 }
938
939 mInitialized = true;
940
941 return NoError();
942 }
943
terminate(Thread * thread)944 Error Display::terminate(Thread *thread)
945 {
946 if (!mInitialized)
947 {
948 return NoError();
949 }
950
951 mMemoryProgramCache.clear();
952 mBlobCache.setBlobCacheFuncs(nullptr, nullptr);
953
954 if (auto *context = thread->getContext())
955 {
956 auto refCount = context->getRefCount();
957 ASSERT(refCount <= 2);
958 // If eglDestroyContext is not called for the current context, we destroy the context.
959 if (context->getRefCount() == 2)
960 {
961 ANGLE_TRY(destroyContext(thread, context));
962 }
963 // unMakeCurrent the context, so it will be released.
964 ANGLE_TRY(makeCurrent(thread, thread->getContext(), nullptr, nullptr, nullptr));
965 ASSERT(!thread->getContext());
966 }
967
968 while (!mContextSet.empty())
969 {
970 auto *context = *mContextSet.begin();
971 // If the context is never be current, so context resources are not allocated,
972 // and we don't need to make the context current for releasing resources.
973 if (!context->isExternal() && context->hasBeenCurrent())
974 {
975 ANGLE_TRY(mImplementation->makeCurrent(this, nullptr, nullptr, context));
976 }
977
978 // Force to release all refs, since the context could be current on other threads.
979 while (context->getRefCount())
980 {
981 context->release();
982 }
983
984 ANGLE_TRY(releaseContext(context));
985 }
986
987 // The global texture and semaphore managers should be deleted with the last context that uses
988 // it.
989 ASSERT(mGlobalTextureShareGroupUsers == 0 && mTextureManager == nullptr);
990 ASSERT(mGlobalSemaphoreShareGroupUsers == 0 && mSemaphoreManager == nullptr);
991
992 while (!mImageSet.empty())
993 {
994 destroyImage(*mImageSet.begin());
995 }
996
997 while (!mStreamSet.empty())
998 {
999 destroyStream(*mStreamSet.begin());
1000 }
1001
1002 while (!mSyncSet.empty())
1003 {
1004 destroySync(*mSyncSet.begin());
1005 }
1006
1007 while (!mState.surfaceSet.empty())
1008 {
1009 ANGLE_TRY(destroySurface(*mState.surfaceSet.begin()));
1010 }
1011
1012 mConfigSet.clear();
1013
1014 if (mDevice != nullptr && mDevice->getOwningDisplay() != nullptr)
1015 {
1016 // Don't delete the device if it was created externally using eglCreateDeviceANGLE
1017 // We also shouldn't set it to null in case eglInitialize() is called again later
1018 SafeDelete(mDevice);
1019 }
1020
1021 mImplementation->terminate();
1022
1023 mDeviceLost = false;
1024
1025 mInitialized = false;
1026
1027 gl::UninitializeDebugAnnotations();
1028
1029 // TODO(jmadill): Store Platform in Display and deinit here.
1030 ANGLEResetDisplayPlatform(this);
1031
1032 return NoError();
1033 }
1034
prepareForCall()1035 Error Display::prepareForCall()
1036 {
1037 return mImplementation->prepareForCall();
1038 }
1039
releaseThread()1040 Error Display::releaseThread()
1041 {
1042 return mImplementation->releaseThread();
1043 }
1044
getConfigs(const egl::AttributeMap & attribs) const1045 std::vector<const Config *> Display::getConfigs(const egl::AttributeMap &attribs) const
1046 {
1047 return mConfigSet.filter(attribs);
1048 }
1049
chooseConfig(const egl::AttributeMap & attribs) const1050 std::vector<const Config *> Display::chooseConfig(const egl::AttributeMap &attribs) const
1051 {
1052 egl::AttributeMap attribsWithDefaults = AttributeMap();
1053
1054 // Insert default values for attributes that have either an Exact or Mask selection criteria,
1055 // and a default value that matters (e.g. isn't EGL_DONT_CARE):
1056 attribsWithDefaults.insert(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
1057 attribsWithDefaults.insert(EGL_LEVEL, 0);
1058 attribsWithDefaults.insert(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT);
1059 attribsWithDefaults.insert(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
1060 attribsWithDefaults.insert(EGL_TRANSPARENT_TYPE, EGL_NONE);
1061 if (getExtensions().pixelFormatFloat)
1062 {
1063 attribsWithDefaults.insert(EGL_COLOR_COMPONENT_TYPE_EXT,
1064 EGL_COLOR_COMPONENT_TYPE_FIXED_EXT);
1065 }
1066
1067 // Add the caller-specified values (Note: the poorly-named insert() method will replace any
1068 // of the default values from above):
1069 for (auto attribIter = attribs.begin(); attribIter != attribs.end(); attribIter++)
1070 {
1071 attribsWithDefaults.insert(attribIter->first, attribIter->second);
1072 }
1073
1074 return mConfigSet.filter(attribsWithDefaults);
1075 }
1076
createWindowSurface(const Config * configuration,EGLNativeWindowType window,const AttributeMap & attribs,Surface ** outSurface)1077 Error Display::createWindowSurface(const Config *configuration,
1078 EGLNativeWindowType window,
1079 const AttributeMap &attribs,
1080 Surface **outSurface)
1081 {
1082 if (mImplementation->testDeviceLost())
1083 {
1084 ANGLE_TRY(restoreLostDevice());
1085 }
1086
1087 SurfacePointer surface(new WindowSurface(mImplementation, configuration, window, attribs,
1088 mFrontendFeatures.forceRobustResourceInit.enabled),
1089 this);
1090 ANGLE_TRY(surface->initialize(this));
1091
1092 ASSERT(outSurface != nullptr);
1093 *outSurface = surface.release();
1094 mState.surfaceSet.insert(*outSurface);
1095
1096 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
1097 ASSERT(windowSurfaces && windowSurfaces->find(window) == windowSurfaces->end());
1098 windowSurfaces->insert(std::make_pair(window, *outSurface));
1099
1100 mSurface = *outSurface;
1101
1102 return NoError();
1103 }
1104
createPbufferSurface(const Config * configuration,const AttributeMap & attribs,Surface ** outSurface)1105 Error Display::createPbufferSurface(const Config *configuration,
1106 const AttributeMap &attribs,
1107 Surface **outSurface)
1108 {
1109 ASSERT(isInitialized());
1110
1111 if (mImplementation->testDeviceLost())
1112 {
1113 ANGLE_TRY(restoreLostDevice());
1114 }
1115
1116 SurfacePointer surface(new PbufferSurface(mImplementation, configuration, attribs,
1117 mFrontendFeatures.forceRobustResourceInit.enabled),
1118 this);
1119 ANGLE_TRY(surface->initialize(this));
1120
1121 ASSERT(outSurface != nullptr);
1122 *outSurface = surface.release();
1123 mState.surfaceSet.insert(*outSurface);
1124
1125 return NoError();
1126 }
1127
createPbufferFromClientBuffer(const Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const AttributeMap & attribs,Surface ** outSurface)1128 Error Display::createPbufferFromClientBuffer(const Config *configuration,
1129 EGLenum buftype,
1130 EGLClientBuffer clientBuffer,
1131 const AttributeMap &attribs,
1132 Surface **outSurface)
1133 {
1134 ASSERT(isInitialized());
1135
1136 if (mImplementation->testDeviceLost())
1137 {
1138 ANGLE_TRY(restoreLostDevice());
1139 }
1140
1141 SurfacePointer surface(
1142 new PbufferSurface(mImplementation, configuration, buftype, clientBuffer, attribs,
1143 mFrontendFeatures.forceRobustResourceInit.enabled),
1144 this);
1145 ANGLE_TRY(surface->initialize(this));
1146
1147 ASSERT(outSurface != nullptr);
1148 *outSurface = surface.release();
1149 mState.surfaceSet.insert(*outSurface);
1150
1151 return NoError();
1152 }
1153
createPixmapSurface(const Config * configuration,NativePixmapType nativePixmap,const AttributeMap & attribs,Surface ** outSurface)1154 Error Display::createPixmapSurface(const Config *configuration,
1155 NativePixmapType nativePixmap,
1156 const AttributeMap &attribs,
1157 Surface **outSurface)
1158 {
1159 ASSERT(isInitialized());
1160
1161 if (mImplementation->testDeviceLost())
1162 {
1163 ANGLE_TRY(restoreLostDevice());
1164 }
1165
1166 SurfacePointer surface(new PixmapSurface(mImplementation, configuration, nativePixmap, attribs,
1167 mFrontendFeatures.forceRobustResourceInit.enabled),
1168 this);
1169 ANGLE_TRY(surface->initialize(this));
1170
1171 ASSERT(outSurface != nullptr);
1172 *outSurface = surface.release();
1173 mState.surfaceSet.insert(*outSurface);
1174
1175 return NoError();
1176 }
1177
createImage(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs,Image ** outImage)1178 Error Display::createImage(const gl::Context *context,
1179 EGLenum target,
1180 EGLClientBuffer buffer,
1181 const AttributeMap &attribs,
1182 Image **outImage)
1183 {
1184 ASSERT(isInitialized());
1185
1186 if (mImplementation->testDeviceLost())
1187 {
1188 ANGLE_TRY(restoreLostDevice());
1189 }
1190
1191 egl::ImageSibling *sibling = nullptr;
1192 if (IsTextureTarget(target))
1193 {
1194 sibling = context->getTexture({egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
1195 }
1196 else if (IsRenderbufferTarget(target))
1197 {
1198 sibling = context->getRenderbuffer({egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
1199 }
1200 else if (IsExternalImageTarget(target))
1201 {
1202 sibling = new ExternalImageSibling(mImplementation, context, target, buffer, attribs);
1203 }
1204 else
1205 {
1206 UNREACHABLE();
1207 }
1208 ASSERT(sibling != nullptr);
1209
1210 angle::UniqueObjectPointer<Image, Display> imagePtr(
1211 new Image(mImplementation, context, target, sibling, attribs), this);
1212 ANGLE_TRY(imagePtr->initialize(this));
1213
1214 Image *image = imagePtr.release();
1215
1216 ASSERT(outImage != nullptr);
1217 *outImage = image;
1218
1219 // Add this image to the list of all images and hold a ref to it.
1220 image->addRef();
1221 mImageSet.insert(image);
1222
1223 return NoError();
1224 }
1225
createStream(const AttributeMap & attribs,Stream ** outStream)1226 Error Display::createStream(const AttributeMap &attribs, Stream **outStream)
1227 {
1228 ASSERT(isInitialized());
1229
1230 Stream *stream = new Stream(this, attribs);
1231
1232 ASSERT(stream != nullptr);
1233 mStreamSet.insert(stream);
1234
1235 ASSERT(outStream != nullptr);
1236 *outStream = stream;
1237
1238 return NoError();
1239 }
1240
createContext(const Config * configuration,gl::Context * shareContext,EGLenum clientType,const AttributeMap & attribs,gl::Context ** outContext)1241 Error Display::createContext(const Config *configuration,
1242 gl::Context *shareContext,
1243 EGLenum clientType,
1244 const AttributeMap &attribs,
1245 gl::Context **outContext)
1246 {
1247 ASSERT(isInitialized());
1248
1249 if (mImplementation->testDeviceLost())
1250 {
1251 ANGLE_TRY(restoreLostDevice());
1252 }
1253
1254 // This display texture sharing will allow the first context to create the texture share group.
1255 bool usingDisplayTextureShareGroup =
1256 attribs.get(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE;
1257 gl::TextureManager *shareTextures = nullptr;
1258
1259 if (usingDisplayTextureShareGroup)
1260 {
1261 ASSERT((mTextureManager == nullptr) == (mGlobalTextureShareGroupUsers == 0));
1262 if (mTextureManager == nullptr)
1263 {
1264 mTextureManager = new gl::TextureManager();
1265 }
1266
1267 mGlobalTextureShareGroupUsers++;
1268 shareTextures = mTextureManager;
1269 }
1270
1271 // This display semaphore sharing will allow the first context to create the semaphore share
1272 // group.
1273 bool usingDisplaySemaphoreShareGroup =
1274 attribs.get(EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE;
1275 gl::SemaphoreManager *shareSemaphores = nullptr;
1276 if (usingDisplaySemaphoreShareGroup)
1277 {
1278 ASSERT((mSemaphoreManager == nullptr) == (mGlobalSemaphoreShareGroupUsers == 0));
1279 if (mSemaphoreManager == nullptr)
1280 {
1281 mSemaphoreManager = new gl::SemaphoreManager();
1282 }
1283
1284 mGlobalSemaphoreShareGroupUsers++;
1285 shareSemaphores = mSemaphoreManager;
1286 }
1287
1288 gl::MemoryProgramCache *cachePointer = &mMemoryProgramCache;
1289
1290 // Check context creation attributes to see if we are using EGL_ANGLE_program_cache_control.
1291 // If not, keep caching enabled for EGL_ANDROID_blob_cache, which can have its callbacks set
1292 // at any time.
1293 bool usesProgramCacheControl =
1294 mAttributeMap.contains(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE);
1295 if (usesProgramCacheControl)
1296 {
1297 bool programCacheControlEnabled =
1298 (mAttributeMap.get(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE, GL_FALSE) ==
1299 GL_TRUE);
1300 // A program cache size of zero indicates it should be disabled.
1301 if (!programCacheControlEnabled || mMemoryProgramCache.maxSize() == 0)
1302 {
1303 cachePointer = nullptr;
1304 }
1305 }
1306
1307 gl::Context *context = new gl::Context(this, configuration, shareContext, shareTextures,
1308 shareSemaphores, cachePointer, clientType, attribs,
1309 mDisplayExtensions, GetClientExtensions());
1310 Error error = context->initialize();
1311 if (error.isError())
1312 {
1313 delete context;
1314 return error;
1315 }
1316
1317 if (shareContext != nullptr)
1318 {
1319 shareContext->setShared();
1320 }
1321
1322 ASSERT(context != nullptr);
1323 context->addRef();
1324 mContextSet.insert(context);
1325
1326 ASSERT(outContext != nullptr);
1327 *outContext = context;
1328 return NoError();
1329 }
1330
createSync(const gl::Context * currentContext,EGLenum type,const AttributeMap & attribs,Sync ** outSync)1331 Error Display::createSync(const gl::Context *currentContext,
1332 EGLenum type,
1333 const AttributeMap &attribs,
1334 Sync **outSync)
1335 {
1336 ASSERT(isInitialized());
1337
1338 if (mImplementation->testDeviceLost())
1339 {
1340 ANGLE_TRY(restoreLostDevice());
1341 }
1342
1343 angle::UniqueObjectPointer<egl::Sync, Display> syncPtr(new Sync(mImplementation, type, attribs),
1344 this);
1345
1346 ANGLE_TRY(syncPtr->initialize(this, currentContext));
1347
1348 Sync *sync = syncPtr.release();
1349
1350 sync->addRef();
1351 mSyncSet.insert(sync);
1352
1353 *outSync = sync;
1354 return NoError();
1355 }
1356
makeCurrent(Thread * thread,gl::Context * previousContext,egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)1357 Error Display::makeCurrent(Thread *thread,
1358 gl::Context *previousContext,
1359 egl::Surface *drawSurface,
1360 egl::Surface *readSurface,
1361 gl::Context *context)
1362 {
1363 if (!mInitialized)
1364 {
1365 return NoError();
1366 }
1367
1368 // If the context is changing we need to update the reference counts. If it's not, e.g. just
1369 // changing the surfaces leave the reference count alone. Otherwise the reference count might go
1370 // to zero even though we know we are not done with the context.
1371 bool contextChanged = context != previousContext;
1372 if (previousContext != nullptr && contextChanged)
1373 {
1374 previousContext->release();
1375 thread->setCurrent(nullptr);
1376
1377 auto error = previousContext->unMakeCurrent(this);
1378 if (previousContext->getRefCount() == 0)
1379 {
1380 ANGLE_TRY(releaseContext(previousContext));
1381 }
1382 ANGLE_TRY(error);
1383 }
1384
1385 ANGLE_TRY(mImplementation->makeCurrent(this, drawSurface, readSurface, context));
1386
1387 if (context != nullptr)
1388 {
1389 ANGLE_TRY(context->makeCurrent(this, drawSurface, readSurface));
1390 thread->setCurrent(context);
1391 }
1392
1393 if (context != nullptr && contextChanged)
1394 {
1395 context->addRef();
1396 }
1397
1398 // Tick all the scratch buffers to make sure they get cleaned up eventually if they stop being
1399 // used.
1400 {
1401 std::lock_guard<std::mutex> lock(mScratchBufferMutex);
1402
1403 for (angle::ScratchBuffer &scatchBuffer : mScratchBuffers)
1404 {
1405 scatchBuffer.tick();
1406 }
1407 for (angle::ScratchBuffer &zeroFilledBuffer : mZeroFilledBuffers)
1408 {
1409 zeroFilledBuffer.tick();
1410 }
1411 }
1412
1413 return NoError();
1414 }
1415
restoreLostDevice()1416 Error Display::restoreLostDevice()
1417 {
1418 for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
1419 {
1420 if ((*ctx)->isResetNotificationEnabled())
1421 {
1422 // If reset notifications have been requested, application must delete all contexts
1423 // first
1424 return EglContextLost();
1425 }
1426 }
1427
1428 return mImplementation->restoreLostDevice(this);
1429 }
1430
destroySurface(Surface * surface)1431 Error Display::destroySurface(Surface *surface)
1432 {
1433 if (surface->getType() == EGL_WINDOW_BIT)
1434 {
1435 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
1436 ASSERT(windowSurfaces);
1437
1438 bool surfaceRemoved = false;
1439 for (WindowSurfaceMap::iterator iter = windowSurfaces->begin();
1440 iter != windowSurfaces->end(); iter++)
1441 {
1442 if (iter->second == surface)
1443 {
1444 windowSurfaces->erase(iter);
1445 surfaceRemoved = true;
1446 break;
1447 }
1448 }
1449
1450 ASSERT(surfaceRemoved);
1451 }
1452
1453 mState.surfaceSet.erase(surface);
1454 ANGLE_TRY(surface->onDestroy(this));
1455 return NoError();
1456 }
1457
destroyImage(egl::Image * image)1458 void Display::destroyImage(egl::Image *image)
1459 {
1460 auto iter = mImageSet.find(image);
1461 ASSERT(iter != mImageSet.end());
1462 (*iter)->release(this);
1463 mImageSet.erase(iter);
1464 }
1465
destroyStream(egl::Stream * stream)1466 void Display::destroyStream(egl::Stream *stream)
1467 {
1468 mStreamSet.erase(stream);
1469 SafeDelete(stream);
1470 }
1471
1472 // releaseContext must be called with the context being deleted as current.
1473 // To do that we can only call this in two places, Display::makeCurrent at the point where this
1474 // context is being made uncurrent and in Display::destroyContext where we make the context current
1475 // as part of destruction.
releaseContext(gl::Context * context)1476 Error Display::releaseContext(gl::Context *context)
1477 {
1478 ASSERT(context->getRefCount() == 0);
1479
1480 // Use scoped_ptr to make sure the context is always freed.
1481 std::unique_ptr<gl::Context> unique_context(context);
1482 ASSERT(mContextSet.find(context) != mContextSet.end());
1483 mContextSet.erase(context);
1484
1485 if (context->usingDisplayTextureShareGroup())
1486 {
1487 ASSERT(mGlobalTextureShareGroupUsers >= 1 && mTextureManager != nullptr);
1488 if (mGlobalTextureShareGroupUsers == 1)
1489 {
1490 // If this is the last context using the global share group, destroy the global
1491 // texture manager so that the textures can be destroyed while a context still
1492 // exists
1493 mTextureManager->release(context);
1494 mTextureManager = nullptr;
1495 }
1496 mGlobalTextureShareGroupUsers--;
1497 }
1498
1499 if (context->usingDisplaySemaphoreShareGroup())
1500 {
1501 ASSERT(mGlobalSemaphoreShareGroupUsers >= 1 && mSemaphoreManager != nullptr);
1502 if (mGlobalSemaphoreShareGroupUsers == 1)
1503 {
1504 // If this is the last context using the global share group, destroy the global
1505 // semaphore manager so that the semaphores can be destroyed while a context still
1506 // exists
1507 mSemaphoreManager->release(context);
1508 mSemaphoreManager = nullptr;
1509 }
1510 mGlobalSemaphoreShareGroupUsers--;
1511 }
1512
1513 ANGLE_TRY(context->onDestroy(this));
1514
1515 return NoError();
1516 }
1517
destroyContext(Thread * thread,gl::Context * context)1518 Error Display::destroyContext(Thread *thread, gl::Context *context)
1519 {
1520 context->release();
1521
1522 auto *currentContext = thread->getContext();
1523 auto *currentDrawSurface = thread->getCurrentDrawSurface();
1524 auto *currentReadSurface = thread->getCurrentReadSurface();
1525
1526 if (context->isCurrent())
1527 {
1528 ASSERT(context->getRefCount() == 1);
1529 // If the context is current, we just return, since the context has been marked destroyed,
1530 // so the context will be destroyed when the context is released from the current.
1531 return NoError();
1532 }
1533
1534 ASSERT(context->getRefCount() == 0);
1535
1536 // For external context, we cannot change the current native context, and the API user should
1537 // make sure the native context is current.
1538 if (context->isExternal())
1539 {
1540 ANGLE_TRY(releaseContext(context));
1541 }
1542 else
1543 {
1544 // Keep |currentContext| alive, while releasing |context|.
1545 gl::ScopedContextRef scopedContextRef(currentContext);
1546
1547 // Make the context current, so we can release resources belong to the context, and then
1548 // when context is released from the current, it will be destroyed.
1549 ANGLE_TRY(makeCurrent(thread, currentContext, nullptr, nullptr, context));
1550 ANGLE_TRY(
1551 makeCurrent(thread, context, currentDrawSurface, currentReadSurface, currentContext));
1552 }
1553 return NoError();
1554 }
1555
destroySync(egl::Sync * sync)1556 void Display::destroySync(egl::Sync *sync)
1557 {
1558 auto iter = mSyncSet.find(sync);
1559 ASSERT(iter != mSyncSet.end());
1560 (*iter)->release(this);
1561 mSyncSet.erase(iter);
1562 }
1563
isDeviceLost() const1564 bool Display::isDeviceLost() const
1565 {
1566 ASSERT(isInitialized());
1567 return mDeviceLost;
1568 }
1569
testDeviceLost()1570 bool Display::testDeviceLost()
1571 {
1572 ASSERT(isInitialized());
1573
1574 if (!mDeviceLost && mImplementation->testDeviceLost())
1575 {
1576 notifyDeviceLost();
1577 }
1578
1579 return mDeviceLost;
1580 }
1581
notifyDeviceLost()1582 void Display::notifyDeviceLost()
1583 {
1584 if (mDeviceLost)
1585 {
1586 return;
1587 }
1588
1589 for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end();
1590 context++)
1591 {
1592 (*context)->markContextLost(gl::GraphicsResetStatus::UnknownContextReset);
1593 }
1594
1595 mDeviceLost = true;
1596 }
1597
setBlobCacheFuncs(EGLSetBlobFuncANDROID set,EGLGetBlobFuncANDROID get)1598 void Display::setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get)
1599 {
1600 mBlobCache.setBlobCacheFuncs(set, get);
1601 mImplementation->setBlobCacheFuncs(set, get);
1602 }
1603
1604 // static
GetNativeClientBuffer(const AHardwareBuffer * buffer)1605 EGLClientBuffer Display::GetNativeClientBuffer(const AHardwareBuffer *buffer)
1606 {
1607 return angle::android::AHardwareBufferToClientBuffer(buffer);
1608 }
1609
1610 // static
CreateNativeClientBuffer(const egl::AttributeMap & attribMap,EGLClientBuffer * eglClientBuffer)1611 Error Display::CreateNativeClientBuffer(const egl::AttributeMap &attribMap,
1612 EGLClientBuffer *eglClientBuffer)
1613 {
1614 int androidHardwareBufferFormat = gl::GetAndroidHardwareBufferFormatFromChannelSizes(attribMap);
1615 int width = attribMap.getAsInt(EGL_WIDTH, 0);
1616 int height = attribMap.getAsInt(EGL_HEIGHT, 0);
1617 int usage = attribMap.getAsInt(EGL_NATIVE_BUFFER_USAGE_ANDROID, 0);
1618
1619 // https://developer.android.com/ndk/reference/group/a-hardware-buffer#ahardwarebuffer_lock
1620 // for AHardwareBuffer_lock()
1621 // The passed AHardwareBuffer must have one layer, otherwise the call will fail.
1622 constexpr int kLayerCount = 1;
1623
1624 *eglClientBuffer = angle::android::CreateEGLClientBufferFromAHardwareBuffer(
1625 width, height, kLayerCount, androidHardwareBufferFormat, usage);
1626
1627 return (*eglClientBuffer == nullptr)
1628 ? egl::EglBadParameter() << "native client buffer allocation failed."
1629 : NoError();
1630 }
1631
waitClient(const gl::Context * context)1632 Error Display::waitClient(const gl::Context *context)
1633 {
1634 return mImplementation->waitClient(context);
1635 }
1636
waitNative(const gl::Context * context,EGLint engine)1637 Error Display::waitNative(const gl::Context *context, EGLint engine)
1638 {
1639 return mImplementation->waitNative(context, engine);
1640 }
1641
getCaps() const1642 const Caps &Display::getCaps() const
1643 {
1644 return mCaps;
1645 }
1646
isInitialized() const1647 bool Display::isInitialized() const
1648 {
1649 return mInitialized;
1650 }
1651
isValidConfig(const Config * config) const1652 bool Display::isValidConfig(const Config *config) const
1653 {
1654 return mConfigSet.contains(config);
1655 }
1656
isValidContext(const gl::Context * context) const1657 bool Display::isValidContext(const gl::Context *context) const
1658 {
1659 return mContextSet.find(const_cast<gl::Context *>(context)) != mContextSet.end();
1660 }
1661
isValidSurface(const Surface * surface) const1662 bool Display::isValidSurface(const Surface *surface) const
1663 {
1664 return mState.surfaceSet.find(const_cast<Surface *>(surface)) != mState.surfaceSet.end();
1665 }
1666
isValidImage(const Image * image) const1667 bool Display::isValidImage(const Image *image) const
1668 {
1669 return mImageSet.find(const_cast<Image *>(image)) != mImageSet.end();
1670 }
1671
isValidStream(const Stream * stream) const1672 bool Display::isValidStream(const Stream *stream) const
1673 {
1674 return mStreamSet.find(const_cast<Stream *>(stream)) != mStreamSet.end();
1675 }
1676
isValidSync(const Sync * sync) const1677 bool Display::isValidSync(const Sync *sync) const
1678 {
1679 return mSyncSet.find(const_cast<Sync *>(sync)) != mSyncSet.end();
1680 }
1681
hasExistingWindowSurface(EGLNativeWindowType window)1682 bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
1683 {
1684 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
1685 ASSERT(windowSurfaces);
1686
1687 return windowSurfaces->find(window) != windowSurfaces->end();
1688 }
1689
GenerateClientExtensions()1690 static ClientExtensions GenerateClientExtensions()
1691 {
1692 ClientExtensions extensions;
1693
1694 extensions.clientExtensions = true;
1695 extensions.platformBase = true;
1696 extensions.platformANGLE = true;
1697
1698 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
1699 extensions.platformANGLED3D = true;
1700 extensions.platformDevice = true;
1701 #endif
1702
1703 #if defined(ANGLE_ENABLE_D3D11)
1704 # if defined(ANGLE_ENABLE_WINDOWS_UWP)
1705 extensions.platformANGLED3D11ON12 = true;
1706 # else
1707 extensions.platformANGLED3D11ON12 = IsWindows10OrGreater();
1708 # endif
1709 #endif
1710
1711 #if defined(ANGLE_ENABLE_OPENGL)
1712 extensions.platformANGLEOpenGL = true;
1713
1714 // Selecting context virtualization is currently only supported in the OpenGL backend.
1715 extensions.platformANGLEContextVirtualization = true;
1716 #endif
1717
1718 #if defined(ANGLE_ENABLE_NULL)
1719 extensions.platformANGLENULL = true;
1720 #endif
1721
1722 #if defined(ANGLE_ENABLE_D3D11)
1723 extensions.deviceCreation = true;
1724 extensions.deviceCreationD3D11 = true;
1725 extensions.experimentalPresentPath = true;
1726 #endif
1727
1728 #if defined(ANGLE_ENABLE_VULKAN)
1729 extensions.platformANGLEVulkan = true;
1730 #endif
1731
1732 #if defined(ANGLE_ENABLE_SWIFTSHADER)
1733 extensions.platformANGLEDeviceTypeSwiftShader = true;
1734 #endif
1735
1736 #if defined(ANGLE_ENABLE_METAL)
1737 extensions.platformANGLEMetal = true;
1738 #endif
1739
1740 #if defined(ANGLE_USE_X11)
1741 extensions.x11Visual = true;
1742 #endif
1743
1744 #if defined(ANGLE_PLATFORM_LINUX)
1745 extensions.platformANGLEDeviceTypeEGLANGLE = true;
1746 #endif
1747
1748 #if (defined(ANGLE_PLATFORM_IOS) && !defined(ANGLE_PLATFORM_MACCATALYST)) || \
1749 (defined(ANGLE_PLATFORM_MACCATALYST) && defined(ANGLE_CPU_ARM64))
1750 extensions.platformANGLEDeviceContextVolatileEagl = true;
1751 #endif
1752
1753 #if defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
1754 extensions.platformANGLEDeviceContextVolatileCgl = true;
1755 #endif
1756
1757 extensions.clientGetAllProcAddresses = true;
1758 extensions.debug = true;
1759 extensions.featureControlANGLE = true;
1760 extensions.deviceQueryEXT = true;
1761
1762 return extensions;
1763 }
1764
1765 template <typename T>
GenerateExtensionsString(const T & extensions)1766 static std::string GenerateExtensionsString(const T &extensions)
1767 {
1768 std::vector<std::string> extensionsVector = extensions.getStrings();
1769
1770 std::ostringstream stream;
1771 std::copy(extensionsVector.begin(), extensionsVector.end(),
1772 std::ostream_iterator<std::string>(stream, " "));
1773 return stream.str();
1774 }
1775
1776 // static
GetClientExtensions()1777 const ClientExtensions &Display::GetClientExtensions()
1778 {
1779 static const ClientExtensions clientExtensions = GenerateClientExtensions();
1780 return clientExtensions;
1781 }
1782
1783 // static
GetClientExtensionString()1784 const std::string &Display::GetClientExtensionString()
1785 {
1786 static const angle::base::NoDestructor<std::string> clientExtensionsString(
1787 GenerateExtensionsString(GetClientExtensions()));
1788 return *clientExtensionsString;
1789 }
1790
initDisplayExtensions()1791 void Display::initDisplayExtensions()
1792 {
1793 mDisplayExtensions = mImplementation->getExtensions();
1794
1795 // Some extensions are always available because they are implemented in the EGL layer.
1796 mDisplayExtensions.createContext = true;
1797 mDisplayExtensions.createContextNoError = true;
1798 mDisplayExtensions.createContextWebGLCompatibility = true;
1799 mDisplayExtensions.createContextBindGeneratesResource = true;
1800 mDisplayExtensions.createContextClientArrays = true;
1801 mDisplayExtensions.pixelFormatFloat = true;
1802 mDisplayExtensions.reusableSyncKHR = true;
1803
1804 // Force EGL_KHR_get_all_proc_addresses on.
1805 mDisplayExtensions.getAllProcAddresses = true;
1806
1807 // Enable program cache control since it is not back-end dependent.
1808 mDisplayExtensions.programCacheControl = true;
1809
1810 // Request extension is implemented in the ANGLE frontend
1811 mDisplayExtensions.createContextExtensionsEnabled = true;
1812
1813 // Blob cache extension is provided by the ANGLE frontend
1814 mDisplayExtensions.blobCache = true;
1815
1816 // The EGL_ANDROID_recordable extension is provided by the ANGLE frontend, and will always
1817 // say that ANativeWindow is not recordable.
1818 mDisplayExtensions.recordable = true;
1819
1820 // All backends support specific context versions
1821 mDisplayExtensions.createContextBackwardsCompatible = true;
1822
1823 // Note: we don't notify the back-end of a change to the renderbuffer right now. This extension
1824 // is implemented only in the front-end. A full implementation involves notifying the back-end.
1825 mDisplayExtensions.mutableRenderBufferKHR = true;
1826
1827 mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions);
1828 }
1829
isValidNativeWindow(EGLNativeWindowType window) const1830 bool Display::isValidNativeWindow(EGLNativeWindowType window) const
1831 {
1832 return mImplementation->isValidNativeWindow(window);
1833 }
1834
validateClientBuffer(const Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const AttributeMap & attribs) const1835 Error Display::validateClientBuffer(const Config *configuration,
1836 EGLenum buftype,
1837 EGLClientBuffer clientBuffer,
1838 const AttributeMap &attribs) const
1839 {
1840 return mImplementation->validateClientBuffer(configuration, buftype, clientBuffer, attribs);
1841 }
1842
validateImageClientBuffer(const gl::Context * context,EGLenum target,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const1843 Error Display::validateImageClientBuffer(const gl::Context *context,
1844 EGLenum target,
1845 EGLClientBuffer clientBuffer,
1846 const egl::AttributeMap &attribs) const
1847 {
1848 return mImplementation->validateImageClientBuffer(context, target, clientBuffer, attribs);
1849 }
1850
valdiatePixmap(const Config * config,EGLNativePixmapType pixmap,const AttributeMap & attributes) const1851 Error Display::valdiatePixmap(const Config *config,
1852 EGLNativePixmapType pixmap,
1853 const AttributeMap &attributes) const
1854 {
1855 return mImplementation->validatePixmap(config, pixmap, attributes);
1856 }
1857
isValidDisplay(const egl::Display * display)1858 bool Display::isValidDisplay(const egl::Display *display)
1859 {
1860 const ANGLEPlatformDisplayMap *anglePlatformDisplayMap = GetANGLEPlatformDisplayMap();
1861 for (const auto &displayPair : *anglePlatformDisplayMap)
1862 {
1863 if (displayPair.second == display)
1864 {
1865 return true;
1866 }
1867 }
1868
1869 const DevicePlatformDisplayMap *devicePlatformDisplayMap = GetDevicePlatformDisplayMap();
1870 for (const auto &displayPair : *devicePlatformDisplayMap)
1871 {
1872 if (displayPair.second == display)
1873 {
1874 return true;
1875 }
1876 }
1877
1878 return false;
1879 }
1880
isValidNativeDisplay(EGLNativeDisplayType display)1881 bool Display::isValidNativeDisplay(EGLNativeDisplayType display)
1882 {
1883 // TODO(jmadill): handle this properly
1884 if (display == EGL_DEFAULT_DISPLAY)
1885 {
1886 return true;
1887 }
1888
1889 #if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_ENABLE_WINDOWS_UWP)
1890 if (display == EGL_SOFTWARE_DISPLAY_ANGLE || display == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
1891 display == EGL_D3D11_ONLY_DISPLAY_ANGLE)
1892 {
1893 return true;
1894 }
1895 return (WindowFromDC(display) != nullptr);
1896 #else
1897 return true;
1898 #endif
1899 }
1900
initVendorString()1901 void Display::initVendorString()
1902 {
1903 mVendorString = "Google Inc.";
1904 std::string vendorStringImpl = mImplementation->getVendorString();
1905 if (!vendorStringImpl.empty())
1906 {
1907 mVendorString += " (" + vendorStringImpl + ")";
1908 }
1909 }
1910
initVersionString()1911 void Display::initVersionString()
1912 {
1913 mVersionString = mImplementation->getVersionString();
1914 }
1915
initializeFrontendFeatures()1916 void Display::initializeFrontendFeatures()
1917 {
1918 // Enable on all Impls
1919 ANGLE_FEATURE_CONDITION((&mFrontendFeatures), loseContextOnOutOfMemory, true);
1920 ANGLE_FEATURE_CONDITION((&mFrontendFeatures), allowCompressedFormats, true);
1921
1922 // No longer enable this on any Impl - crbug.com/1165751
1923 ANGLE_FEATURE_CONDITION((&mFrontendFeatures), scalarizeVecAndMatConstructorArgs, false);
1924
1925 mImplementation->initializeFrontendFeatures(&mFrontendFeatures);
1926
1927 rx::ApplyFeatureOverrides(&mFrontendFeatures, mState);
1928
1929 // Disabled by default. To reduce the risk, create a feature to enable
1930 // compressing pipeline cache in multi-thread pool.
1931 ANGLE_FEATURE_CONDITION(&mFrontendFeatures, enableCompressingPipelineCacheInThreadPool, false);
1932 }
1933
getExtensions() const1934 const DisplayExtensions &Display::getExtensions() const
1935 {
1936 return mDisplayExtensions;
1937 }
1938
getExtensionString() const1939 const std::string &Display::getExtensionString() const
1940 {
1941 return mDisplayExtensionString;
1942 }
1943
getVendorString() const1944 const std::string &Display::getVendorString() const
1945 {
1946 return mVendorString;
1947 }
1948
getVersionString() const1949 const std::string &Display::getVersionString() const
1950 {
1951 return mVersionString;
1952 }
1953
getBackendRendererDescription() const1954 std::string Display::getBackendRendererDescription() const
1955 {
1956 return mImplementation->getRendererDescription();
1957 }
1958
getBackendVendorString() const1959 std::string Display::getBackendVendorString() const
1960 {
1961 return mImplementation->getVendorString();
1962 }
1963
getBackendVersionString() const1964 std::string Display::getBackendVersionString() const
1965 {
1966 return mImplementation->getVersionString();
1967 }
1968
getDevice() const1969 Device *Display::getDevice() const
1970 {
1971 return mDevice;
1972 }
1973
getWGLSurface() const1974 Surface *Display::getWGLSurface() const
1975 {
1976 return mSurface;
1977 }
1978
getMaxSupportedESVersion() const1979 gl::Version Display::getMaxSupportedESVersion() const
1980 {
1981 return mImplementation->getMaxSupportedESVersion();
1982 }
1983
programCacheGetAttrib(EGLenum attrib) const1984 EGLint Display::programCacheGetAttrib(EGLenum attrib) const
1985 {
1986 switch (attrib)
1987 {
1988 case EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE:
1989 return static_cast<EGLint>(BlobCache::kKeyLength);
1990
1991 case EGL_PROGRAM_CACHE_SIZE_ANGLE:
1992 return static_cast<EGLint>(mMemoryProgramCache.entryCount());
1993
1994 default:
1995 UNREACHABLE();
1996 return 0;
1997 }
1998 }
1999
programCacheQuery(EGLint index,void * key,EGLint * keysize,void * binary,EGLint * binarysize)2000 Error Display::programCacheQuery(EGLint index,
2001 void *key,
2002 EGLint *keysize,
2003 void *binary,
2004 EGLint *binarysize)
2005 {
2006 ASSERT(index >= 0 && index < static_cast<EGLint>(mMemoryProgramCache.entryCount()));
2007
2008 const BlobCache::Key *programHash = nullptr;
2009 BlobCache::Value programBinary;
2010 // TODO(jmadill): Make this thread-safe.
2011 bool result =
2012 mMemoryProgramCache.getAt(static_cast<size_t>(index), &programHash, &programBinary);
2013 if (!result)
2014 {
2015 return EglBadAccess() << "Program binary not accessible.";
2016 }
2017
2018 ASSERT(keysize && binarysize);
2019
2020 if (key)
2021 {
2022 ASSERT(*keysize == static_cast<EGLint>(BlobCache::kKeyLength));
2023 memcpy(key, programHash->data(), BlobCache::kKeyLength);
2024 }
2025
2026 if (binary)
2027 {
2028 // Note: we check the size here instead of in the validation code, since we need to
2029 // access the cache as atomically as possible. It's possible that the cache contents
2030 // could change between the validation size check and the retrieval.
2031 if (programBinary.size() > static_cast<size_t>(*binarysize))
2032 {
2033 return EglBadAccess() << "Program binary too large or changed during access.";
2034 }
2035
2036 memcpy(binary, programBinary.data(), programBinary.size());
2037 }
2038
2039 *binarysize = static_cast<EGLint>(programBinary.size());
2040 *keysize = static_cast<EGLint>(BlobCache::kKeyLength);
2041
2042 return NoError();
2043 }
2044
programCachePopulate(const void * key,EGLint keysize,const void * binary,EGLint binarysize)2045 Error Display::programCachePopulate(const void *key,
2046 EGLint keysize,
2047 const void *binary,
2048 EGLint binarysize)
2049 {
2050 ASSERT(keysize == static_cast<EGLint>(BlobCache::kKeyLength));
2051
2052 BlobCache::Key programHash;
2053 memcpy(programHash.data(), key, BlobCache::kKeyLength);
2054
2055 if (!mMemoryProgramCache.putBinary(programHash, reinterpret_cast<const uint8_t *>(binary),
2056 static_cast<size_t>(binarysize)))
2057 {
2058 return EglBadAccess() << "Failed to copy program binary into the cache.";
2059 }
2060
2061 return NoError();
2062 }
2063
programCacheResize(EGLint limit,EGLenum mode)2064 EGLint Display::programCacheResize(EGLint limit, EGLenum mode)
2065 {
2066 switch (mode)
2067 {
2068 case EGL_PROGRAM_CACHE_RESIZE_ANGLE:
2069 {
2070 size_t initialSize = mMemoryProgramCache.size();
2071 mMemoryProgramCache.resize(static_cast<size_t>(limit));
2072 return static_cast<EGLint>(initialSize);
2073 }
2074
2075 case EGL_PROGRAM_CACHE_TRIM_ANGLE:
2076 return static_cast<EGLint>(mMemoryProgramCache.trim(static_cast<size_t>(limit)));
2077
2078 default:
2079 UNREACHABLE();
2080 return 0;
2081 }
2082 }
2083
overrideFrontendFeatures(const std::vector<std::string> & featureNames,bool enabled)2084 void Display::overrideFrontendFeatures(const std::vector<std::string> &featureNames, bool enabled)
2085 {
2086 mFrontendFeatures.overrideFeatures(featureNames, enabled);
2087 }
2088
queryStringi(const EGLint name,const EGLint index)2089 const char *Display::queryStringi(const EGLint name, const EGLint index)
2090 {
2091 const char *result = nullptr;
2092 switch (name)
2093 {
2094 case EGL_FEATURE_NAME_ANGLE:
2095 result = mFeatures[index]->name;
2096 break;
2097 case EGL_FEATURE_CATEGORY_ANGLE:
2098 result = angle::FeatureCategoryToString(mFeatures[index]->category);
2099 break;
2100 case EGL_FEATURE_DESCRIPTION_ANGLE:
2101 result = mFeatures[index]->description;
2102 break;
2103 case EGL_FEATURE_BUG_ANGLE:
2104 result = mFeatures[index]->bug;
2105 break;
2106 case EGL_FEATURE_STATUS_ANGLE:
2107 result = angle::FeatureStatusToString(mFeatures[index]->enabled);
2108 break;
2109 case EGL_FEATURE_CONDITION_ANGLE:
2110 result = mFeatures[index]->condition;
2111 break;
2112 default:
2113 UNREACHABLE();
2114 return nullptr;
2115 }
2116 return result;
2117 }
2118
queryAttrib(const EGLint attribute)2119 EGLAttrib Display::queryAttrib(const EGLint attribute)
2120 {
2121 EGLAttrib value = 0;
2122 switch (attribute)
2123 {
2124 case EGL_DEVICE_EXT:
2125 value = reinterpret_cast<EGLAttrib>(mDevice);
2126 break;
2127
2128 case EGL_FEATURE_COUNT_ANGLE:
2129 value = mFeatures.size();
2130 break;
2131
2132 default:
2133 UNREACHABLE();
2134 }
2135 return value;
2136 }
2137
requestScratchBuffer()2138 angle::ScratchBuffer Display::requestScratchBuffer()
2139 {
2140 return requestScratchBufferImpl(&mScratchBuffers);
2141 }
2142
returnScratchBuffer(angle::ScratchBuffer scratchBuffer)2143 void Display::returnScratchBuffer(angle::ScratchBuffer scratchBuffer)
2144 {
2145 returnScratchBufferImpl(std::move(scratchBuffer), &mScratchBuffers);
2146 }
2147
requestZeroFilledBuffer()2148 angle::ScratchBuffer Display::requestZeroFilledBuffer()
2149 {
2150 return requestScratchBufferImpl(&mZeroFilledBuffers);
2151 }
2152
returnZeroFilledBuffer(angle::ScratchBuffer zeroFilledBuffer)2153 void Display::returnZeroFilledBuffer(angle::ScratchBuffer zeroFilledBuffer)
2154 {
2155 returnScratchBufferImpl(std::move(zeroFilledBuffer), &mZeroFilledBuffers);
2156 }
2157
requestScratchBufferImpl(std::vector<angle::ScratchBuffer> * bufferVector)2158 angle::ScratchBuffer Display::requestScratchBufferImpl(
2159 std::vector<angle::ScratchBuffer> *bufferVector)
2160 {
2161 std::lock_guard<std::mutex> lock(mScratchBufferMutex);
2162 if (!bufferVector->empty())
2163 {
2164 angle::ScratchBuffer buffer = std::move(bufferVector->back());
2165 bufferVector->pop_back();
2166 return buffer;
2167 }
2168
2169 return angle::ScratchBuffer(kScratchBufferLifetime);
2170 }
2171
returnScratchBufferImpl(angle::ScratchBuffer scratchBuffer,std::vector<angle::ScratchBuffer> * bufferVector)2172 void Display::returnScratchBufferImpl(angle::ScratchBuffer scratchBuffer,
2173 std::vector<angle::ScratchBuffer> *bufferVector)
2174 {
2175 std::lock_guard<std::mutex> lock(mScratchBufferMutex);
2176 bufferVector->push_back(std::move(scratchBuffer));
2177 }
2178
handleGPUSwitch()2179 Error Display::handleGPUSwitch()
2180 {
2181 ANGLE_TRY(mImplementation->handleGPUSwitch());
2182 initVendorString();
2183 return NoError();
2184 }
2185
2186 } // namespace egl
2187