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