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 <sstream>
16 #include <vector>
17
18 #include <EGL/eglext.h>
19 #include <platform/PlatformMethods.h>
20
21 #include "anglebase/no_destructor.h"
22 #include "common/android_util.h"
23 #include "common/debug.h"
24 #include "common/mathutil.h"
25 #include "common/platform_helpers.h"
26 #include "common/string_utils.h"
27 #include "common/system_utils.h"
28 #include "common/tls.h"
29 #include "common/utilities.h"
30 #include "gpu_info_util/SystemInfo.h"
31 #include "image_util/loadimage.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_PLATFORM_APPLE)
48 # include <dispatch/dispatch.h>
49 # include "common/tls.h"
50 #endif
51
52 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
53 # include "libANGLE/renderer/d3d/DisplayD3D.h"
54 #endif
55
56 #if defined(ANGLE_ENABLE_OPENGL)
57 # if defined(ANGLE_PLATFORM_WINDOWS)
58 # include "libANGLE/renderer/gl/wgl/DisplayWGL.h"
59 # elif ANGLE_ENABLE_CGL
60 # include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
61 # elif ANGLE_ENABLE_EAGL
62 # include "libANGLE/renderer/gl/eagl/DisplayEAGL.h"
63 # elif defined(ANGLE_PLATFORM_LINUX)
64 # include "libANGLE/renderer/gl/egl/DisplayEGL.h"
65 # if defined(ANGLE_USE_X11)
66 # include "libANGLE/renderer/gl/glx/DisplayGLX_api.h"
67 # endif
68 # elif defined(ANGLE_PLATFORM_ANDROID)
69 # include "libANGLE/renderer/gl/egl/android/DisplayAndroid.h"
70 # else
71 # error Unsupported OpenGL platform.
72 # endif
73 #endif
74
75 #if defined(ANGLE_ENABLE_NULL)
76 # include "libANGLE/renderer/null/DisplayNULL.h"
77 #endif // defined(ANGLE_ENABLE_NULL)
78
79 #if defined(ANGLE_ENABLE_WGPU)
80 # include "libANGLE/renderer/wgpu/DisplayWgpu_api.h"
81 #endif
82
83 #if defined(ANGLE_ENABLE_VULKAN)
84 # include "libANGLE/renderer/vulkan/DisplayVk_api.h"
85 #endif // defined(ANGLE_ENABLE_VULKAN)
86
87 #if defined(ANGLE_ENABLE_METAL)
88 # include "libANGLE/renderer/metal/DisplayMtl_api.h"
89 #endif // defined(ANGLE_ENABLE_METAL)
90
91 namespace egl
92 {
93
94 namespace
95 {
96 struct TLSData
97 {
98 angle::UnlockedTailCall unlockedTailCall;
99 Error errorScratchSpace;
100
101 TLSData();
102 };
103
TLSData()104 TLSData::TLSData() : errorScratchSpace(0) {}
105
106 #if defined(ANGLE_PLATFORM_APPLE)
107 // TODO(angleproject:6479): Due to a bug in Apple's dyld loader, `thread_local` will cause
108 // excessive memory use. Temporarily avoid it by using pthread's thread
109 // local storage instead.
GetDisplayTLSIndex()110 static angle::TLSIndex GetDisplayTLSIndex()
111 {
112 static angle::TLSIndex DisplayIndex = TLS_INVALID_INDEX;
113 static dispatch_once_t once;
114 dispatch_once(&once, ^{
115 ASSERT(DisplayIndex == TLS_INVALID_INDEX);
116 DisplayIndex = angle::CreateTLSIndex(nullptr);
117 });
118 return DisplayIndex;
119 }
GetDisplayTLS()120 TLSData *GetDisplayTLS()
121 {
122 angle::TLSIndex DisplayIndex = GetDisplayTLSIndex();
123 ASSERT(DisplayIndex != TLS_INVALID_INDEX);
124 return static_cast<TLSData *>(angle::GetTLSValue(DisplayIndex));
125 }
SetDisplayTLS(TLSData * tlsData)126 void SetDisplayTLS(TLSData *tlsData)
127 {
128 angle::TLSIndex DisplayIndex = GetDisplayTLSIndex();
129 ASSERT(DisplayIndex != TLS_INVALID_INDEX);
130 angle::SetTLSValue(DisplayIndex, tlsData);
131 }
132 #else
133 // Tail calls generated during execution of the entry point, to be run at the end of the entry
134 // point. gTLSData->unlockedTailCall.run() is called at the end of any EGL entry point that is
135 // expected to generate such calls. At the end of every other call, it is asserted that this is
136 // empty.
137 thread_local TLSData *gDisplayTLS = nullptr;
138
GetDisplayTLS()139 TLSData *GetDisplayTLS()
140 {
141 return gDisplayTLS;
142 }
143 #endif
144
145 constexpr angle::SubjectIndex kGPUSwitchedSubjectIndex = 0;
146
147 static constexpr size_t kWindowSurfaceMapSize = 32;
148 typedef angle::FlatUnorderedMap<EGLNativeWindowType, Surface *, kWindowSurfaceMapSize>
149 WindowSurfaceMap;
150 // Get a map of all EGL window surfaces to validate that no window has more than one EGL surface
151 // associated with it.
GetWindowSurfaces()152 static WindowSurfaceMap *GetWindowSurfaces()
153 {
154 static angle::base::NoDestructor<WindowSurfaceMap> windowSurfaces;
155 return windowSurfaces.get();
156 }
157
EGLStringArrayHash(const char ** ary)158 size_t EGLStringArrayHash(const char **ary)
159 {
160 size_t hash = 0;
161 if (ary != nullptr)
162 {
163 for (; *ary != nullptr; ary++)
164 {
165 hash ^= std::hash<std::string>{}(std::string(*ary));
166 }
167 }
168 return hash;
169 }
170
171 struct ANGLEPlatformDisplay
172 {
173 ANGLEPlatformDisplay() = default;
174
ANGLEPlatformDisplayegl::__anonc3e1fa260111::ANGLEPlatformDisplay175 ANGLEPlatformDisplay(EGLNativeDisplayType nativeDisplayType)
176 : nativeDisplayType(nativeDisplayType)
177 {}
178
ANGLEPlatformDisplayegl::__anonc3e1fa260111::ANGLEPlatformDisplay179 ANGLEPlatformDisplay(EGLNativeDisplayType nativeDisplayType,
180 EGLAttrib powerPreference,
181 EGLAttrib platformANGLEType,
182 EGLAttrib deviceIdHigh,
183 EGLAttrib deviceIdLow,
184 EGLAttrib displayKey,
185 EGLAttrib enabledFeatureOverrides,
186 EGLAttrib disabledFeatureOverrides,
187 EGLAttrib disableAllNonOverriddenFeatures)
188 : nativeDisplayType(nativeDisplayType),
189 powerPreference(powerPreference),
190 platformANGLEType(platformANGLEType),
191 deviceIdHigh(deviceIdHigh),
192 deviceIdLow(deviceIdLow),
193 displayKey(displayKey),
194 disableAllNonOverriddenFeatures(static_cast<bool>(disableAllNonOverriddenFeatures))
195 {
196 enabledFeatureOverridesHash =
197 EGLStringArrayHash(reinterpret_cast<const char **>(enabledFeatureOverrides));
198 disabledFeatureOverridesHash =
199 EGLStringArrayHash(reinterpret_cast<const char **>(disabledFeatureOverrides));
200 }
201
tieegl::__anonc3e1fa260111::ANGLEPlatformDisplay202 auto tie() const
203 {
204 return std::tie(nativeDisplayType, powerPreference, platformANGLEType, deviceIdHigh,
205 deviceIdLow, displayKey, enabledFeatureOverridesHash,
206 disabledFeatureOverridesHash, disableAllNonOverriddenFeatures);
207 }
208
209 EGLNativeDisplayType nativeDisplayType{EGL_DEFAULT_DISPLAY};
210 EGLAttrib powerPreference{EGL_LOW_POWER_ANGLE};
211 EGLAttrib platformANGLEType{EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE};
212 EGLAttrib deviceIdHigh{0};
213 EGLAttrib deviceIdLow{0};
214 EGLAttrib displayKey{0};
215 size_t enabledFeatureOverridesHash;
216 size_t disabledFeatureOverridesHash;
217 bool disableAllNonOverriddenFeatures;
218 };
219
operator ==(const ANGLEPlatformDisplay & a,const ANGLEPlatformDisplay & b)220 inline bool operator==(const ANGLEPlatformDisplay &a, const ANGLEPlatformDisplay &b)
221 {
222 return a.tie() == b.tie();
223 }
224
225 static constexpr size_t kANGLEPlatformDisplayMapSize = 9;
226 typedef angle::FlatUnorderedMap<ANGLEPlatformDisplay, Display *, kANGLEPlatformDisplayMapSize>
227 ANGLEPlatformDisplayMap;
GetANGLEPlatformDisplayMap()228 static ANGLEPlatformDisplayMap *GetANGLEPlatformDisplayMap()
229 {
230 static angle::base::NoDestructor<ANGLEPlatformDisplayMap> displays;
231 return displays.get();
232 }
233
234 static constexpr size_t kDevicePlatformDisplayMapSize = 8;
235 typedef angle::FlatUnorderedMap<Device *, Display *, kDevicePlatformDisplayMapSize>
236 DevicePlatformDisplayMap;
GetDevicePlatformDisplayMap()237 static DevicePlatformDisplayMap *GetDevicePlatformDisplayMap()
238 {
239 static angle::base::NoDestructor<DevicePlatformDisplayMap> displays;
240 return displays.get();
241 }
242
CreateDisplayFromDevice(Device * eglDevice,const DisplayState & state)243 rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice, const DisplayState &state)
244 {
245 rx::DisplayImpl *impl = nullptr;
246
247 #if defined(ANGLE_ENABLE_D3D11)
248 if (eglDevice->getExtensions().deviceD3D11)
249 {
250 impl = new rx::DisplayD3D(state);
251 }
252 #endif
253
254 #if defined(ANGLE_ENABLE_D3D9)
255 if (eglDevice->getExtensions().deviceD3D9)
256 {
257 // Currently the only way to get EGLDeviceEXT representing a D3D9 device
258 // is to retrieve one from an already-existing EGLDisplay.
259 // When eglGetPlatformDisplayEXT is called with a D3D9 EGLDeviceEXT,
260 // the already-existing display should be returned.
261 // Therefore this codepath to create a new display from the device
262 // should never be hit.
263 UNREACHABLE();
264 }
265 #endif
266
267 ASSERT(impl != nullptr);
268 return impl;
269 }
270
271 // On platforms with support for multiple back-ends, allow an environment variable to control
272 // the default. This is useful to run angle with benchmarks without having to modify the
273 // benchmark source. Possible values for this environment variable (ANGLE_DEFAULT_PLATFORM)
274 // are: vulkan, gl, d3d11, null.
GetDisplayTypeFromEnvironment()275 EGLAttrib GetDisplayTypeFromEnvironment()
276 {
277 std::string angleDefaultEnv = angle::GetEnvironmentVar("ANGLE_DEFAULT_PLATFORM");
278 angle::ToLower(&angleDefaultEnv);
279
280 #if defined(ANGLE_ENABLE_VULKAN)
281 if ((angleDefaultEnv == "vulkan") || (angleDefaultEnv == "vulkan-null") ||
282 (angleDefaultEnv == "swiftshader"))
283 {
284 return EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
285 }
286 #endif
287
288 #if defined(ANGLE_ENABLE_WGPU)
289 if (angleDefaultEnv == "webgpu")
290 {
291 return EGL_PLATFORM_ANGLE_TYPE_WEBGPU_ANGLE;
292 }
293 #endif
294
295 #if defined(ANGLE_ENABLE_OPENGL)
296 if (angleDefaultEnv == "gl")
297 {
298 return EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
299 }
300 #endif
301
302 #if defined(ANGLE_ENABLE_D3D11)
303 if (angleDefaultEnv == "d3d11")
304 {
305 return EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
306 }
307 #endif
308
309 #if defined(ANGLE_ENABLE_METAL)
310 if (angleDefaultEnv == "metal")
311 {
312 return EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE;
313 }
314 #endif
315
316 #if defined(ANGLE_ENABLE_NULL)
317 if (angleDefaultEnv == "null")
318 {
319 return EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE;
320 }
321 #endif
322 #if defined(ANGLE_ENABLE_D3D11)
323 return EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
324 #elif defined(ANGLE_ENABLE_D3D9)
325 return EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
326 #elif defined(ANGLE_ENABLE_VULKAN) && defined(ANGLE_PLATFORM_ANDROID)
327 return EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
328 #elif defined(ANGLE_ENABLE_OPENGL)
329 # if defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_USE_GBM)
330 return EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
331 # else
332 return EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
333 # endif
334 #elif defined(ANGLE_ENABLE_METAL)
335 return EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE;
336 #elif defined(ANGLE_ENABLE_VULKAN)
337 return EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
338 #elif defined(ANGLE_ENABLE_NULL)
339 return EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE;
340 #else
341 # error No default ANGLE platform type
342 #endif
343 }
344
GetDeviceTypeFromEnvironment()345 EGLAttrib GetDeviceTypeFromEnvironment()
346 {
347 std::string angleDefaultEnv = angle::GetEnvironmentVar("ANGLE_DEFAULT_PLATFORM");
348 angle::ToLower(&angleDefaultEnv);
349
350 #if defined(ANGLE_ENABLE_VULKAN)
351 if (angleDefaultEnv == "vulkan-null")
352 {
353 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE;
354 }
355 else if (angleDefaultEnv == "swiftshader")
356 {
357 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE;
358 }
359 #endif
360 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
361 }
362
GetPlatformTypeFromEnvironment()363 EGLAttrib GetPlatformTypeFromEnvironment()
364 {
365 #if defined(ANGLE_USE_OZONE)
366 return 0;
367 #elif defined(ANGLE_USE_X11)
368 return EGL_PLATFORM_X11_EXT;
369 #elif defined(ANGLE_USE_WAYLAND)
370 return EGL_PLATFORM_WAYLAND_EXT;
371 #elif defined(ANGLE_USE_VULKAN_DISPLAY) && defined(ANGLE_VULKAN_DISPLAY_MODE_SIMPLE)
372 return EGL_PLATFORM_VULKAN_DISPLAY_MODE_SIMPLE_ANGLE;
373 #elif defined(ANGLE_USE_VULKAN_DISPLAY) && defined(ANGLE_VULKAN_DISPLAY_MODE_HEADLESS)
374 return EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE;
375 #else
376 return 0;
377 #endif // defined(ANGLE_USE_OZONE)
378 }
379
CreateDisplayFromAttribs(EGLAttrib displayType,EGLAttrib deviceType,EGLAttrib platformType,const DisplayState & state)380 rx::DisplayImpl *CreateDisplayFromAttribs(EGLAttrib displayType,
381 EGLAttrib deviceType,
382 EGLAttrib platformType,
383 const DisplayState &state)
384 {
385 ASSERT(displayType != EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
386 rx::DisplayImpl *impl = nullptr;
387
388 switch (displayType)
389 {
390 case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
391 UNREACHABLE();
392 break;
393
394 case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
395 case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
396 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
397 impl = new rx::DisplayD3D(state);
398 break;
399 #else
400 // A D3D display was requested on a platform that doesn't support it
401 UNREACHABLE();
402 break;
403 #endif
404
405 case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
406 #if defined(ANGLE_ENABLE_OPENGL)
407 # if defined(ANGLE_PLATFORM_WINDOWS)
408 impl = new rx::DisplayWGL(state);
409 break;
410
411 # elif ANGLE_ENABLE_CGL
412 impl = new rx::DisplayCGL(state);
413 break;
414
415 # elif ANGLE_ENABLE_EAGL
416 impl = new rx::DisplayEAGL(state);
417 break;
418
419 # elif defined(ANGLE_PLATFORM_LINUX)
420 # if defined(ANGLE_USE_GBM)
421 if (platformType == 0)
422 {
423 impl = new rx::DisplayEGL(state);
424 break;
425 }
426 # endif
427 if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE)
428 {
429 impl = new rx::DisplayEGL(state);
430 break;
431 }
432 # if defined(ANGLE_USE_X11)
433 if (platformType == EGL_PLATFORM_X11_EXT)
434 {
435 impl = rx::CreateGLXDisplay(state);
436 break;
437 }
438 # endif
439 if (platformType == EGL_PLATFORM_SURFACELESS_MESA)
440 {
441 impl = new rx::DisplayEGL(state);
442 break;
443 }
444 break;
445
446 # elif defined(ANGLE_PLATFORM_ANDROID)
447 // No GL support on this platform, fail display creation.
448 impl = nullptr;
449 break;
450
451 # else
452 # error Unsupported OpenGL platform.
453 # endif
454 #else
455 // No display available
456 UNREACHABLE();
457 break;
458
459 #endif // defined(ANGLE_ENABLE_OPENGL)
460
461 case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
462 #if defined(ANGLE_ENABLE_OPENGL)
463 # if defined(ANGLE_PLATFORM_WINDOWS)
464 impl = new rx::DisplayWGL(state);
465 # elif defined(ANGLE_PLATFORM_LINUX)
466 # if defined(ANGLE_USE_GBM)
467 if (platformType == 0)
468 {
469 impl = new rx::DisplayEGL(state);
470 break;
471 }
472 # endif
473 if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE)
474 {
475 impl = new rx::DisplayEGL(state);
476 break;
477 }
478 else
479 {
480 # if defined(ANGLE_USE_X11)
481 if (platformType == EGL_PLATFORM_X11_EXT)
482 {
483 impl = rx::CreateGLXDisplay(state);
484 break;
485 }
486 # endif
487 if (platformType == EGL_PLATFORM_SURFACELESS_MESA)
488 {
489 impl = new rx::DisplayEGL(state);
490 break;
491 }
492 }
493 # elif defined(ANGLE_PLATFORM_ANDROID)
494 impl = new rx::DisplayAndroid(state);
495 # else
496 // No GLES support on this platform, fail display creation.
497 impl = nullptr;
498 # endif
499 #endif // defined(ANGLE_ENABLE_OPENGL)
500 break;
501
502 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
503 #if defined(ANGLE_ENABLE_VULKAN)
504 # if defined(ANGLE_USE_VULKAN_NULL_DISPLAY)
505 if (rx::IsVulkanNullDisplayAvailable())
506 {
507 impl = rx::CreateVulkanNullDisplay(state);
508 }
509 break;
510 # elif defined(ANGLE_PLATFORM_WINDOWS)
511 if (rx::IsVulkanWin32DisplayAvailable())
512 {
513 impl = rx::CreateVulkanWin32Display(state);
514 }
515 break;
516 # elif defined(ANGLE_PLATFORM_LINUX)
517 # if defined(ANGLE_USE_GBM)
518 if (platformType == EGL_PLATFORM_GBM_KHR && rx::IsVulkanGbmDisplayAvailable())
519 {
520 impl = rx::CreateVulkanGbmDisplay(state);
521 break;
522 }
523 # endif
524 # if defined(ANGLE_USE_X11)
525 if (platformType == EGL_PLATFORM_X11_EXT && rx::IsVulkanXcbDisplayAvailable())
526 {
527 impl = rx::CreateVulkanXcbDisplay(state);
528 break;
529 }
530 # endif
531 # if defined(ANGLE_USE_WAYLAND)
532 if (platformType == EGL_PLATFORM_WAYLAND_EXT && rx::IsVulkanWaylandDisplayAvailable())
533 {
534 impl = rx::CreateVulkanWaylandDisplay(state);
535 break;
536 }
537 # endif
538 if (platformType == EGL_PLATFORM_SURFACELESS_MESA &&
539 rx::IsVulkanOffscreenDisplayAvailable())
540 {
541 impl = rx::CreateVulkanOffscreenDisplay(state);
542 break;
543 }
544 # if defined(ANGLE_USE_VULKAN_DISPLAY)
545 if (platformType == EGL_PLATFORM_VULKAN_DISPLAY_MODE_SIMPLE_ANGLE &&
546 rx::IsVulkanSimpleDisplayAvailable())
547 {
548 impl = rx::CreateVulkanSimpleDisplay(state);
549 }
550 else if (platformType == EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE &&
551 rx::IsVulkanHeadlessDisplayAvailable())
552 {
553 impl = rx::CreateVulkanHeadlessDisplay(state);
554 }
555 else if (rx::IsVulkanOffscreenDisplayAvailable())
556 {
557 impl = rx::CreateVulkanOffscreenDisplay(state);
558 }
559 else
560 {
561 // Not supported creation type on vulkan display, fail display creation.
562 impl = nullptr;
563 }
564 # endif
565 break;
566 # elif defined(ANGLE_PLATFORM_ANDROID)
567 if (rx::IsVulkanAndroidDisplayAvailable())
568 {
569 impl = rx::CreateVulkanAndroidDisplay(state);
570 }
571 break;
572 # elif defined(ANGLE_PLATFORM_FUCHSIA)
573 if (rx::IsVulkanFuchsiaDisplayAvailable())
574 {
575 impl = rx::CreateVulkanFuchsiaDisplay(state);
576 }
577 break;
578 # elif defined(ANGLE_PLATFORM_GGP)
579 if (rx::IsVulkanGGPDisplayAvailable())
580 {
581 impl = rx::CreateVulkanGGPDisplay(state);
582 }
583 break;
584 # elif defined(ANGLE_PLATFORM_APPLE)
585 if (rx::IsVulkanMacDisplayAvailable())
586 {
587 impl = rx::CreateVulkanMacDisplay(state);
588 }
589 break;
590 # else
591 # error Unsupported Vulkan platform.
592 # endif
593 #else
594 // Vulkan isn't available
595 break;
596 #endif // defined(ANGLE_ENABLE_VULKAN)
597
598 case EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE:
599 #if defined(ANGLE_ENABLE_METAL)
600 if (rx::IsMetalDisplayAvailable())
601 {
602 impl = rx::CreateMetalDisplay(state);
603 break;
604 }
605 #endif
606 // Metal isn't available.
607 break;
608
609 case EGL_PLATFORM_ANGLE_TYPE_WEBGPU_ANGLE:
610 #if defined(ANGLE_ENABLE_WGPU)
611 impl = rx::CreateWgpuDisplay(state);
612 #endif // defined(ANGLE_ENABLE_WGPU)
613 // WebGPU isn't available.
614 break;
615
616 case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE:
617 #if defined(ANGLE_ENABLE_NULL)
618 impl = new rx::DisplayNULL(state);
619 break;
620 #else
621 // No display available
622 UNREACHABLE();
623 break;
624 #endif // defined(ANGLE_ENABLE_NULL)
625
626 default:
627 UNREACHABLE();
628 break;
629 }
630
631 return impl;
632 }
633
Display_logError(angle::PlatformMethods * platform,const char * errorMessage)634 void Display_logError(angle::PlatformMethods *platform, const char *errorMessage)
635 {
636 gl::Trace(gl::LOG_ERR, errorMessage);
637 }
638
Display_logWarning(angle::PlatformMethods * platform,const char * warningMessage)639 void Display_logWarning(angle::PlatformMethods *platform, const char *warningMessage)
640 {
641 gl::Trace(gl::LOG_WARN, warningMessage);
642 }
643
Display_logInfo(angle::PlatformMethods * platform,const char * infoMessage)644 void Display_logInfo(angle::PlatformMethods *platform, const char *infoMessage)
645 {
646 // Uncomment to get info spam
647 #if defined(ANGLE_ENABLE_DEBUG_TRACE)
648 gl::Trace(gl::LOG_INFO, infoMessage);
649 #endif
650 }
651
EGLStringArrayToStringVector(const char ** ary)652 const std::vector<std::string> EGLStringArrayToStringVector(const char **ary)
653 {
654 std::vector<std::string> vec;
655 if (ary != nullptr)
656 {
657 for (; *ary != nullptr; ary++)
658 {
659 vec.push_back(std::string(*ary));
660 }
661 }
662 return vec;
663 }
664
ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display)665 void ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display)
666 {
667 angle::PlatformMethods *platformMethods = ANGLEPlatformCurrent();
668
669 ANGLEResetDisplayPlatform(display);
670 platformMethods->logError = Display_logError;
671 platformMethods->logWarning = Display_logWarning;
672 platformMethods->logInfo = Display_logInfo;
673 }
674
UpdateAttribsFromEnvironment(AttributeMap & attribMap)675 void UpdateAttribsFromEnvironment(AttributeMap &attribMap)
676 {
677 EGLAttrib displayType =
678 attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
679 if (displayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
680 {
681 displayType = GetDisplayTypeFromEnvironment();
682 attribMap.insert(EGL_PLATFORM_ANGLE_TYPE_ANGLE, displayType);
683 }
684 EGLAttrib deviceType = attribMap.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, 0);
685 if (deviceType == 0)
686 {
687 deviceType = GetDeviceTypeFromEnvironment();
688 attribMap.insert(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, deviceType);
689 }
690 EGLAttrib platformType = attribMap.get(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE, 0);
691 if (platformType == 0)
692 {
693 platformType = GetPlatformTypeFromEnvironment();
694 attribMap.insert(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE, platformType);
695 }
696 }
697
698 static constexpr uint32_t kScratchBufferLifetime = 64u;
699
700 } // anonymous namespace
701
702 // DisplayState
DisplayState(EGLNativeDisplayType nativeDisplayId)703 DisplayState::DisplayState(EGLNativeDisplayType nativeDisplayId)
704 : label(nullptr),
705 displayId(nativeDisplayId),
706 singleThreadPool(nullptr),
707 multiThreadPool(nullptr),
708 deviceLost(false)
709 {}
710
~DisplayState()711 DisplayState::~DisplayState() {}
712
notifyDeviceLost() const713 void DisplayState::notifyDeviceLost() const
714 {
715 if (deviceLost)
716 {
717 return;
718 }
719
720 for (auto context = contextMap.begin(); context != contextMap.end(); context++)
721 {
722 context->second->markContextLost(gl::GraphicsResetStatus::UnknownContextReset);
723 }
724
725 deviceLost = true;
726 }
727
728 // Note that ANGLE support on Ozone platform is limited. Our preferred support Matrix for
729 // EGL_ANGLE_platform_angle on Linux and Ozone/Linux/Fuchsia platforms should be the following:
730 //
731 // |--------------------------------------------------------|
732 // | ANGLE type | DEVICE type | PLATFORM type | Display |
733 // |--------------------------------------------------------|
734 // | OPENGL | EGL | ANY | EGL |
735 // | OPENGL | HARDWARE | X11_EXT | GLX |
736 // | OPENGLES | HARDWARE | X11_EXT | GLX |
737 // | OPENGLES | EGL | ANY | EGL |
738 // | VULKAN | HARDWARE | X11_EXT | VkXcb |
739 // | VULKAN | SWIFTSHADER | X11_EXT | VkXcb |
740 // | OPENGLES | HARDWARE | SURFACELESS_MESA | EGL* |
741 // | OPENGLES | HARDWARE | DEVICE_EXT | EGL |
742 // | VULKAN | HARDWARE | SURFACELESS_MESA | VkBase** |
743 // | VULKAN | SWIFTSHADER | SURFACELESS_MESA | VkBase** |
744 // |--------------------------------------------------------|
745 //
746 // * No surfaceless support yet.
747 // ** Not implemented yet.
748 //
749 // |-----------------------------------------------|
750 // | OS | BUILD type | Default PLATFORM type |
751 // |-----------------------------------------------|
752 // | Linux | X11 | X11_EXT |
753 // | Linux | Ozone | SURFACELESS_MESA |
754 // | Fuchsia | Ozone | FUCHSIA*** |
755 // |-----------------------------------------------|
756 //
757 // *** Chosen implicitly. No EGLAttrib available.
758 //
759 // For more details, please refer to
760 // https://docs.google.com/document/d/1XjHiDZQISq1AMrg_l1TX1_kIKvDpU76hidn9i4cAjl8/edit?disco=AAAAJl9V_YY
761 //
762 // static
GetDisplayFromNativeDisplay(EGLenum platform,EGLNativeDisplayType nativeDisplay,const AttributeMap & attribMap)763 Display *Display::GetDisplayFromNativeDisplay(EGLenum platform,
764 EGLNativeDisplayType nativeDisplay,
765 const AttributeMap &attribMap)
766 {
767 Display *display = nullptr;
768
769 AttributeMap updatedAttribMap(attribMap);
770 UpdateAttribsFromEnvironment(updatedAttribMap);
771
772 EGLAttrib powerPreference =
773 updatedAttribMap.get(EGL_POWER_PREFERENCE_ANGLE, EGL_LOW_POWER_ANGLE);
774 EGLAttrib platformANGLEType =
775 updatedAttribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
776 EGLAttrib deviceIdHigh = updatedAttribMap.get(EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE, 0);
777 EGLAttrib deviceIdLow = updatedAttribMap.get(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE, 0);
778 EGLAttrib displayKey = updatedAttribMap.get(EGL_PLATFORM_ANGLE_DISPLAY_KEY_ANGLE, 0);
779 EGLAttrib enabledFeatureOverrides =
780 updatedAttribMap.get(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, 0);
781 EGLAttrib disabledFeatureOverrides =
782 updatedAttribMap.get(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, 0);
783 EGLAttrib disableAllNonOverriddenFeatures =
784 updatedAttribMap.get(EGL_FEATURE_ALL_DISABLED_ANGLE, 0);
785 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
786 ANGLEPlatformDisplay combinedDisplayKey(
787 nativeDisplay, powerPreference, platformANGLEType, deviceIdHigh, deviceIdLow, displayKey,
788 enabledFeatureOverrides, disabledFeatureOverrides, disableAllNonOverriddenFeatures);
789 const auto &iter = displays->find(combinedDisplayKey);
790
791 if (iter != displays->end())
792 {
793 display = iter->second;
794 }
795
796 if (display == nullptr)
797 {
798 // Validate the native display
799 if (!Display::isValidNativeDisplay(nativeDisplay))
800 {
801 return nullptr;
802 }
803
804 display = new Display(platform, nativeDisplay, nullptr);
805 displays->insert(std::make_pair(combinedDisplayKey, display));
806 }
807 // Apply new attributes if the display is not initialized yet.
808 if (!display->isInitialized())
809 {
810 display->setAttributes(updatedAttribMap);
811
812 EGLAttrib displayType = display->mAttributeMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
813 EGLAttrib deviceType = display->mAttributeMap.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
814 EGLAttrib platformType = platform;
815 if (platform == EGL_PLATFORM_ANGLE_ANGLE)
816 {
817 platformType =
818 display->mAttributeMap.get(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE);
819 }
820 rx::DisplayImpl *impl =
821 CreateDisplayFromAttribs(displayType, deviceType, platformType, display->getState());
822 if (impl == nullptr)
823 {
824 // No valid display implementation for these attributes
825 return nullptr;
826 }
827
828 #if defined(ANGLE_USE_ANDROID_TLS_SLOT)
829 angle::gUseAndroidOpenGLTlsSlot = displayType == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
830 #endif // defined(ANGLE_PLATFORM_ANDROID)
831
832 display->setupDisplayPlatform(impl);
833 }
834
835 return display;
836 }
837
838 // static
GetExistingDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay)839 Display *Display::GetExistingDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay)
840 {
841 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
842 const auto &iter = displays->find(nativeDisplay);
843
844 // Check that there is a matching display
845 if (iter == displays->end())
846 {
847 return nullptr;
848 }
849
850 return iter->second;
851 }
852
853 // static
GetDisplayFromDevice(Device * device,const AttributeMap & attribMap)854 Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attribMap)
855 {
856 Display *display = nullptr;
857
858 ASSERT(Device::IsValidDevice(device));
859
860 ANGLEPlatformDisplayMap *anglePlatformDisplays = GetANGLEPlatformDisplayMap();
861 DevicePlatformDisplayMap *devicePlatformDisplays = GetDevicePlatformDisplayMap();
862
863 // First see if this eglDevice is in use by a Display created using ANGLE platform
864 for (auto &displayMapEntry : *anglePlatformDisplays)
865 {
866 egl::Display *iterDisplay = displayMapEntry.second;
867 if (iterDisplay->getDevice() == device)
868 {
869 display = iterDisplay;
870 }
871 }
872
873 if (display == nullptr)
874 {
875 // See if the eglDevice is in use by a Display created using the DEVICE platform
876 const auto &iter = devicePlatformDisplays->find(device);
877 if (iter != devicePlatformDisplays->end())
878 {
879 display = iter->second;
880 }
881 }
882
883 if (display == nullptr)
884 {
885 // Otherwise create a new Display
886 display = new Display(EGL_PLATFORM_DEVICE_EXT, 0, device);
887 devicePlatformDisplays->insert(std::make_pair(device, display));
888 }
889
890 // Apply new attributes if the display is not initialized yet.
891 if (!display->isInitialized())
892 {
893 display->setAttributes(attribMap);
894 rx::DisplayImpl *impl = CreateDisplayFromDevice(device, display->getState());
895 display->setupDisplayPlatform(impl);
896 }
897
898 return display;
899 }
900
901 // static
GetEglDisplaySet()902 Display::EglDisplaySet Display::GetEglDisplaySet()
903 {
904 Display::EglDisplaySet displays;
905
906 ANGLEPlatformDisplayMap *anglePlatformDisplays = GetANGLEPlatformDisplayMap();
907 DevicePlatformDisplayMap *devicePlatformDisplays = GetDevicePlatformDisplayMap();
908
909 for (auto anglePlatformDisplayMapEntry : *anglePlatformDisplays)
910 {
911 displays.insert(anglePlatformDisplayMapEntry.second);
912 }
913
914 for (auto devicePlatformDisplayMapEntry : *devicePlatformDisplays)
915 {
916 displays.insert(devicePlatformDisplayMapEntry.second);
917 }
918
919 return displays;
920 }
921
Display(EGLenum platform,EGLNativeDisplayType displayId,Device * eglDevice)922 Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice)
923 : mState(displayId),
924 mImplementation(nullptr),
925 mGPUSwitchedBinding(this, kGPUSwitchedSubjectIndex),
926 mAttributeMap(),
927 mConfigSet(),
928 mStreamSet(),
929 mInvalidContextMap(),
930 mInvalidImageMap(),
931 mInvalidStreamSet(),
932 mInvalidSurfaceMap(),
933 mInvalidSyncMap(),
934 mInitialized(false),
935 mCaps(),
936 mDisplayExtensions(),
937 mDisplayExtensionString(),
938 mVendorString(),
939 mVersionString(),
940 mDevice(eglDevice),
941 mSurface(nullptr),
942 mPlatform(platform),
943 mManagersMutex(nullptr),
944 mTextureManager(nullptr),
945 mSemaphoreManager(nullptr),
946 mBlobCache(gl::kDefaultMaxProgramCacheMemoryBytes),
947 mMemoryProgramCache(mBlobCache),
948 mMemoryShaderCache(mBlobCache),
949 mGlobalTextureShareGroupUsers(0),
950 mGlobalSemaphoreShareGroupUsers(0),
951 mTerminatedByApi(false)
952 {}
953
~Display()954 Display::~Display()
955 {
956 switch (mPlatform)
957 {
958 case EGL_PLATFORM_ANGLE_ANGLE:
959 case EGL_PLATFORM_GBM_KHR:
960 case EGL_PLATFORM_WAYLAND_EXT:
961 case EGL_PLATFORM_SURFACELESS_MESA:
962 {
963 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
964 ANGLEPlatformDisplayMap::iterator iter = displays->find(ANGLEPlatformDisplay(
965 mState.displayId,
966 mAttributeMap.get(EGL_POWER_PREFERENCE_ANGLE, EGL_LOW_POWER_ANGLE),
967 mAttributeMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE,
968 EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE),
969 mAttributeMap.get(EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE, 0),
970 mAttributeMap.get(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE, 0),
971 mAttributeMap.get(EGL_PLATFORM_ANGLE_DISPLAY_KEY_ANGLE, 0),
972 mAttributeMap.get(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, 0),
973 mAttributeMap.get(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, 0),
974 mAttributeMap.get(EGL_FEATURE_ALL_DISABLED_ANGLE, 0)));
975 if (iter != displays->end())
976 {
977 displays->erase(iter);
978 }
979 break;
980 }
981 case EGL_PLATFORM_DEVICE_EXT:
982 {
983 DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap();
984 DevicePlatformDisplayMap::iterator iter = displays->find(mDevice);
985 if (iter != displays->end())
986 {
987 displays->erase(iter);
988 }
989 break;
990 }
991 default:
992 {
993 UNREACHABLE();
994 }
995 }
996
997 SafeDelete(mDevice);
998 SafeDelete(mImplementation);
999 }
1000
setLabel(EGLLabelKHR label)1001 void Display::setLabel(EGLLabelKHR label)
1002 {
1003 mState.label = label;
1004 }
1005
getLabel() const1006 EGLLabelKHR Display::getLabel() const
1007 {
1008 return mState.label;
1009 }
1010
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)1011 void Display::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
1012 {
1013 ASSERT(index == kGPUSwitchedSubjectIndex);
1014 ASSERT(message == angle::SubjectMessage::SubjectChanged);
1015 for (auto context : mState.contextMap)
1016 {
1017 context.second->onGPUSwitch();
1018 }
1019 }
1020
setupDisplayPlatform(rx::DisplayImpl * impl)1021 void Display::setupDisplayPlatform(rx::DisplayImpl *impl)
1022 {
1023 ASSERT(!mInitialized);
1024
1025 ASSERT(impl != nullptr);
1026 SafeDelete(mImplementation);
1027 mImplementation = impl;
1028
1029 // TODO(anglebug.com/7365): Remove PlatformMethods.
1030 const angle::PlatformMethods *platformMethods =
1031 reinterpret_cast<const angle::PlatformMethods *>(
1032 mAttributeMap.get(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX, 0));
1033 if (platformMethods != nullptr)
1034 {
1035 *ANGLEPlatformCurrent() = *platformMethods;
1036 }
1037 else
1038 {
1039 ANGLESetDefaultDisplayPlatform(this);
1040 }
1041
1042 const char **featuresForceEnabled =
1043 reinterpret_cast<const char **>(mAttributeMap.get(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, 0));
1044 const char **featuresForceDisabled =
1045 reinterpret_cast<const char **>(mAttributeMap.get(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, 0));
1046 mState.featureOverrides.enabled = EGLStringArrayToStringVector(featuresForceEnabled);
1047 mState.featureOverrides.disabled = EGLStringArrayToStringVector(featuresForceDisabled);
1048 mState.featureOverrides.allDisabled =
1049 static_cast<bool>(mAttributeMap.get(EGL_FEATURE_ALL_DISABLED_ANGLE, 0));
1050 mImplementation->addObserver(&mGPUSwitchedBinding);
1051 }
1052
initialize()1053 Error Display::initialize()
1054 {
1055 mTerminatedByApi = false;
1056
1057 ASSERT(mImplementation != nullptr);
1058 mImplementation->setBlobCache(&mBlobCache);
1059
1060 // Enable shader caching if debug layers are turned on. This allows us to test that shaders are
1061 // properly saved & restored on all platforms. The cache won't allocate space until it's used
1062 // and will be ignored entirely if the application / system sets it's own cache functions.
1063 if (rx::ShouldUseDebugLayers(mAttributeMap))
1064 {
1065 mBlobCache.resize(1024 * 1024);
1066 }
1067
1068 setGlobalDebugAnnotator();
1069
1070 gl::InitializeDebugMutexIfNeeded();
1071
1072 ANGLE_TRACE_EVENT0("gpu.angle", "egl::Display::initialize");
1073
1074 if (isInitialized())
1075 {
1076 return NoError();
1077 }
1078
1079 Error error = mImplementation->initialize(this);
1080 if (error.isError())
1081 {
1082 // Log extended error message here
1083 ERR() << "ANGLE Display::initialize error " << error.getID() << ": " << error.getMessage();
1084 return error;
1085 }
1086
1087 mCaps = mImplementation->getCaps();
1088
1089 mConfigSet = mImplementation->generateConfigs();
1090 if (mConfigSet.size() == 0)
1091 {
1092 mImplementation->terminate();
1093 return EglNotInitialized() << "No configs were generated.";
1094 }
1095
1096 // OpenGL ES1 is implemented in the frontend, explicitly add ES1 support to all configs
1097 for (auto &config : mConfigSet)
1098 {
1099 // TODO(geofflang): Enable the conformant bit once we pass enough tests
1100 // config.second.conformant |= EGL_OPENGL_ES_BIT;
1101
1102 config.second.renderableType |= EGL_OPENGL_ES_BIT;
1103
1104 // If we aren't using desktop GL entry points, remove desktop GL support from all configs
1105 #if !defined(ANGLE_ENABLE_GL_DESKTOP_FRONTEND)
1106 config.second.renderableType &= ~EGL_OPENGL_BIT;
1107 #endif
1108 }
1109
1110 mFrontendFeatures.reset();
1111 rx::ApplyFeatureOverrides(&mFrontendFeatures, mState.featureOverrides);
1112 if (!mState.featureOverrides.allDisabled)
1113 {
1114 initializeFrontendFeatures();
1115 }
1116
1117 mFeatures.clear();
1118 mFrontendFeatures.populateFeatureList(&mFeatures);
1119 mImplementation->populateFeatureList(&mFeatures);
1120
1121 initDisplayExtensions();
1122 initVendorString();
1123 initVersionString();
1124 initClientAPIString();
1125
1126 // Populate the Display's EGLDeviceEXT if the Display wasn't created using one
1127 if (mPlatform == EGL_PLATFORM_DEVICE_EXT)
1128 {
1129 // For EGL_PLATFORM_DEVICE_EXT, mDevice should always be populated using
1130 // an external device
1131 ASSERT(mDevice != nullptr);
1132 }
1133 else if (GetClientExtensions().deviceQueryEXT)
1134 {
1135 std::unique_ptr<rx::DeviceImpl> impl(mImplementation->createDevice());
1136 ASSERT(impl);
1137 error = impl->initialize();
1138 if (error.isError())
1139 {
1140 ERR() << "Failed to initialize display because device creation failed: "
1141 << error.getMessage();
1142 mImplementation->terminate();
1143 return error;
1144 }
1145 // Don't leak Device memory.
1146 ASSERT(mDevice == nullptr);
1147 mDevice = new Device(this, impl.release());
1148 }
1149 else
1150 {
1151 mDevice = nullptr;
1152 }
1153
1154 mState.singleThreadPool = angle::WorkerThreadPool::Create(1, ANGLEPlatformCurrent());
1155 mState.multiThreadPool = angle::WorkerThreadPool::Create(0, ANGLEPlatformCurrent());
1156
1157 if (kIsContextMutexEnabled)
1158 {
1159 ASSERT(mManagersMutex == nullptr);
1160 mManagersMutex = new ContextMutex();
1161 mManagersMutex->addRef();
1162 }
1163
1164 mInitialized = true;
1165
1166 return NoError();
1167 }
1168
destroyInvalidEglObjects()1169 Error Display::destroyInvalidEglObjects()
1170 {
1171 // Destroy invalid EGL objects
1172 while (!mInvalidContextMap.empty())
1173 {
1174 gl::Context *context = mInvalidContextMap.begin()->second;
1175 // eglReleaseThread() may call to this method when there are still Contexts, that may
1176 // potentially acces shared state of the "context".
1177 // Need AddRefLock because there may be ContextMutex destruction.
1178 ScopedContextMutexAddRefLock lock(context->getContextMutex());
1179 context->setIsDestroyed();
1180 ANGLE_TRY(releaseContextImpl(context, &mInvalidContextMap));
1181 }
1182
1183 while (!mInvalidImageMap.empty())
1184 {
1185 destroyImageImpl(mInvalidImageMap.begin()->second, &mInvalidImageMap);
1186 }
1187
1188 while (!mInvalidStreamSet.empty())
1189 {
1190 destroyStreamImpl(*mInvalidStreamSet.begin(), &mInvalidStreamSet);
1191 }
1192
1193 while (!mInvalidSurfaceMap.empty())
1194 {
1195 ANGLE_TRY(destroySurfaceImpl(mInvalidSurfaceMap.begin()->second, &mInvalidSurfaceMap));
1196 }
1197
1198 while (!mInvalidSyncMap.empty())
1199 {
1200 destroySyncImpl(mInvalidSyncMap.begin()->second->id(), &mInvalidSyncMap);
1201 }
1202
1203 return NoError();
1204 }
1205
terminate(Thread * thread,TerminateReason terminateReason)1206 Error Display::terminate(Thread *thread, TerminateReason terminateReason)
1207 {
1208 if (terminateReason == TerminateReason::Api)
1209 {
1210 mTerminatedByApi = true;
1211 }
1212
1213 // All subsequent calls assume the display to be valid and terminated by app.
1214 // If it is not terminated or if it isn't even initialized, early return.
1215 if (!mTerminatedByApi || !mInitialized)
1216 {
1217 return NoError();
1218 }
1219
1220 // EGL 1.5 Specification
1221 // 3.2 Initialization
1222 // Termination marks all EGL-specific resources, such as contexts and surfaces, associated
1223 // with the specified display for deletion. Handles to all such resources are invalid as soon
1224 // as eglTerminate returns. Cache EGL objects that are no longer valid.
1225 //
1226 // It is fairly common for apps to call eglTerminate while some contexts and/or surfaces are
1227 // still current on some thread. Since objects are refCounted, trying to destroy them right away
1228 // would only result in a decRef. We instead cache such invalid objects and use other EGL
1229 // entrypoints like eglReleaseThread or thread exit events (on the Android platform) to
1230 // perform the necessary cleanup.
1231 mInvalidImageMap.insert(mImageMap.begin(), mImageMap.end());
1232 mImageMap.clear();
1233
1234 mInvalidStreamSet.insert(mStreamSet.begin(), mStreamSet.end());
1235 mStreamSet.clear();
1236
1237 mInvalidSurfaceMap.insert(mState.surfaceMap.begin(), mState.surfaceMap.end());
1238 mState.surfaceMap.clear();
1239
1240 mInvalidSyncMap.insert(std::make_move_iterator(mSyncMap.begin()),
1241 std::make_move_iterator(mSyncMap.end()));
1242 mSyncMap.clear();
1243
1244 // Cache total number of contexts before invalidation. This is used as a check to verify that
1245 // no context is "lost" while being moved between the various sets.
1246 size_t contextSetSizeBeforeInvalidation = mState.contextMap.size() + mInvalidContextMap.size();
1247
1248 // If app called eglTerminate and no active threads remain,
1249 // force release any context that is still current.
1250 ContextMap contextsStillCurrent = {};
1251 for (auto context : mState.contextMap)
1252 {
1253 if (context.second->isReferenced())
1254 {
1255 contextsStillCurrent.emplace(context);
1256 continue;
1257 }
1258
1259 // Add context that is not current to mInvalidContextSet for cleanup.
1260 mInvalidContextMap.emplace(context);
1261 }
1262
1263 // There are many methods that require contexts that are still current to be present in
1264 // display's contextSet like during context release or to notify of state changes in a subject.
1265 // So as to not interrupt this flow, do not remove contexts that are still current on some
1266 // thread from display's contextSet even though eglTerminate marks such contexts as invalid.
1267 //
1268 // "mState.contextSet" will now contain only those contexts that are still current on some
1269 // thread.
1270 mState.contextMap = std::move(contextsStillCurrent);
1271
1272 // Assert that the total number of contexts is the same before and after context invalidation.
1273 ASSERT(contextSetSizeBeforeInvalidation ==
1274 mState.contextMap.size() + mInvalidContextMap.size());
1275
1276 if (!mState.contextMap.empty())
1277 {
1278 // There was atleast 1 context that was current on some thread, early return.
1279 return NoError();
1280 }
1281
1282 // The global texture and semaphore managers should be deleted with the last context that uses
1283 // it.
1284 ASSERT(mGlobalTextureShareGroupUsers == 0 && mTextureManager == nullptr);
1285 ASSERT(mGlobalSemaphoreShareGroupUsers == 0 && mSemaphoreManager == nullptr);
1286
1287 if (mManagersMutex != nullptr)
1288 {
1289 mManagersMutex->release();
1290 mManagersMutex = nullptr;
1291 }
1292
1293 // Clean up all invalid objects
1294 ANGLE_TRY(destroyInvalidEglObjects());
1295
1296 mSyncPools.clear();
1297
1298 mConfigSet.clear();
1299
1300 if (mDevice != nullptr && mDevice->getOwningDisplay() != nullptr)
1301 {
1302 // Don't delete the device if it was created externally using eglCreateDeviceANGLE
1303 // We also shouldn't set it to null in case eglInitialize() is called again later
1304 SafeDelete(mDevice);
1305 }
1306
1307 // Before tearing down the backend device, ensure all deferred operations are run. It is not
1308 // possible to defer them beyond this point.
1309 GetCurrentThreadUnlockedTailCall()->run(nullptr);
1310
1311 mImplementation->terminate();
1312
1313 mMemoryProgramCache.clear();
1314 mMemoryShaderCache.clear();
1315 mBlobCache.setBlobCacheFuncs(nullptr, nullptr);
1316
1317 mState.singleThreadPool.reset();
1318 mState.multiThreadPool.reset();
1319
1320 mState.deviceLost = false;
1321
1322 mInitialized = false;
1323
1324 gl::UninitializeDebugAnnotations();
1325
1326 // TODO(jmadill): Store Platform in Display and deinit here.
1327 ANGLEResetDisplayPlatform(this);
1328
1329 return NoError();
1330 }
1331
1332 #if ANGLE_USE_DISPLAY_PREPARE_FOR_CALL
prepareForCall()1333 Error Display::prepareForCall()
1334 {
1335 return mImplementation->prepareForCall();
1336 }
1337 #endif
1338
releaseThread()1339 Error Display::releaseThread()
1340 {
1341 // Need to check if initialized, because makeCurrent() may terminate the Display.
1342 if (!mInitialized)
1343 {
1344 return NoError();
1345 }
1346 ANGLE_TRY(mImplementation->releaseThread());
1347 return destroyInvalidEglObjects();
1348 }
1349
getConfigs(const egl::AttributeMap & attribs) const1350 std::vector<const Config *> Display::getConfigs(const egl::AttributeMap &attribs) const
1351 {
1352 return mConfigSet.filter(attribs);
1353 }
1354
chooseConfig(const egl::AttributeMap & attribs) const1355 std::vector<const Config *> Display::chooseConfig(const egl::AttributeMap &attribs) const
1356 {
1357 egl::AttributeMap attribsWithDefaults = AttributeMap();
1358
1359 // Insert default values for attributes that have either an Exact or Mask selection criteria,
1360 // and a default value that matters (e.g. isn't EGL_DONT_CARE):
1361 attribsWithDefaults.insert(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
1362 attribsWithDefaults.insert(EGL_LEVEL, 0);
1363 attribsWithDefaults.insert(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT);
1364 attribsWithDefaults.insert(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
1365 attribsWithDefaults.insert(EGL_TRANSPARENT_TYPE, EGL_NONE);
1366 if (getExtensions().pixelFormatFloat)
1367 {
1368 attribsWithDefaults.insert(EGL_COLOR_COMPONENT_TYPE_EXT,
1369 EGL_COLOR_COMPONENT_TYPE_FIXED_EXT);
1370 }
1371
1372 // Add the caller-specified values (Note: the poorly-named insert() method will replace any
1373 // of the default values from above):
1374 for (auto attribIter = attribs.begin(); attribIter != attribs.end(); attribIter++)
1375 {
1376 attribsWithDefaults.insert(attribIter->first, attribIter->second);
1377 }
1378
1379 return mConfigSet.filter(attribsWithDefaults);
1380 }
1381
createWindowSurface(const Config * configuration,EGLNativeWindowType window,const AttributeMap & attribs,Surface ** outSurface)1382 Error Display::createWindowSurface(const Config *configuration,
1383 EGLNativeWindowType window,
1384 const AttributeMap &attribs,
1385 Surface **outSurface)
1386 {
1387 if (mImplementation->testDeviceLost())
1388 {
1389 ANGLE_TRY(restoreLostDevice());
1390 }
1391
1392 SurfaceID id = {mSurfaceHandleAllocator.allocate()};
1393 SurfacePointer surface(new WindowSurface(mImplementation, id, configuration, window, attribs,
1394 mFrontendFeatures.forceRobustResourceInit.enabled),
1395 this);
1396 ANGLE_TRY(surface->initialize(this));
1397
1398 ASSERT(outSurface != nullptr);
1399 *outSurface = surface.release();
1400 mState.surfaceMap.insert(std::pair((*outSurface)->id().value, *outSurface));
1401
1402 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
1403 ASSERT(windowSurfaces && windowSurfaces->find(window) == windowSurfaces->end());
1404 windowSurfaces->insert(std::make_pair(window, *outSurface));
1405
1406 mSurface = *outSurface;
1407
1408 return NoError();
1409 }
1410
createPbufferSurface(const Config * configuration,const AttributeMap & attribs,Surface ** outSurface)1411 Error Display::createPbufferSurface(const Config *configuration,
1412 const AttributeMap &attribs,
1413 Surface **outSurface)
1414 {
1415 ASSERT(isInitialized());
1416
1417 if (mImplementation->testDeviceLost())
1418 {
1419 ANGLE_TRY(restoreLostDevice());
1420 }
1421
1422 SurfaceID id = {mSurfaceHandleAllocator.allocate()};
1423 SurfacePointer surface(new PbufferSurface(mImplementation, id, configuration, attribs,
1424 mFrontendFeatures.forceRobustResourceInit.enabled),
1425 this);
1426 ANGLE_TRY(surface->initialize(this));
1427
1428 ASSERT(outSurface != nullptr);
1429 *outSurface = surface.release();
1430 mState.surfaceMap.insert(std::pair((*outSurface)->id().value, *outSurface));
1431
1432 return NoError();
1433 }
1434
createPbufferFromClientBuffer(const Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const AttributeMap & attribs,Surface ** outSurface)1435 Error Display::createPbufferFromClientBuffer(const Config *configuration,
1436 EGLenum buftype,
1437 EGLClientBuffer clientBuffer,
1438 const AttributeMap &attribs,
1439 Surface **outSurface)
1440 {
1441 ASSERT(isInitialized());
1442
1443 if (mImplementation->testDeviceLost())
1444 {
1445 ANGLE_TRY(restoreLostDevice());
1446 }
1447
1448 SurfaceID id = {mSurfaceHandleAllocator.allocate()};
1449 SurfacePointer surface(
1450 new PbufferSurface(mImplementation, id, configuration, buftype, clientBuffer, attribs,
1451 mFrontendFeatures.forceRobustResourceInit.enabled),
1452 this);
1453 ANGLE_TRY(surface->initialize(this));
1454
1455 ASSERT(outSurface != nullptr);
1456 *outSurface = surface.release();
1457 mState.surfaceMap.insert(std::pair((*outSurface)->id().value, *outSurface));
1458
1459 return NoError();
1460 }
1461
createPixmapSurface(const Config * configuration,NativePixmapType nativePixmap,const AttributeMap & attribs,Surface ** outSurface)1462 Error Display::createPixmapSurface(const Config *configuration,
1463 NativePixmapType nativePixmap,
1464 const AttributeMap &attribs,
1465 Surface **outSurface)
1466 {
1467 ASSERT(isInitialized());
1468
1469 if (mImplementation->testDeviceLost())
1470 {
1471 ANGLE_TRY(restoreLostDevice());
1472 }
1473
1474 SurfaceID id = {mSurfaceHandleAllocator.allocate()};
1475 SurfacePointer surface(
1476 new PixmapSurface(mImplementation, id, configuration, nativePixmap, attribs,
1477 mFrontendFeatures.forceRobustResourceInit.enabled),
1478 this);
1479 ANGLE_TRY(surface->initialize(this));
1480
1481 ASSERT(outSurface != nullptr);
1482 *outSurface = surface.release();
1483 mState.surfaceMap.insert(std::pair((*outSurface)->id().value, *outSurface));
1484
1485 return NoError();
1486 }
1487
createImage(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs,Image ** outImage)1488 Error Display::createImage(const gl::Context *context,
1489 EGLenum target,
1490 EGLClientBuffer buffer,
1491 const AttributeMap &attribs,
1492 Image **outImage)
1493 {
1494 ASSERT(isInitialized());
1495
1496 if (mImplementation->testDeviceLost())
1497 {
1498 ANGLE_TRY(restoreLostDevice());
1499 }
1500
1501 egl::ImageSibling *sibling = nullptr;
1502 if (IsTextureTarget(target))
1503 {
1504 sibling = context->getTexture({egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
1505 }
1506 else if (IsRenderbufferTarget(target))
1507 {
1508 sibling = context->getRenderbuffer({egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
1509 }
1510 else if (IsExternalImageTarget(target))
1511 {
1512 sibling = new ExternalImageSibling(mImplementation, context, target, buffer, attribs);
1513 }
1514 else
1515 {
1516 UNREACHABLE();
1517 }
1518 ASSERT(sibling != nullptr);
1519
1520 ImageID id = {mImageHandleAllocator.allocate()};
1521 angle::UniqueObjectPointer<Image, Display> imagePtr(
1522 new Image(mImplementation, id, context, target, sibling, attribs), this);
1523 ANGLE_TRY(imagePtr->initialize(this, context));
1524
1525 Image *image = imagePtr.release();
1526
1527 ASSERT(outImage != nullptr);
1528 *outImage = image;
1529
1530 // Add this image to the list of all images and hold a ref to it.
1531 image->addRef();
1532 mImageMap.insert(std::pair(image->id().value, image));
1533
1534 return NoError();
1535 }
1536
createStream(const AttributeMap & attribs,Stream ** outStream)1537 Error Display::createStream(const AttributeMap &attribs, Stream **outStream)
1538 {
1539 ASSERT(isInitialized());
1540
1541 Stream *stream = new Stream(this, attribs);
1542
1543 ASSERT(stream != nullptr);
1544 mStreamSet.insert(stream);
1545
1546 ASSERT(outStream != nullptr);
1547 *outStream = stream;
1548
1549 return NoError();
1550 }
1551
createContext(const Config * configuration,gl::Context * shareContext,EGLenum clientType,const AttributeMap & attribs,gl::Context ** outContext)1552 Error Display::createContext(const Config *configuration,
1553 gl::Context *shareContext,
1554 EGLenum clientType,
1555 const AttributeMap &attribs,
1556 gl::Context **outContext)
1557 {
1558 ASSERT(!mTerminatedByApi);
1559 ASSERT(isInitialized());
1560
1561 if (mImplementation->testDeviceLost())
1562 {
1563 ANGLE_TRY(restoreLostDevice());
1564 }
1565
1566 // This display texture sharing will allow the first context to create the texture share group.
1567 bool usingDisplayTextureShareGroup =
1568 attribs.get(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE;
1569 gl::TextureManager *shareTextures = nullptr;
1570
1571 if (usingDisplayTextureShareGroup)
1572 {
1573 ASSERT((mTextureManager == nullptr) == (mGlobalTextureShareGroupUsers == 0));
1574 if (mTextureManager == nullptr)
1575 {
1576 mTextureManager = new gl::TextureManager();
1577 }
1578
1579 mGlobalTextureShareGroupUsers++;
1580 shareTextures = mTextureManager;
1581 }
1582
1583 // This display semaphore sharing will allow the first context to create the semaphore share
1584 // group.
1585 bool usingDisplaySemaphoreShareGroup =
1586 attribs.get(EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE;
1587 gl::SemaphoreManager *shareSemaphores = nullptr;
1588 if (usingDisplaySemaphoreShareGroup)
1589 {
1590 ASSERT((mSemaphoreManager == nullptr) == (mGlobalSemaphoreShareGroupUsers == 0));
1591 if (mSemaphoreManager == nullptr)
1592 {
1593 mSemaphoreManager = new gl::SemaphoreManager();
1594 }
1595
1596 mGlobalSemaphoreShareGroupUsers++;
1597 shareSemaphores = mSemaphoreManager;
1598 }
1599
1600 ScopedContextMutexLock mutexLock;
1601 ContextMutex *sharedContextMutex = nullptr;
1602 if (kIsContextMutexEnabled)
1603 {
1604 ASSERT(mManagersMutex != nullptr);
1605 if (shareContext != nullptr)
1606 {
1607 sharedContextMutex = shareContext->getContextMutex().getRoot();
1608 }
1609 else if (shareTextures != nullptr || shareSemaphores != nullptr)
1610 {
1611 mutexLock = ScopedContextMutexLock(mManagersMutex);
1612 sharedContextMutex = mManagersMutex->getRoot();
1613 }
1614 // When using shareTextures/Semaphores all Contexts in the Group must use mManagersMutex.
1615 ASSERT((shareTextures == nullptr && shareSemaphores == nullptr) ||
1616 sharedContextMutex == mManagersMutex->getRoot());
1617 }
1618
1619 gl::MemoryProgramCache *programCachePointer = &mMemoryProgramCache;
1620 // Check context creation attributes to see if we are using EGL_ANGLE_program_cache_control.
1621 // If not, keep caching enabled for EGL_ANDROID_blob_cache, which can have its callbacks set
1622 // at any time.
1623 bool usesProgramCacheControl = attribs.contains(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE);
1624 if (usesProgramCacheControl)
1625 {
1626 bool programCacheControlEnabled =
1627 (attribs.get(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE, GL_FALSE) == GL_TRUE);
1628 // A program cache size of zero indicates it should be disabled.
1629 if (!programCacheControlEnabled || mMemoryProgramCache.maxSize() == 0)
1630 {
1631 programCachePointer = nullptr;
1632 }
1633 }
1634
1635 gl::MemoryShaderCache *shaderCachePointer = &mMemoryShaderCache;
1636 // Check if shader caching frontend feature is enabled.
1637 if (!mFrontendFeatures.cacheCompiledShader.enabled)
1638 {
1639 shaderCachePointer = nullptr;
1640 }
1641
1642 gl::Context *context =
1643 new gl::Context(this, configuration, shareContext, shareTextures, shareSemaphores,
1644 sharedContextMutex, programCachePointer, shaderCachePointer, clientType,
1645 attribs, mDisplayExtensions, GetClientExtensions());
1646 Error error = context->initialize();
1647 if (error.isError())
1648 {
1649 delete context;
1650 return error;
1651 }
1652
1653 if (shareContext != nullptr)
1654 {
1655 shareContext->setShared();
1656 }
1657
1658 ASSERT(context != nullptr);
1659 mState.contextMap.insert(std::pair(context->id().value, context));
1660
1661 ASSERT(outContext != nullptr);
1662 *outContext = context;
1663 return NoError();
1664 }
1665
createSync(const gl::Context * currentContext,EGLenum type,const AttributeMap & attribs,Sync ** outSync)1666 Error Display::createSync(const gl::Context *currentContext,
1667 EGLenum type,
1668 const AttributeMap &attribs,
1669 Sync **outSync)
1670 {
1671 ASSERT(isInitialized());
1672
1673 SyncID id = {mSyncHandleAllocator.allocate()};
1674
1675 if (mImplementation->testDeviceLost())
1676 {
1677 ANGLE_TRY(restoreLostDevice());
1678 }
1679
1680 std::unique_ptr<Sync> sync;
1681
1682 SyncPool &pool = mSyncPools[type];
1683 if (!pool.empty())
1684 {
1685 sync = std::move(pool.back());
1686 pool.pop_back();
1687 }
1688 else
1689 {
1690 sync.reset(new Sync(mImplementation, type));
1691 }
1692
1693 Error err = sync->initialize(this, currentContext, id, attribs);
1694 if (err.isError())
1695 {
1696 sync->onDestroy(this);
1697 return err;
1698 }
1699
1700 *outSync = sync.get();
1701 mSyncMap.insert(std::pair(id.value, std::move(sync)));
1702
1703 return NoError();
1704 }
1705
makeCurrent(Thread * thread,gl::Context * previousContext,egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)1706 Error Display::makeCurrent(Thread *thread,
1707 gl::Context *previousContext,
1708 egl::Surface *drawSurface,
1709 egl::Surface *readSurface,
1710 gl::Context *context)
1711 {
1712 if (!mInitialized)
1713 {
1714 return NoError();
1715 }
1716
1717 bool contextChanged = context != previousContext;
1718 if (previousContext != nullptr && contextChanged)
1719 {
1720 // Need AddRefLock because there may be ContextMutex destruction.
1721 ScopedContextMutexAddRefLock lock(previousContext->getContextMutex());
1722
1723 previousContext->release();
1724 thread->setCurrent(nullptr);
1725
1726 auto error = previousContext->unMakeCurrent(this);
1727 if (!previousContext->isReferenced() && previousContext->isDestroyed())
1728 {
1729 // The previous Context may have been created with a different Display.
1730 Display *previousDisplay = previousContext->getDisplay();
1731 ANGLE_TRY(previousDisplay->releaseContext(previousContext, thread));
1732 }
1733 ANGLE_TRY(error);
1734 }
1735
1736 {
1737 ScopedContextMutexLock lock(context != nullptr ? &context->getContextMutex() : nullptr);
1738
1739 thread->setCurrent(context);
1740
1741 ANGLE_TRY(mImplementation->makeCurrent(this, drawSurface, readSurface, context));
1742
1743 if (context != nullptr)
1744 {
1745 ANGLE_TRY(context->makeCurrent(this, drawSurface, readSurface));
1746 if (contextChanged)
1747 {
1748 context->addRef();
1749 }
1750 }
1751 }
1752
1753 // Tick all the scratch buffers to make sure they get cleaned up eventually if they stop being
1754 // used.
1755 {
1756 std::lock_guard<angle::SimpleMutex> lock(mScratchBufferMutex);
1757
1758 for (angle::ScratchBuffer &scatchBuffer : mScratchBuffers)
1759 {
1760 scatchBuffer.tick();
1761 }
1762 for (angle::ScratchBuffer &zeroFilledBuffer : mZeroFilledBuffers)
1763 {
1764 zeroFilledBuffer.tick();
1765 }
1766 }
1767
1768 // If eglTerminate() has previously been called and Context was changed, perform InternalCleanup
1769 // to invalidate any non-current Contexts, and possibly fully terminate the Display and release
1770 // all of its resources.
1771 if (mTerminatedByApi && contextChanged)
1772 {
1773 return terminate(thread, TerminateReason::InternalCleanup);
1774 }
1775
1776 return NoError();
1777 }
1778
restoreLostDevice()1779 Error Display::restoreLostDevice()
1780 {
1781 for (ContextMap::iterator ctx = mState.contextMap.begin(); ctx != mState.contextMap.end();
1782 ctx++)
1783 {
1784 if (ctx->second->isResetNotificationEnabled())
1785 {
1786 // If reset notifications have been requested, application must delete all contexts
1787 // first
1788 return EglContextLost();
1789 }
1790 }
1791
1792 return mImplementation->restoreLostDevice(this);
1793 }
1794
destroySurfaceImpl(Surface * surface,SurfaceMap * surfaces)1795 Error Display::destroySurfaceImpl(Surface *surface, SurfaceMap *surfaces)
1796 {
1797 if (surface->getType() == EGL_WINDOW_BIT)
1798 {
1799 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
1800 ASSERT(windowSurfaces);
1801
1802 bool surfaceRemoved = false;
1803 for (WindowSurfaceMap::iterator iter = windowSurfaces->begin();
1804 iter != windowSurfaces->end(); iter++)
1805 {
1806 if (iter->second == surface)
1807 {
1808 windowSurfaces->erase(iter);
1809 surfaceRemoved = true;
1810 break;
1811 }
1812 }
1813
1814 ASSERT(surfaceRemoved);
1815 }
1816
1817 auto iter = surfaces->find(surface->id().value);
1818 ASSERT(iter != surfaces->end());
1819 mSurfaceHandleAllocator.release(surface->id().value);
1820 surfaces->erase(iter);
1821 ANGLE_TRY(surface->onDestroy(this));
1822 return NoError();
1823 }
1824
destroyImageImpl(Image * image,ImageMap * images)1825 void Display::destroyImageImpl(Image *image, ImageMap *images)
1826 {
1827 auto iter = images->find(image->id().value);
1828 ASSERT(iter != images->end());
1829 mImageHandleAllocator.release(image->id().value);
1830 {
1831 // Need AddRefLock because there may be ContextMutex destruction.
1832 ScopedContextMutexAddRefLock lock(image->getContextMutex());
1833 iter->second->release(this);
1834 }
1835 images->erase(iter);
1836 }
1837
destroyStreamImpl(Stream * stream,StreamSet * streams)1838 void Display::destroyStreamImpl(Stream *stream, StreamSet *streams)
1839 {
1840 streams->erase(stream);
1841 SafeDelete(stream);
1842 }
1843
1844 // releaseContext must be called with the context being deleted as current.
1845 // To do that we can only call this in two places, Display::makeCurrent at the point where this
1846 // context is being made uncurrent and in Display::destroyContext where we make the context current
1847 // as part of destruction.
releaseContext(gl::Context * context,Thread * thread)1848 Error Display::releaseContext(gl::Context *context, Thread *thread)
1849 {
1850 return releaseContextImpl(context, &mState.contextMap);
1851 }
1852
releaseContextImpl(gl::Context * context,ContextMap * contexts)1853 Error Display::releaseContextImpl(gl::Context *context, ContextMap *contexts)
1854 {
1855 ASSERT(!context->isReferenced());
1856
1857 // Use scoped_ptr to make sure the context is always freed.
1858 std::unique_ptr<gl::Context> unique_context(context);
1859 ASSERT(contexts->find(context->id().value) != contexts->end());
1860 contexts->erase(context->id().value);
1861
1862 if (context->usingDisplayTextureShareGroup())
1863 {
1864 ASSERT(mGlobalTextureShareGroupUsers >= 1 && mTextureManager != nullptr);
1865 if (mGlobalTextureShareGroupUsers == 1)
1866 {
1867 // If this is the last context using the global share group, destroy the global
1868 // texture manager so that the textures can be destroyed while a context still
1869 // exists
1870 mTextureManager->release(context);
1871 mTextureManager = nullptr;
1872 }
1873 mGlobalTextureShareGroupUsers--;
1874 }
1875
1876 if (context->usingDisplaySemaphoreShareGroup())
1877 {
1878 ASSERT(mGlobalSemaphoreShareGroupUsers >= 1 && mSemaphoreManager != nullptr);
1879 if (mGlobalSemaphoreShareGroupUsers == 1)
1880 {
1881 // If this is the last context using the global share group, destroy the global
1882 // semaphore manager so that the semaphores can be destroyed while a context still
1883 // exists
1884 mSemaphoreManager->release(context);
1885 mSemaphoreManager = nullptr;
1886 }
1887 mGlobalSemaphoreShareGroupUsers--;
1888 }
1889
1890 ANGLE_TRY(context->onDestroy(this));
1891
1892 return NoError();
1893 }
1894
destroyContext(Thread * thread,gl::Context * context)1895 Error Display::destroyContext(Thread *thread, gl::Context *context)
1896 {
1897 auto *currentContext = thread->getContext();
1898 auto *currentDrawSurface = thread->getCurrentDrawSurface();
1899 auto *currentReadSurface = thread->getCurrentReadSurface();
1900
1901 context->setIsDestroyed();
1902
1903 // If the context is still current on at least 1 thread, just return since it'll be released
1904 // once no threads have it current anymore.
1905 if (context->isReferenced())
1906 {
1907 return NoError();
1908 }
1909
1910 // For external context, we cannot change the current native context, and the API user should
1911 // make sure the native context is current.
1912 if (context->isExternal())
1913 {
1914 // Need AddRefLock because there may be ContextMutex destruction.
1915 ScopedContextMutexAddRefLock lock(context->getContextMutex());
1916 ANGLE_TRY(releaseContext(context, thread));
1917 }
1918 else
1919 {
1920 // Keep |currentContext| alive, while releasing |context|.
1921 gl::ScopedContextRef scopedContextRef(currentContext);
1922
1923 // keep |currentDrawSurface| and |currentReadSurface| alive as well
1924 // while releasing |context|.
1925 ScopedSurfaceRef drawSurfaceRef(currentDrawSurface);
1926 ScopedSurfaceRef readSurfaceRef(
1927 currentReadSurface == currentDrawSurface ? nullptr : currentReadSurface);
1928
1929 // Make the context current, so we can release resources belong to the context, and then
1930 // when context is released from the current, it will be destroyed.
1931 // TODO(http://www.anglebug.com/6322): Don't require a Context to be current in order to
1932 // destroy it.
1933 ANGLE_TRY(makeCurrent(thread, currentContext, nullptr, nullptr, context));
1934 ANGLE_TRY(
1935 makeCurrent(thread, context, currentDrawSurface, currentReadSurface, currentContext));
1936 }
1937
1938 return NoError();
1939 }
1940
destroySyncImpl(SyncID syncId,SyncMap * syncs)1941 void Display::destroySyncImpl(SyncID syncId, SyncMap *syncs)
1942 {
1943 auto iter = syncs->find(syncId.value);
1944 ASSERT(iter != syncs->end());
1945 mSyncHandleAllocator.release(syncId.value);
1946
1947 auto &sync = iter->second;
1948 sync->onDestroy(this);
1949
1950 SyncPool &pool = mSyncPools[sync->getType()];
1951 if (pool.size() < kMaxSyncPoolSizePerType)
1952 {
1953 pool.push_back(std::move(sync));
1954 }
1955
1956 syncs->erase(iter);
1957 }
1958
destroyImage(Image * image)1959 void Display::destroyImage(Image *image)
1960 {
1961 return destroyImageImpl(image, &mImageMap);
1962 }
1963
destroyStream(Stream * stream)1964 void Display::destroyStream(Stream *stream)
1965 {
1966 return destroyStreamImpl(stream, &mStreamSet);
1967 }
1968
destroySurface(Surface * surface)1969 Error Display::destroySurface(Surface *surface)
1970 {
1971 return destroySurfaceImpl(surface, &mState.surfaceMap);
1972 }
1973
destroySync(Sync * sync)1974 void Display::destroySync(Sync *sync)
1975 {
1976 return destroySyncImpl(sync->id(), &mSyncMap);
1977 }
1978
isDeviceLost() const1979 bool Display::isDeviceLost() const
1980 {
1981 ASSERT(isInitialized());
1982 return mState.deviceLost;
1983 }
1984
testDeviceLost()1985 bool Display::testDeviceLost()
1986 {
1987 ASSERT(isInitialized());
1988
1989 if (!mState.deviceLost && mImplementation->testDeviceLost())
1990 {
1991 notifyDeviceLost();
1992 }
1993
1994 return mState.deviceLost;
1995 }
1996
notifyDeviceLost()1997 void Display::notifyDeviceLost()
1998 {
1999 mState.notifyDeviceLost();
2000 }
2001
setBlobCacheFuncs(EGLSetBlobFuncANDROID set,EGLGetBlobFuncANDROID get)2002 void Display::setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get)
2003 {
2004 mBlobCache.setBlobCacheFuncs(set, get);
2005 mImplementation->setBlobCacheFuncs(set, get);
2006 }
2007
2008 // static
GetNativeClientBuffer(const AHardwareBuffer * buffer)2009 EGLClientBuffer Display::GetNativeClientBuffer(const AHardwareBuffer *buffer)
2010 {
2011 return angle::android::AHardwareBufferToClientBuffer(buffer);
2012 }
2013
2014 // static
CreateNativeClientBuffer(const egl::AttributeMap & attribMap,EGLClientBuffer * eglClientBuffer)2015 Error Display::CreateNativeClientBuffer(const egl::AttributeMap &attribMap,
2016 EGLClientBuffer *eglClientBuffer)
2017 {
2018 int androidHardwareBufferFormat = gl::GetAndroidHardwareBufferFormatFromChannelSizes(attribMap);
2019 int width = attribMap.getAsInt(EGL_WIDTH, 0);
2020 int height = attribMap.getAsInt(EGL_HEIGHT, 0);
2021 int usage = attribMap.getAsInt(EGL_NATIVE_BUFFER_USAGE_ANDROID, 0);
2022
2023 // https://developer.android.com/ndk/reference/group/a-hardware-buffer#ahardwarebuffer_lock
2024 // for AHardwareBuffer_lock()
2025 // The passed AHardwareBuffer must have one layer, otherwise the call will fail.
2026 constexpr int kLayerCount = 1;
2027
2028 *eglClientBuffer = angle::android::CreateEGLClientBufferFromAHardwareBuffer(
2029 width, height, kLayerCount, androidHardwareBufferFormat, usage);
2030
2031 return (*eglClientBuffer == nullptr)
2032 ? egl::EglBadParameter() << "native client buffer allocation failed."
2033 : NoError();
2034 }
2035
waitClient(const gl::Context * context)2036 Error Display::waitClient(const gl::Context *context)
2037 {
2038 return mImplementation->waitClient(context);
2039 }
2040
waitNative(const gl::Context * context,EGLint engine)2041 Error Display::waitNative(const gl::Context *context, EGLint engine)
2042 {
2043 return mImplementation->waitNative(context, engine);
2044 }
2045
getCaps() const2046 const Caps &Display::getCaps() const
2047 {
2048 return mCaps;
2049 }
2050
isInitialized() const2051 bool Display::isInitialized() const
2052 {
2053 return mInitialized;
2054 }
2055
isValidConfig(const Config * config) const2056 bool Display::isValidConfig(const Config *config) const
2057 {
2058 return mConfigSet.contains(config);
2059 }
2060
isValidContext(const gl::ContextID contextID) const2061 bool Display::isValidContext(const gl::ContextID contextID) const
2062 {
2063 return getContext(contextID) != nullptr;
2064 }
2065
isValidSurface(SurfaceID surfaceID) const2066 bool Display::isValidSurface(SurfaceID surfaceID) const
2067 {
2068 return getSurface(surfaceID) != nullptr;
2069 }
2070
isValidImage(ImageID imageID) const2071 bool Display::isValidImage(ImageID imageID) const
2072 {
2073 return getImage(imageID) != nullptr;
2074 }
2075
isValidStream(const Stream * stream) const2076 bool Display::isValidStream(const Stream *stream) const
2077 {
2078 return mStreamSet.find(const_cast<Stream *>(stream)) != mStreamSet.end();
2079 }
2080
isValidSync(SyncID syncID) const2081 bool Display::isValidSync(SyncID syncID) const
2082 {
2083 return getSync(syncID) != nullptr;
2084 }
2085
hasExistingWindowSurface(EGLNativeWindowType window)2086 bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
2087 {
2088 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
2089 ASSERT(windowSurfaces);
2090
2091 return windowSurfaces->find(window) != windowSurfaces->end();
2092 }
2093
GenerateClientExtensions()2094 static ClientExtensions GenerateClientExtensions()
2095 {
2096 ClientExtensions extensions;
2097
2098 extensions.clientExtensions = true;
2099 extensions.platformBase = true;
2100 extensions.platformANGLE = true;
2101
2102 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
2103 extensions.platformANGLED3D = true;
2104 extensions.platformDevice = true;
2105 #endif
2106
2107 #if defined(ANGLE_USE_GBM)
2108 extensions.platformGbmKHR = true;
2109 #endif
2110
2111 #if defined(ANGLE_USE_WAYLAND)
2112 extensions.platformWaylandEXT = true;
2113 #endif
2114
2115 #if defined(ANGLE_PLATFORM_LINUX) && (defined(ANGLE_ENABLE_OPENGL) || defined(ANGLE_ENABLE_VULKAN))
2116 extensions.platformSurfacelessMESA = true;
2117 #endif
2118
2119 #if defined(ANGLE_ENABLE_D3D11)
2120 extensions.platformANGLED3D11ON12 = angle::IsWindows10OrLater();
2121 extensions.platformANGLEDeviceId = true;
2122 #endif
2123
2124 #if defined(ANGLE_ENABLE_OPENGL)
2125 extensions.platformANGLEOpenGL = true;
2126 #endif
2127
2128 #if defined(ANGLE_ENABLE_NULL)
2129 extensions.platformANGLENULL = true;
2130 #endif
2131
2132 #if defined(ANGLE_ENABLE_WGPU)
2133 extensions.platformANGLEWebgpu = true;
2134 #endif
2135
2136 #if defined(ANGLE_ENABLE_D3D11)
2137 extensions.deviceCreation = true;
2138 extensions.deviceCreationD3D11 = true;
2139 extensions.experimentalPresentPath = true;
2140 #endif
2141
2142 #if defined(ANGLE_ENABLE_VULKAN)
2143 extensions.platformANGLEVulkan = true;
2144 extensions.platformANGLEDeviceId = true;
2145 #endif
2146
2147 #if defined(ANGLE_ENABLE_SWIFTSHADER)
2148 extensions.platformANGLEDeviceTypeSwiftShader = true;
2149 #endif
2150
2151 #if defined(ANGLE_ENABLE_METAL)
2152 extensions.platformANGLEMetal = true;
2153 extensions.platformANGLEDeviceId = true;
2154 #endif
2155
2156 #if defined(ANGLE_USE_X11)
2157 extensions.x11Visual = true;
2158 #endif
2159
2160 #if defined(ANGLE_PLATFORM_LINUX)
2161 extensions.platformANGLEDeviceTypeEGLANGLE = true;
2162 #endif
2163
2164 #if defined(ANGLE_ENABLE_EAGL)
2165 extensions.platformANGLEDeviceContextVolatileEagl = true;
2166 #endif
2167
2168 #if defined(ANGLE_ENABLE_CGL)
2169 extensions.platformANGLEDeviceContextVolatileCgl = true;
2170 #endif
2171
2172 #if defined(ANGLE_ENABLE_METAL)
2173 extensions.displayPowerPreferenceANGLE = true;
2174 #endif
2175
2176 extensions.clientGetAllProcAddresses = true;
2177 extensions.debug = true;
2178 extensions.featureControlANGLE = true;
2179 extensions.deviceQueryEXT = true;
2180 extensions.noErrorANGLE = true;
2181
2182 return extensions;
2183 }
2184
2185 template <typename T>
GenerateExtensionsString(const T & extensions)2186 static std::string GenerateExtensionsString(const T &extensions)
2187 {
2188 std::vector<std::string> extensionsVector = extensions.getStrings();
2189
2190 std::ostringstream stream;
2191 std::copy(extensionsVector.begin(), extensionsVector.end(),
2192 std::ostream_iterator<std::string>(stream, " "));
2193 return stream.str();
2194 }
2195
2196 // static
GetClientExtensions()2197 const ClientExtensions &Display::GetClientExtensions()
2198 {
2199 static const ClientExtensions clientExtensions = GenerateClientExtensions();
2200 return clientExtensions;
2201 }
2202
2203 // static
GetClientExtensionString()2204 const std::string &Display::GetClientExtensionString()
2205 {
2206 static const angle::base::NoDestructor<std::string> clientExtensionsString(
2207 GenerateExtensionsString(GetClientExtensions()));
2208 return *clientExtensionsString;
2209 }
2210
initDisplayExtensions()2211 void Display::initDisplayExtensions()
2212 {
2213 mDisplayExtensions = mImplementation->getExtensions();
2214
2215 // Some extensions are always available because they are implemented in the EGL layer.
2216 mDisplayExtensions.createContext = true;
2217 mDisplayExtensions.createContextNoError = !mFrontendFeatures.forceGlErrorChecking.enabled;
2218 mDisplayExtensions.createContextWebGLCompatibility = true;
2219 mDisplayExtensions.createContextBindGeneratesResource = true;
2220 mDisplayExtensions.createContextClientArrays = true;
2221 mDisplayExtensions.pixelFormatFloat = true;
2222 mDisplayExtensions.reusableSyncKHR = true;
2223
2224 // Force EGL_KHR_get_all_proc_addresses on.
2225 mDisplayExtensions.getAllProcAddresses = true;
2226
2227 // Enable program cache control since it is not back-end dependent.
2228 mDisplayExtensions.programCacheControlANGLE = true;
2229
2230 // Request extension is implemented in the ANGLE frontend
2231 mDisplayExtensions.createContextExtensionsEnabled = true;
2232
2233 // Blob cache extension is provided by the ANGLE frontend
2234 mDisplayExtensions.blobCache = true;
2235
2236 // The EGL_ANDROID_recordable extension is provided by the ANGLE frontend, and will always
2237 // say that ANativeWindow is not recordable.
2238 mDisplayExtensions.recordable = true;
2239
2240 // All backends support specific context versions
2241 mDisplayExtensions.createContextBackwardsCompatible = true;
2242
2243 mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions);
2244 }
2245
isValidNativeWindow(EGLNativeWindowType window) const2246 bool Display::isValidNativeWindow(EGLNativeWindowType window) const
2247 {
2248 return mImplementation->isValidNativeWindow(window);
2249 }
2250
validateClientBuffer(const Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const AttributeMap & attribs) const2251 Error Display::validateClientBuffer(const Config *configuration,
2252 EGLenum buftype,
2253 EGLClientBuffer clientBuffer,
2254 const AttributeMap &attribs) const
2255 {
2256 return mImplementation->validateClientBuffer(configuration, buftype, clientBuffer, attribs);
2257 }
2258
validateImageClientBuffer(const gl::Context * context,EGLenum target,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const2259 Error Display::validateImageClientBuffer(const gl::Context *context,
2260 EGLenum target,
2261 EGLClientBuffer clientBuffer,
2262 const egl::AttributeMap &attribs) const
2263 {
2264 return mImplementation->validateImageClientBuffer(context, target, clientBuffer, attribs);
2265 }
2266
valdiatePixmap(const Config * config,EGLNativePixmapType pixmap,const AttributeMap & attributes) const2267 Error Display::valdiatePixmap(const Config *config,
2268 EGLNativePixmapType pixmap,
2269 const AttributeMap &attributes) const
2270 {
2271 return mImplementation->validatePixmap(config, pixmap, attributes);
2272 }
2273
isValidDisplay(const egl::Display * display)2274 bool Display::isValidDisplay(const egl::Display *display)
2275 {
2276 const ANGLEPlatformDisplayMap *anglePlatformDisplayMap = GetANGLEPlatformDisplayMap();
2277 for (const auto &displayPair : *anglePlatformDisplayMap)
2278 {
2279 if (displayPair.second == display)
2280 {
2281 return true;
2282 }
2283 }
2284
2285 const DevicePlatformDisplayMap *devicePlatformDisplayMap = GetDevicePlatformDisplayMap();
2286 for (const auto &displayPair : *devicePlatformDisplayMap)
2287 {
2288 if (displayPair.second == display)
2289 {
2290 return true;
2291 }
2292 }
2293
2294 return false;
2295 }
2296
isValidNativeDisplay(EGLNativeDisplayType display)2297 bool Display::isValidNativeDisplay(EGLNativeDisplayType display)
2298 {
2299 // TODO(jmadill): handle this properly
2300 if (display == EGL_DEFAULT_DISPLAY)
2301 {
2302 return true;
2303 }
2304
2305 #if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_ENABLE_WINDOWS_UWP)
2306 if (display == EGL_SOFTWARE_DISPLAY_ANGLE || display == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
2307 display == EGL_D3D11_ONLY_DISPLAY_ANGLE)
2308 {
2309 return true;
2310 }
2311 return (WindowFromDC(display) != nullptr);
2312 #else
2313 return true;
2314 #endif
2315 }
2316
initVendorString()2317 void Display::initVendorString()
2318 {
2319 mVendorString = "Google Inc.";
2320 std::string vendorStringImpl = mImplementation->getVendorString();
2321 if (!vendorStringImpl.empty())
2322 {
2323 mVendorString += " (" + vendorStringImpl + ")";
2324 }
2325 }
2326
initVersionString()2327 void Display::initVersionString()
2328 {
2329 mVersionString = mImplementation->getVersionString(true);
2330 }
2331
initClientAPIString()2332 void Display::initClientAPIString()
2333 {
2334 std::string supportedClientAPIs = "OpenGL_ES";
2335
2336 #ifdef ANGLE_ENABLE_GL_DESKTOP_FRONTEND
2337 // If angle_enable_gl_desktop_frontend is enabled and the max supported desktop version
2338 // is not None, we support a desktop GL frontend.
2339 if (mImplementation->getMaxSupportedDesktopVersion().valid())
2340 {
2341 supportedClientAPIs += " OpenGL";
2342 }
2343 #endif // ANGLE_ENABLE_GL_DESKTOP_FRONTEND
2344
2345 mClientAPIString = supportedClientAPIs;
2346 }
2347
initializeFrontendFeatures()2348 void Display::initializeFrontendFeatures()
2349 {
2350 // Enable on all Impls
2351 ANGLE_FEATURE_CONDITION(&mFrontendFeatures, loseContextOnOutOfMemory, true);
2352 ANGLE_FEATURE_CONDITION(&mFrontendFeatures, allowCompressedFormats, true);
2353
2354 // Togglable until work on the extension is complete - anglebug.com/7279.
2355 ANGLE_FEATURE_CONDITION(&mFrontendFeatures, emulatePixelLocalStorage, true);
2356
2357 ANGLE_FEATURE_CONDITION(&mFrontendFeatures, forceMinimumMaxVertexAttributes, false);
2358
2359 mImplementation->initializeFrontendFeatures(&mFrontendFeatures);
2360 }
2361
getExtensions() const2362 const DisplayExtensions &Display::getExtensions() const
2363 {
2364 return mDisplayExtensions;
2365 }
2366
getExtensionString() const2367 const std::string &Display::getExtensionString() const
2368 {
2369 return mDisplayExtensionString;
2370 }
2371
getVendorString() const2372 const std::string &Display::getVendorString() const
2373 {
2374 return mVendorString;
2375 }
2376
getVersionString() const2377 const std::string &Display::getVersionString() const
2378 {
2379 return mVersionString;
2380 }
2381
getClientAPIString() const2382 const std::string &Display::getClientAPIString() const
2383 {
2384 return mClientAPIString;
2385 }
2386
getBackendRendererDescription() const2387 std::string Display::getBackendRendererDescription() const
2388 {
2389 return mImplementation->getRendererDescription();
2390 }
2391
getBackendVendorString() const2392 std::string Display::getBackendVendorString() const
2393 {
2394 return mImplementation->getVendorString();
2395 }
2396
getBackendVersionString(bool includeFullVersion) const2397 std::string Display::getBackendVersionString(bool includeFullVersion) const
2398 {
2399 return mImplementation->getVersionString(includeFullVersion);
2400 }
2401
getDevice() const2402 Device *Display::getDevice() const
2403 {
2404 return mDevice;
2405 }
2406
getWGLSurface() const2407 Surface *Display::getWGLSurface() const
2408 {
2409 return mSurface;
2410 }
2411
getMaxSupportedESVersion() const2412 gl::Version Display::getMaxSupportedESVersion() const
2413 {
2414 return mImplementation->getMaxSupportedESVersion();
2415 }
2416
programCacheGetAttrib(EGLenum attrib) const2417 EGLint Display::programCacheGetAttrib(EGLenum attrib) const
2418 {
2419 switch (attrib)
2420 {
2421 case EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE:
2422 return static_cast<EGLint>(BlobCache::kKeyLength);
2423
2424 case EGL_PROGRAM_CACHE_SIZE_ANGLE:
2425 return static_cast<EGLint>(mMemoryProgramCache.entryCount());
2426
2427 default:
2428 UNREACHABLE();
2429 return 0;
2430 }
2431 }
2432
programCacheQuery(EGLint index,void * key,EGLint * keysize,void * binary,EGLint * binarysize)2433 Error Display::programCacheQuery(EGLint index,
2434 void *key,
2435 EGLint *keysize,
2436 void *binary,
2437 EGLint *binarysize)
2438 {
2439 ASSERT(index >= 0 && index < static_cast<EGLint>(mMemoryProgramCache.entryCount()));
2440
2441 const BlobCache::Key *programHash = nullptr;
2442 BlobCache::Value programBinary;
2443 // TODO(jmadill): Make this thread-safe.
2444 bool result =
2445 mMemoryProgramCache.getAt(static_cast<size_t>(index), &programHash, &programBinary);
2446 if (!result)
2447 {
2448 return EglBadAccess() << "Program binary not accessible.";
2449 }
2450
2451 ASSERT(keysize && binarysize);
2452
2453 if (key)
2454 {
2455 ASSERT(*keysize == static_cast<EGLint>(BlobCache::kKeyLength));
2456 memcpy(key, programHash->data(), BlobCache::kKeyLength);
2457 }
2458
2459 if (binary)
2460 {
2461 // Note: we check the size here instead of in the validation code, since we need to
2462 // access the cache as atomically as possible. It's possible that the cache contents
2463 // could change between the validation size check and the retrieval.
2464 if (programBinary.size() > static_cast<size_t>(*binarysize))
2465 {
2466 return EglBadAccess() << "Program binary too large or changed during access.";
2467 }
2468
2469 memcpy(binary, programBinary.data(), programBinary.size());
2470 }
2471
2472 *binarysize = static_cast<EGLint>(programBinary.size());
2473 *keysize = static_cast<EGLint>(BlobCache::kKeyLength);
2474
2475 return NoError();
2476 }
2477
programCachePopulate(const void * key,EGLint keysize,const void * binary,EGLint binarysize)2478 Error Display::programCachePopulate(const void *key,
2479 EGLint keysize,
2480 const void *binary,
2481 EGLint binarysize)
2482 {
2483 ASSERT(keysize == static_cast<EGLint>(BlobCache::kKeyLength));
2484
2485 BlobCache::Key programHash;
2486 memcpy(programHash.data(), key, BlobCache::kKeyLength);
2487
2488 if (!mMemoryProgramCache.putBinary(programHash, reinterpret_cast<const uint8_t *>(binary),
2489 static_cast<size_t>(binarysize)))
2490 {
2491 return EglBadAccess() << "Failed to copy program binary into the cache.";
2492 }
2493
2494 return NoError();
2495 }
2496
programCacheResize(EGLint limit,EGLenum mode)2497 EGLint Display::programCacheResize(EGLint limit, EGLenum mode)
2498 {
2499 switch (mode)
2500 {
2501 case EGL_PROGRAM_CACHE_RESIZE_ANGLE:
2502 {
2503 size_t initialSize = mMemoryProgramCache.size();
2504 mMemoryProgramCache.resize(static_cast<size_t>(limit));
2505 return static_cast<EGLint>(initialSize);
2506 }
2507
2508 case EGL_PROGRAM_CACHE_TRIM_ANGLE:
2509 return static_cast<EGLint>(mMemoryProgramCache.trim(static_cast<size_t>(limit)));
2510
2511 default:
2512 UNREACHABLE();
2513 return 0;
2514 }
2515 }
2516
overrideFrontendFeatures(const std::vector<std::string> & featureNames,bool enabled)2517 void Display::overrideFrontendFeatures(const std::vector<std::string> &featureNames, bool enabled)
2518 {
2519 mFrontendFeatures.overrideFeatures(featureNames, enabled);
2520 }
2521
queryStringi(const EGLint name,const EGLint index)2522 const char *Display::queryStringi(const EGLint name, const EGLint index)
2523 {
2524 const char *result = nullptr;
2525 switch (name)
2526 {
2527 case EGL_FEATURE_NAME_ANGLE:
2528 result = mFeatures[index]->name;
2529 break;
2530 case EGL_FEATURE_CATEGORY_ANGLE:
2531 result = angle::FeatureCategoryToString(mFeatures[index]->category);
2532 break;
2533 case EGL_FEATURE_DESCRIPTION_ANGLE:
2534 result = mFeatures[index]->description;
2535 break;
2536 case EGL_FEATURE_BUG_ANGLE:
2537 result = mFeatures[index]->bug;
2538 break;
2539 case EGL_FEATURE_STATUS_ANGLE:
2540 result = angle::FeatureStatusToString(mFeatures[index]->enabled);
2541 break;
2542 case EGL_FEATURE_CONDITION_ANGLE:
2543 result = mFeatures[index]->condition;
2544 break;
2545 default:
2546 UNREACHABLE();
2547 return nullptr;
2548 }
2549 return result;
2550 }
2551
queryAttrib(const EGLint attribute)2552 EGLAttrib Display::queryAttrib(const EGLint attribute)
2553 {
2554 EGLAttrib value = 0;
2555 switch (attribute)
2556 {
2557 case EGL_DEVICE_EXT:
2558 value = reinterpret_cast<EGLAttrib>(mDevice);
2559 break;
2560
2561 case EGL_FEATURE_COUNT_ANGLE:
2562 value = mFeatures.size();
2563 break;
2564
2565 default:
2566 UNREACHABLE();
2567 }
2568 return value;
2569 }
2570
requestScratchBuffer()2571 angle::ScratchBuffer Display::requestScratchBuffer()
2572 {
2573 return requestScratchBufferImpl(&mScratchBuffers);
2574 }
2575
returnScratchBuffer(angle::ScratchBuffer scratchBuffer)2576 void Display::returnScratchBuffer(angle::ScratchBuffer scratchBuffer)
2577 {
2578 returnScratchBufferImpl(std::move(scratchBuffer), &mScratchBuffers);
2579 }
2580
requestZeroFilledBuffer()2581 angle::ScratchBuffer Display::requestZeroFilledBuffer()
2582 {
2583 return requestScratchBufferImpl(&mZeroFilledBuffers);
2584 }
2585
returnZeroFilledBuffer(angle::ScratchBuffer zeroFilledBuffer)2586 void Display::returnZeroFilledBuffer(angle::ScratchBuffer zeroFilledBuffer)
2587 {
2588 returnScratchBufferImpl(std::move(zeroFilledBuffer), &mZeroFilledBuffers);
2589 }
2590
requestScratchBufferImpl(std::vector<angle::ScratchBuffer> * bufferVector)2591 angle::ScratchBuffer Display::requestScratchBufferImpl(
2592 std::vector<angle::ScratchBuffer> *bufferVector)
2593 {
2594 std::lock_guard<angle::SimpleMutex> lock(mScratchBufferMutex);
2595 if (!bufferVector->empty())
2596 {
2597 angle::ScratchBuffer buffer = std::move(bufferVector->back());
2598 bufferVector->pop_back();
2599 return buffer;
2600 }
2601
2602 return angle::ScratchBuffer(kScratchBufferLifetime);
2603 }
2604
returnScratchBufferImpl(angle::ScratchBuffer scratchBuffer,std::vector<angle::ScratchBuffer> * bufferVector)2605 void Display::returnScratchBufferImpl(angle::ScratchBuffer scratchBuffer,
2606 std::vector<angle::ScratchBuffer> *bufferVector)
2607 {
2608 std::lock_guard<angle::SimpleMutex> lock(mScratchBufferMutex);
2609 bufferVector->push_back(std::move(scratchBuffer));
2610 }
2611
handleGPUSwitch()2612 Error Display::handleGPUSwitch()
2613 {
2614 ANGLE_TRY(mImplementation->handleGPUSwitch());
2615 initVendorString();
2616 return NoError();
2617 }
2618
forceGPUSwitch(EGLint gpuIDHigh,EGLint gpuIDLow)2619 Error Display::forceGPUSwitch(EGLint gpuIDHigh, EGLint gpuIDLow)
2620 {
2621 ANGLE_TRY(mImplementation->forceGPUSwitch(gpuIDHigh, gpuIDLow));
2622 initVendorString();
2623 return NoError();
2624 }
2625
waitUntilWorkScheduled()2626 Error Display::waitUntilWorkScheduled()
2627 {
2628 ANGLE_TRY(mImplementation->waitUntilWorkScheduled());
2629 return NoError();
2630 }
2631
supportsDmaBufFormat(EGLint format) const2632 bool Display::supportsDmaBufFormat(EGLint format) const
2633 {
2634 return mImplementation->supportsDmaBufFormat(format);
2635 }
2636
queryDmaBufFormats(EGLint max_formats,EGLint * formats,EGLint * num_formats)2637 Error Display::queryDmaBufFormats(EGLint max_formats, EGLint *formats, EGLint *num_formats)
2638 {
2639 ANGLE_TRY(mImplementation->queryDmaBufFormats(max_formats, formats, num_formats));
2640 return NoError();
2641 }
2642
queryDmaBufModifiers(EGLint format,EGLint max_modifiers,EGLuint64KHR * modifiers,EGLBoolean * external_only,EGLint * num_modifiers)2643 Error Display::queryDmaBufModifiers(EGLint format,
2644 EGLint max_modifiers,
2645 EGLuint64KHR *modifiers,
2646 EGLBoolean *external_only,
2647 EGLint *num_modifiers)
2648 {
2649 ANGLE_TRY(mImplementation->queryDmaBufModifiers(format, max_modifiers, modifiers, external_only,
2650 num_modifiers));
2651 return NoError();
2652 }
2653
getImageLoadContext() const2654 angle::ImageLoadContext Display::getImageLoadContext() const
2655 {
2656 angle::ImageLoadContext imageLoadContext;
2657
2658 imageLoadContext.singleThreadPool = mState.singleThreadPool;
2659 imageLoadContext.multiThreadPool = mFrontendFeatures.singleThreadedTextureDecompression.enabled
2660 ? nullptr
2661 : mState.multiThreadPool;
2662
2663 return imageLoadContext;
2664 }
2665
getContext(gl::ContextID contextID) const2666 const gl::Context *Display::getContext(gl::ContextID contextID) const
2667 {
2668 auto iter = mState.contextMap.find(contextID.value);
2669 return iter != mState.contextMap.end() ? iter->second : nullptr;
2670 }
2671
getSurface(egl::SurfaceID surfaceID) const2672 const egl::Surface *Display::getSurface(egl::SurfaceID surfaceID) const
2673 {
2674 auto iter = mState.surfaceMap.find(surfaceID.value);
2675 return iter != mState.surfaceMap.end() ? iter->second : nullptr;
2676 }
2677
getImage(egl::ImageID imageID) const2678 const egl::Image *Display::getImage(egl::ImageID imageID) const
2679 {
2680 auto iter = mImageMap.find(imageID.value);
2681 return iter != mImageMap.end() ? iter->second : nullptr;
2682 }
2683
getSync(egl::SyncID syncID) const2684 const egl::Sync *Display::getSync(egl::SyncID syncID) const
2685 {
2686 auto iter = mSyncMap.find(syncID.value);
2687 return iter != mSyncMap.end() ? iter->second.get() : nullptr;
2688 }
2689
getContext(gl::ContextID contextID)2690 gl::Context *Display::getContext(gl::ContextID contextID)
2691 {
2692 auto iter = mState.contextMap.find(contextID.value);
2693 return iter != mState.contextMap.end() ? iter->second : nullptr;
2694 }
2695
getSurface(egl::SurfaceID surfaceID)2696 egl::Surface *Display::getSurface(egl::SurfaceID surfaceID)
2697 {
2698 auto iter = mState.surfaceMap.find(surfaceID.value);
2699 return iter != mState.surfaceMap.end() ? iter->second : nullptr;
2700 }
2701
getImage(egl::ImageID imageID)2702 egl::Image *Display::getImage(egl::ImageID imageID)
2703 {
2704 auto iter = mImageMap.find(imageID.value);
2705 return iter != mImageMap.end() ? iter->second : nullptr;
2706 }
2707
getSync(egl::SyncID syncID)2708 egl::Sync *Display::getSync(egl::SyncID syncID)
2709 {
2710 auto iter = mSyncMap.find(syncID.value);
2711 return iter != mSyncMap.end() ? iter->second.get() : nullptr;
2712 }
2713
2714 // static
InitTLS()2715 void Display::InitTLS()
2716 {
2717 TLSData *tlsData = new TLSData;
2718
2719 #if defined(ANGLE_PLATFORM_APPLE)
2720 SetDisplayTLS(tlsData);
2721 #else
2722 gDisplayTLS = tlsData;
2723 #endif
2724 }
2725
2726 // static
GetCurrentThreadUnlockedTailCall()2727 angle::UnlockedTailCall *Display::GetCurrentThreadUnlockedTailCall()
2728 {
2729 return &GetDisplayTLS()->unlockedTailCall;
2730 }
2731
2732 // static
GetCurrentThreadErrorScratchSpace()2733 Error *Display::GetCurrentThreadErrorScratchSpace()
2734 {
2735 return &GetDisplayTLS()->errorScratchSpace;
2736 }
2737 } // namespace egl
2738