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