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