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::__anona8a699080111::ANGLEPlatformDisplay173 ANGLEPlatformDisplay(EGLNativeDisplayType nativeDisplayType)
174 : nativeDisplayType(nativeDisplayType)
175 {}
176
ANGLEPlatformDisplayegl::__anona8a699080111::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::__anona8a699080111::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_APPLE)
585 if (rx::IsVulkanMacDisplayAvailable())
586 {
587 impl = rx::CreateVulkanMacDisplay(state);
588 }
589 break;
590 # else
591 # error Unsupported Vulkan platform.
592 # endif
593 #else
594 // Vulkan isn't available
595 break;
596 #endif // defined(ANGLE_ENABLE_VULKAN)
597
598 case EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE:
599 #if defined(ANGLE_ENABLE_METAL)
600 if (rx::IsMetalDisplayAvailable())
601 {
602 impl = rx::CreateMetalDisplay(state);
603 break;
604 }
605 #endif
606 // Metal isn't available.
607 break;
608
609 case EGL_PLATFORM_ANGLE_TYPE_WEBGPU_ANGLE:
610 #if defined(ANGLE_ENABLE_WGPU)
611 impl = rx::CreateWgpuDisplay(state);
612 #endif // defined(ANGLE_ENABLE_WGPU)
613 // WebGPU isn't available.
614 break;
615
616 case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE:
617 #if defined(ANGLE_ENABLE_NULL)
618 impl = new rx::DisplayNULL(state);
619 break;
620 #else
621 // No display available
622 UNREACHABLE();
623 break;
624 #endif // defined(ANGLE_ENABLE_NULL)
625
626 default:
627 UNREACHABLE();
628 break;
629 }
630
631 return impl;
632 }
633
Display_logError(angle::PlatformMethods * platform,const char * errorMessage)634 void Display_logError(angle::PlatformMethods *platform, const char *errorMessage)
635 {
636 gl::Trace(gl::LOG_ERR, errorMessage);
637 }
638
Display_logWarning(angle::PlatformMethods * platform,const char * warningMessage)639 void Display_logWarning(angle::PlatformMethods *platform, const char *warningMessage)
640 {
641 gl::Trace(gl::LOG_WARN, warningMessage);
642 }
643
Display_logInfo(angle::PlatformMethods * platform,const char * infoMessage)644 void Display_logInfo(angle::PlatformMethods *platform, const char *infoMessage)
645 {
646 // Uncomment to get info spam
647 #if defined(ANGLE_ENABLE_DEBUG_TRACE)
648 gl::Trace(gl::LOG_INFO, infoMessage);
649 #endif
650 }
651
EGLStringArrayToStringVector(const char ** ary)652 const std::vector<std::string> EGLStringArrayToStringVector(const char **ary)
653 {
654 std::vector<std::string> vec;
655 if (ary != nullptr)
656 {
657 for (; *ary != nullptr; ary++)
658 {
659 vec.push_back(std::string(*ary));
660 }
661 }
662 return vec;
663 }
664
ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display)665 void ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display)
666 {
667 angle::PlatformMethods *platformMethods = ANGLEPlatformCurrent();
668
669 ANGLEResetDisplayPlatform(display);
670 platformMethods->logError = Display_logError;
671 platformMethods->logWarning = Display_logWarning;
672 platformMethods->logInfo = Display_logInfo;
673 }
674
UpdateAttribsFromEnvironment(AttributeMap & attribMap)675 void UpdateAttribsFromEnvironment(AttributeMap &attribMap)
676 {
677 EGLAttrib displayType =
678 attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
679 if (displayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
680 {
681 displayType = GetDisplayTypeFromEnvironment();
682 attribMap.insert(EGL_PLATFORM_ANGLE_TYPE_ANGLE, displayType);
683 }
684 EGLAttrib deviceType = attribMap.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, 0);
685 if (deviceType == 0)
686 {
687 deviceType = GetDeviceTypeFromEnvironment();
688 attribMap.insert(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, deviceType);
689 }
690 EGLAttrib platformType = attribMap.get(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE, 0);
691 if (platformType == 0)
692 {
693 platformType = GetPlatformTypeFromEnvironment();
694 attribMap.insert(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE, platformType);
695 }
696 }
697
698 static constexpr uint32_t kScratchBufferLifetime = 64u;
699
700 } // anonymous namespace
701
702 // DisplayState
DisplayState(EGLNativeDisplayType nativeDisplayId)703 DisplayState::DisplayState(EGLNativeDisplayType nativeDisplayId)
704 : label(nullptr),
705 displayId(nativeDisplayId),
706 singleThreadPool(nullptr),
707 multiThreadPool(nullptr),
708 deviceLost(false)
709 {}
710
~DisplayState()711 DisplayState::~DisplayState() {}
712
notifyDeviceLost() const713 void DisplayState::notifyDeviceLost() const
714 {
715 if (deviceLost)
716 {
717 return;
718 }
719
720 {
721 std::lock_guard<angle::SimpleMutex> lock(contextMapMutex);
722 for (auto context = contextMap.begin(); context != contextMap.end(); context++)
723 {
724 context->second->markContextLost(gl::GraphicsResetStatus::UnknownContextReset);
725 }
726 }
727
728 deviceLost = true;
729 }
730
731 // Note that ANGLE support on Ozone platform is limited. Our preferred support Matrix for
732 // EGL_ANGLE_platform_angle on Linux and Ozone/Linux/Fuchsia platforms should be the following:
733 //
734 // |--------------------------------------------------------|
735 // | ANGLE type | DEVICE type | PLATFORM type | Display |
736 // |--------------------------------------------------------|
737 // | OPENGL | EGL | ANY | EGL |
738 // | OPENGL | HARDWARE | X11_EXT | GLX |
739 // | OPENGLES | HARDWARE | X11_EXT | GLX |
740 // | OPENGLES | EGL | ANY | EGL |
741 // | VULKAN | HARDWARE | X11_EXT | VkXcb |
742 // | VULKAN | SWIFTSHADER | X11_EXT | VkXcb |
743 // | OPENGLES | HARDWARE | SURFACELESS_MESA | EGL* |
744 // | OPENGLES | HARDWARE | DEVICE_EXT | EGL |
745 // | VULKAN | HARDWARE | SURFACELESS_MESA | VkBase** |
746 // | VULKAN | SWIFTSHADER | SURFACELESS_MESA | VkBase** |
747 // |--------------------------------------------------------|
748 //
749 // * No surfaceless support yet.
750 // ** Not implemented yet.
751 //
752 // |-----------------------------------------------|
753 // | OS | BUILD type | Default PLATFORM type |
754 // |-----------------------------------------------|
755 // | Linux | X11 | X11_EXT |
756 // | Linux | Ozone | SURFACELESS_MESA |
757 // | Fuchsia | Ozone | FUCHSIA*** |
758 // |-----------------------------------------------|
759 //
760 // *** Chosen implicitly. No EGLAttrib available.
761 //
762 // For more details, please refer to
763 // https://docs.google.com/document/d/1XjHiDZQISq1AMrg_l1TX1_kIKvDpU76hidn9i4cAjl8/edit?disco=AAAAJl9V_YY
764 //
765 // static
GetDisplayFromNativeDisplay(EGLenum platform,EGLNativeDisplayType nativeDisplay,const AttributeMap & attribMap)766 Display *Display::GetDisplayFromNativeDisplay(EGLenum platform,
767 EGLNativeDisplayType nativeDisplay,
768 const AttributeMap &attribMap)
769 {
770 Display *display = nullptr;
771
772 AttributeMap updatedAttribMap(attribMap);
773 UpdateAttribsFromEnvironment(updatedAttribMap);
774
775 EGLAttrib powerPreference =
776 updatedAttribMap.get(EGL_POWER_PREFERENCE_ANGLE, EGL_LOW_POWER_ANGLE);
777 EGLAttrib platformANGLEType =
778 updatedAttribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
779 EGLAttrib deviceIdHigh = updatedAttribMap.get(EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE, 0);
780 EGLAttrib deviceIdLow = updatedAttribMap.get(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE, 0);
781 EGLAttrib displayKey = updatedAttribMap.get(EGL_PLATFORM_ANGLE_DISPLAY_KEY_ANGLE, 0);
782 EGLAttrib enabledFeatureOverrides =
783 updatedAttribMap.get(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, 0);
784 EGLAttrib disabledFeatureOverrides =
785 updatedAttribMap.get(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, 0);
786 EGLAttrib disableAllNonOverriddenFeatures =
787 updatedAttribMap.get(EGL_FEATURE_ALL_DISABLED_ANGLE, 0);
788 ANGLEPlatformDisplay combinedDisplayKey(
789 nativeDisplay, powerPreference, platformANGLEType, deviceIdHigh, deviceIdLow, displayKey,
790 enabledFeatureOverrides, disabledFeatureOverrides, disableAllNonOverriddenFeatures);
791
792 {
793 std::lock_guard<angle::SimpleMutex> lock(*ANGLEPlatformDisplayMapMutex());
794
795 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
796 const auto &iter = displays->find(combinedDisplayKey);
797
798 if (iter != displays->end())
799 {
800 display = iter->second;
801 }
802
803 if (display == nullptr)
804 {
805 // Validate the native display
806 if (!Display::isValidNativeDisplay(nativeDisplay))
807 {
808 return nullptr;
809 }
810
811 display = new Display(platform, nativeDisplay, nullptr);
812 displays->insert(std::make_pair(combinedDisplayKey, display));
813 }
814 }
815 // Apply new attributes if the display is not initialized yet.
816 if (!display->isInitialized())
817 {
818 display->setAttributes(updatedAttribMap);
819
820 EGLAttrib displayType = display->mAttributeMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
821 EGLAttrib deviceType = display->mAttributeMap.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
822 EGLAttrib platformType = platform;
823 if (platform == EGL_PLATFORM_ANGLE_ANGLE)
824 {
825 platformType =
826 display->mAttributeMap.get(EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE);
827 }
828 rx::DisplayImpl *impl =
829 CreateDisplayFromAttribs(displayType, deviceType, platformType, display->getState());
830 if (impl == nullptr)
831 {
832 // No valid display implementation for these attributes
833 return nullptr;
834 }
835
836 #if defined(ANGLE_USE_ANDROID_TLS_SLOT)
837 angle::gUseAndroidOpenGLTlsSlot = displayType == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
838 #endif // defined(ANGLE_PLATFORM_ANDROID)
839
840 display->setupDisplayPlatform(impl);
841 }
842
843 return display;
844 }
845
846 // static
GetExistingDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay)847 Display *Display::GetExistingDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay)
848 {
849 std::lock_guard<angle::SimpleMutex> lock(*ANGLEPlatformDisplayMapMutex());
850 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
851 const auto &iter = displays->find(nativeDisplay);
852
853 // Check that there is a matching display
854 if (iter == displays->end())
855 {
856 return nullptr;
857 }
858
859 return iter->second;
860 }
861
862 // static
GetDisplayFromDevice(Device * device,const AttributeMap & attribMap)863 Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attribMap)
864 {
865 Display *display = nullptr;
866
867 ASSERT(Device::IsValidDevice(device));
868
869 {
870 // First see if this eglDevice is in use by a Display created using ANGLE platform
871 std::lock_guard<angle::SimpleMutex> lock(*ANGLEPlatformDisplayMapMutex());
872 ANGLEPlatformDisplayMap *anglePlatformDisplays = GetANGLEPlatformDisplayMap();
873 for (auto &displayMapEntry : *anglePlatformDisplays)
874 {
875 egl::Display *iterDisplay = displayMapEntry.second;
876 if (iterDisplay->getDevice() == device)
877 {
878 display = iterDisplay;
879 }
880 }
881 }
882
883 if (display == nullptr)
884 {
885 // Next see if this eglDevice is in use by a Display created using the DEVICE platform
886 std::lock_guard<angle::SimpleMutex> lock(*DevicePlatformDisplayMapMutex());
887 DevicePlatformDisplayMap *devicePlatformDisplays = GetDevicePlatformDisplayMap();
888
889 // See if the eglDevice is in use by a Display created using the DEVICE platform
890 const auto &iter = devicePlatformDisplays->find(device);
891 if (iter != devicePlatformDisplays->end())
892 {
893 display = iter->second;
894 }
895
896 if (display == nullptr)
897 {
898 // Otherwise create a new Display
899 display = new Display(EGL_PLATFORM_DEVICE_EXT, 0, device);
900 devicePlatformDisplays->insert(std::make_pair(device, display));
901 }
902 }
903
904 // Apply new attributes if the display is not initialized yet.
905 if (!display->isInitialized())
906 {
907 display->setAttributes(attribMap);
908 rx::DisplayImpl *impl = CreateDisplayFromDevice(device, display->getState());
909 display->setupDisplayPlatform(impl);
910 }
911
912 return display;
913 }
914
Display(EGLenum platform,EGLNativeDisplayType displayId,Device * eglDevice)915 Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice)
916 : mState(displayId),
917 mImplementation(nullptr),
918 mGPUSwitchedBinding(this, kGPUSwitchedSubjectIndex),
919 mAttributeMap(),
920 mConfigSet(),
921 mStreamSet(),
922 mInvalidContextMap(),
923 mInvalidImageMap(),
924 mInvalidStreamSet(),
925 mInvalidSurfaceMap(),
926 mInvalidSyncMap(),
927 mInitialized(false),
928 mCaps(),
929 mDisplayExtensions(),
930 mDisplayExtensionString(),
931 mVendorString(),
932 mVersionString(),
933 mDevice(eglDevice),
934 mSurface(nullptr),
935 mPlatform(platform),
936 mManagersMutex(nullptr),
937 mTextureManager(nullptr),
938 mSemaphoreManager(nullptr),
939 mBlobCache(gl::kDefaultMaxProgramCacheMemoryBytes),
940 mMemoryProgramCache(mBlobCache),
941 mMemoryShaderCache(mBlobCache),
942 mGlobalTextureShareGroupUsers(0),
943 mGlobalSemaphoreShareGroupUsers(0),
944 mTerminatedByApi(false)
945 {}
946
~Display()947 Display::~Display()
948 {
949 switch (mPlatform)
950 {
951 case EGL_PLATFORM_ANGLE_ANGLE:
952 case EGL_PLATFORM_GBM_KHR:
953 case EGL_PLATFORM_WAYLAND_EXT:
954 case EGL_PLATFORM_SURFACELESS_MESA:
955 {
956 std::lock_guard<angle::SimpleMutex> lock(*ANGLEPlatformDisplayMapMutex());
957 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
958 ANGLEPlatformDisplayMap::iterator iter = displays->find(ANGLEPlatformDisplay(
959 mState.displayId,
960 mAttributeMap.get(EGL_POWER_PREFERENCE_ANGLE, EGL_LOW_POWER_ANGLE),
961 mAttributeMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE,
962 EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE),
963 mAttributeMap.get(EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE, 0),
964 mAttributeMap.get(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE, 0),
965 mAttributeMap.get(EGL_PLATFORM_ANGLE_DISPLAY_KEY_ANGLE, 0),
966 mAttributeMap.get(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, 0),
967 mAttributeMap.get(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, 0),
968 mAttributeMap.get(EGL_FEATURE_ALL_DISABLED_ANGLE, 0)));
969 if (iter != displays->end())
970 {
971 displays->erase(iter);
972 }
973 break;
974 }
975 case EGL_PLATFORM_DEVICE_EXT:
976 {
977 std::lock_guard<angle::SimpleMutex> lock(*DevicePlatformDisplayMapMutex());
978 DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap();
979 DevicePlatformDisplayMap::iterator iter = displays->find(mDevice);
980 if (iter != displays->end())
981 {
982 displays->erase(iter);
983 }
984 break;
985 }
986 default:
987 {
988 UNREACHABLE();
989 }
990 }
991
992 SafeDelete(mDevice);
993 SafeDelete(mImplementation);
994 }
995
setLabel(EGLLabelKHR label)996 void Display::setLabel(EGLLabelKHR label)
997 {
998 mState.label = label;
999 }
1000
getLabel() const1001 EGLLabelKHR Display::getLabel() const
1002 {
1003 return mState.label;
1004 }
1005
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)1006 void Display::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
1007 {
1008 ASSERT(index == kGPUSwitchedSubjectIndex);
1009 ASSERT(message == angle::SubjectMessage::SubjectChanged);
1010 std::lock_guard<angle::SimpleMutex> lock(mState.contextMapMutex);
1011 for (auto context : mState.contextMap)
1012 {
1013 context.second->onGPUSwitch();
1014 }
1015 }
1016
setupDisplayPlatform(rx::DisplayImpl * impl)1017 void Display::setupDisplayPlatform(rx::DisplayImpl *impl)
1018 {
1019 ASSERT(!mInitialized);
1020
1021 ASSERT(impl != nullptr);
1022 SafeDelete(mImplementation);
1023 mImplementation = impl;
1024
1025 // TODO(anglebug.com/42265835): Remove PlatformMethods.
1026 const angle::PlatformMethods *platformMethods =
1027 reinterpret_cast<const angle::PlatformMethods *>(
1028 mAttributeMap.get(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX, 0));
1029 if (platformMethods != nullptr)
1030 {
1031 *ANGLEPlatformCurrent() = *platformMethods;
1032 }
1033 else
1034 {
1035 ANGLESetDefaultDisplayPlatform(this);
1036 }
1037
1038 const char **featuresForceEnabled =
1039 reinterpret_cast<const char **>(mAttributeMap.get(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, 0));
1040 const char **featuresForceDisabled =
1041 reinterpret_cast<const char **>(mAttributeMap.get(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, 0));
1042 mState.featureOverrides.enabled = EGLStringArrayToStringVector(featuresForceEnabled);
1043 mState.featureOverrides.disabled = EGLStringArrayToStringVector(featuresForceDisabled);
1044 mState.featureOverrides.allDisabled =
1045 static_cast<bool>(mAttributeMap.get(EGL_FEATURE_ALL_DISABLED_ANGLE, 0));
1046 mImplementation->addObserver(&mGPUSwitchedBinding);
1047 }
1048
initialize()1049 Error Display::initialize()
1050 {
1051 mTerminatedByApi = false;
1052
1053 ASSERT(mImplementation != nullptr);
1054 mImplementation->setBlobCache(&mBlobCache);
1055
1056 // Enable shader caching if debug layers are turned on. This allows us to test that shaders are
1057 // properly saved & restored on all platforms. The cache won't allocate space until it's used
1058 // and will be ignored entirely if the application / system sets it's own cache functions.
1059 if (rx::ShouldUseDebugLayers(mAttributeMap))
1060 {
1061 mBlobCache.resize(1024 * 1024);
1062 }
1063
1064 setGlobalDebugAnnotator();
1065
1066 gl::InitializeDebugMutexIfNeeded();
1067
1068 ANGLE_TRACE_EVENT0("gpu.angle", "egl::Display::initialize");
1069
1070 if (isInitialized())
1071 {
1072 return NoError();
1073 }
1074
1075 Error error = mImplementation->initialize(this);
1076 if (error.isError())
1077 {
1078 // Log extended error message here
1079 ERR() << "ANGLE Display::initialize error " << error.getID() << ": " << error.getMessage();
1080 return error;
1081 }
1082
1083 mCaps = mImplementation->getCaps();
1084
1085 mConfigSet = mImplementation->generateConfigs();
1086 if (mConfigSet.size() == 0)
1087 {
1088 mImplementation->terminate();
1089 return egl::Error(EGL_NOT_INITIALIZED, "No configs were generated.");
1090 }
1091
1092 // OpenGL ES1 is implemented in the frontend, explicitly add ES1 support to all configs
1093 for (auto &config : mConfigSet)
1094 {
1095 // TODO(geofflang): Enable the conformant bit once we pass enough tests
1096 // config.second.conformant |= EGL_OPENGL_ES_BIT;
1097
1098 config.second.renderableType |= EGL_OPENGL_ES_BIT;
1099 }
1100
1101 mFrontendFeatures.reset();
1102 rx::ApplyFeatureOverrides(&mFrontendFeatures, mState.featureOverrides);
1103 if (!mState.featureOverrides.allDisabled)
1104 {
1105 initializeFrontendFeatures();
1106 }
1107
1108 mFeatures.clear();
1109 mFrontendFeatures.populateFeatureList(&mFeatures);
1110 mImplementation->populateFeatureList(&mFeatures);
1111
1112 initDisplayExtensions();
1113 initVendorString();
1114 initVersionString();
1115 initClientAPIString();
1116
1117 // Populate the Display's EGLDeviceEXT if the Display wasn't created using one
1118 if (mPlatform == EGL_PLATFORM_DEVICE_EXT)
1119 {
1120 // For EGL_PLATFORM_DEVICE_EXT, mDevice should always be populated using
1121 // an external device
1122 ASSERT(mDevice != nullptr);
1123 }
1124 else if (GetClientExtensions().deviceQueryEXT)
1125 {
1126 std::unique_ptr<rx::DeviceImpl> impl(mImplementation->createDevice());
1127 ASSERT(impl);
1128 error = impl->initialize();
1129 if (error.isError())
1130 {
1131 ERR() << "Failed to initialize display because device creation failed: "
1132 << error.getMessage();
1133 mImplementation->terminate();
1134 return error;
1135 }
1136 // Don't leak Device memory.
1137 ASSERT(mDevice == nullptr);
1138 mDevice = new Device(this, impl.release());
1139 }
1140 else
1141 {
1142 mDevice = nullptr;
1143 }
1144
1145 mState.singleThreadPool = angle::WorkerThreadPool::Create(1, ANGLEPlatformCurrent());
1146 mState.multiThreadPool = angle::WorkerThreadPool::Create(0, ANGLEPlatformCurrent());
1147
1148 if (kIsContextMutexEnabled)
1149 {
1150 ASSERT(mManagersMutex == nullptr);
1151 mManagersMutex = new ContextMutex();
1152 mManagersMutex->addRef();
1153 }
1154
1155 mInitialized = true;
1156
1157 return NoError();
1158 }
1159
destroyInvalidEglObjects()1160 Error Display::destroyInvalidEglObjects()
1161 {
1162 // Destroy invalid EGL objects
1163 // Note that we don't need to lock mState.contextMapMutex here.
1164 // Write and read access to mInvalidContextMap are coming from
1165 // EGL_Terminate, EGL_ReleaseThread, ThreadCleanupCallBACK.
1166 // Those functions are protected by egl global lock,
1167 // so there is no race condition on mInvalidContextMap.
1168 while (!mInvalidContextMap.empty())
1169 {
1170 gl::Context *context = mInvalidContextMap.begin()->second;
1171 // eglReleaseThread() may call to this method when there are still Contexts, that may
1172 // potentially acces shared state of the "context".
1173 // Need AddRefLock because there may be ContextMutex destruction.
1174 ScopedContextMutexAddRefLock lock(context->getContextMutex());
1175 context->setIsDestroyed();
1176 ANGLE_TRY(releaseContextImpl(eraseContextImpl(context, &mInvalidContextMap)));
1177 }
1178
1179 while (!mInvalidImageMap.empty())
1180 {
1181 destroyImageImpl(mInvalidImageMap.begin()->second, &mInvalidImageMap);
1182 }
1183
1184 while (!mInvalidStreamSet.empty())
1185 {
1186 destroyStreamImpl(*mInvalidStreamSet.begin(), &mInvalidStreamSet);
1187 }
1188
1189 while (!mInvalidSurfaceMap.empty())
1190 {
1191 ANGLE_TRY(destroySurfaceImpl(mInvalidSurfaceMap.begin()->second, &mInvalidSurfaceMap));
1192 }
1193
1194 while (!mInvalidSyncMap.empty())
1195 {
1196 destroySyncImpl(mInvalidSyncMap.begin()->second->id(), &mInvalidSyncMap);
1197 }
1198
1199 return NoError();
1200 }
1201
terminate(Thread * thread,TerminateReason terminateReason)1202 Error Display::terminate(Thread *thread, TerminateReason terminateReason)
1203 {
1204
1205 if (terminateReason == TerminateReason::Api)
1206 {
1207 mTerminatedByApi = true;
1208 }
1209
1210 // All subsequent calls assume the display to be valid and terminated by app.
1211 // If it is not terminated or if it isn't even initialized, early return.
1212 if (!mTerminatedByApi || !mInitialized)
1213 {
1214 return NoError();
1215 }
1216
1217 // EGL 1.5 Specification
1218 // 3.2 Initialization
1219 // Termination marks all EGL-specific resources, such as contexts and surfaces, associated
1220 // with the specified display for deletion. Handles to all such resources are invalid as
1221 // soon as eglTerminate returns. Cache EGL objects that are no longer valid.
1222 //
1223 // It is fairly common for apps to call eglTerminate while some contexts and/or surfaces are
1224 // still current on some thread. Since objects are refCounted, trying to destroy them right
1225 // away would only result in a decRef. We instead cache such invalid objects and use other
1226 // EGL entrypoints like eglReleaseThread or thread exit events (on the Android platform) to
1227 // perform the necessary cleanup.
1228 mInvalidImageMap.insert(mImageMap.begin(), mImageMap.end());
1229 mImageMap.clear();
1230
1231 mInvalidStreamSet.insert(mStreamSet.begin(), mStreamSet.end());
1232 mStreamSet.clear();
1233
1234 mInvalidSurfaceMap.insert(mState.surfaceMap.begin(), mState.surfaceMap.end());
1235 mState.surfaceMap.clear();
1236
1237 mInvalidSyncMap.insert(std::make_move_iterator(mSyncMap.begin()),
1238 std::make_move_iterator(mSyncMap.end()));
1239 mSyncMap.clear();
1240
1241 {
1242 // Lock mState.contextMapMutex to protect mState.contextMap.
1243 // mInvalidContextMap does not need protection. It just happens to fall within this scope.
1244 std::lock_guard<angle::SimpleMutex> lock(mState.contextMapMutex);
1245 // Cache total number of contexts before invalidation. This is used as a check to verify
1246 // that no context is "lost" while being moved between the various sets.
1247 size_t contextSetSizeBeforeInvalidation =
1248 mState.contextMap.size() + mInvalidContextMap.size();
1249
1250 // If app called eglTerminate and no active threads remain,
1251 // force release any context that is still current.
1252 ContextMap contextsStillCurrent = {};
1253 for (auto context : mState.contextMap)
1254 {
1255 if (context.second->isReferenced())
1256 {
1257 contextsStillCurrent.emplace(context);
1258 continue;
1259 }
1260
1261 // Add context that is not current to mInvalidContextSet for cleanup.
1262 mInvalidContextMap.emplace(context);
1263 }
1264
1265 // There are many methods that require contexts that are still current to be present in
1266 // display's contextSet like during context release or to notify of state changes in a
1267 // subject. So as to not interrupt this flow, do not remove contexts that are still
1268 // current on some thread from display's contextSet even though eglTerminate marks such
1269 // contexts as invalid.
1270 //
1271 // "mState.contextSet" will now contain only those contexts that are still current on
1272 // some thread.
1273 mState.contextMap = std::move(contextsStillCurrent);
1274
1275 // Assert that the total number of contexts is the same before and after context
1276 // invalidation.
1277 ASSERT(contextSetSizeBeforeInvalidation ==
1278 mState.contextMap.size() + mInvalidContextMap.size());
1279
1280 if (!mState.contextMap.empty())
1281 {
1282 // There was atleast 1 context that was current on some thread, early return.
1283 return NoError();
1284 }
1285 }
1286
1287 // The global texture and semaphore managers should be deleted with the last context that uses
1288 // it.
1289 ASSERT(mGlobalTextureShareGroupUsers == 0 && mTextureManager == nullptr);
1290 ASSERT(mGlobalSemaphoreShareGroupUsers == 0 && mSemaphoreManager == nullptr);
1291
1292 if (mManagersMutex != nullptr)
1293 {
1294 mManagersMutex->release();
1295 mManagersMutex = nullptr;
1296 }
1297
1298 // Clean up all invalid objects
1299 ANGLE_TRY(destroyInvalidEglObjects());
1300
1301 mSyncPools.clear();
1302
1303 mConfigSet.clear();
1304
1305 if (mDevice != nullptr && mDevice->getOwningDisplay() != nullptr)
1306 {
1307 // Don't delete the device if it was created externally using eglCreateDeviceANGLE
1308 // We also shouldn't set it to null in case eglInitialize() is called again later
1309 SafeDelete(mDevice);
1310 }
1311
1312 // Before tearing down the backend device, ensure all deferred operations are run. It is not
1313 // possible to defer them beyond this point.
1314 GetCurrentThreadUnlockedTailCall()->run(nullptr);
1315
1316 mImplementation->terminate();
1317
1318 mMemoryProgramCache.clear();
1319 mMemoryShaderCache.clear();
1320 mBlobCache.setBlobCacheFuncs(nullptr, nullptr);
1321
1322 mState.singleThreadPool.reset();
1323 mState.multiThreadPool.reset();
1324
1325 mState.deviceLost = false;
1326
1327 mInitialized = false;
1328
1329 gl::UninitializeDebugAnnotations();
1330
1331 // TODO(jmadill): Store Platform in Display and deinit here.
1332 ANGLEResetDisplayPlatform(this);
1333
1334 return NoError();
1335 }
1336
1337 #if ANGLE_USE_DISPLAY_PREPARE_FOR_CALL
prepareForCall()1338 Error Display::prepareForCall()
1339 {
1340 return mImplementation->prepareForCall();
1341 }
1342 #endif
1343
releaseThread()1344 Error Display::releaseThread()
1345 {
1346 // Need to check if initialized, because makeCurrent() may terminate the Display.
1347 if (!mInitialized)
1348 {
1349 return NoError();
1350 }
1351 ANGLE_TRY(mImplementation->releaseThread());
1352 return destroyInvalidEglObjects();
1353 }
1354
getConfigs(const egl::AttributeMap & attribs) const1355 std::vector<const Config *> Display::getConfigs(const egl::AttributeMap &attribs) const
1356 {
1357 return mConfigSet.filter(attribs);
1358 }
1359
chooseConfig(const egl::AttributeMap & attribs) const1360 std::vector<const Config *> Display::chooseConfig(const egl::AttributeMap &attribs) const
1361 {
1362 egl::AttributeMap attribsWithDefaults = AttributeMap();
1363
1364 // Insert default values for attributes that have either an Exact or Mask selection criteria,
1365 // and a default value that matters (e.g. isn't EGL_DONT_CARE):
1366 attribsWithDefaults.insert(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
1367 attribsWithDefaults.insert(EGL_LEVEL, 0);
1368 attribsWithDefaults.insert(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT);
1369 attribsWithDefaults.insert(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
1370 attribsWithDefaults.insert(EGL_TRANSPARENT_TYPE, EGL_NONE);
1371 if (getExtensions().pixelFormatFloat)
1372 {
1373 attribsWithDefaults.insert(EGL_COLOR_COMPONENT_TYPE_EXT,
1374 EGL_COLOR_COMPONENT_TYPE_FIXED_EXT);
1375 }
1376
1377 // Add the caller-specified values (Note: the poorly-named insert() method will replace any
1378 // of the default values from above):
1379 for (auto attribIter = attribs.begin(); attribIter != attribs.end(); attribIter++)
1380 {
1381 attribsWithDefaults.insert(attribIter->first, attribIter->second);
1382 }
1383
1384 return mConfigSet.filter(attribsWithDefaults);
1385 }
1386
createWindowSurface(const Config * configuration,EGLNativeWindowType window,const AttributeMap & attribs,Surface ** outSurface)1387 Error Display::createWindowSurface(const Config *configuration,
1388 EGLNativeWindowType window,
1389 const AttributeMap &attribs,
1390 Surface **outSurface)
1391 {
1392 if (mImplementation->testDeviceLost())
1393 {
1394 ANGLE_TRY(restoreLostDevice());
1395 }
1396
1397 SurfaceID id = {mSurfaceHandleAllocator.allocate()};
1398 SurfacePointer surface(new WindowSurface(mImplementation, id, configuration, window, attribs,
1399 mFrontendFeatures.forceRobustResourceInit.enabled),
1400 this);
1401 ANGLE_TRY(surface->initialize(this));
1402
1403 ASSERT(outSurface != nullptr);
1404 *outSurface = surface.release();
1405 mState.surfaceMap.insert(std::pair((*outSurface)->id().value, *outSurface));
1406
1407 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
1408 ASSERT(windowSurfaces && windowSurfaces->find(window) == windowSurfaces->end());
1409 windowSurfaces->insert(std::make_pair(window, *outSurface));
1410
1411 mSurface = *outSurface;
1412
1413 return NoError();
1414 }
1415
createPbufferSurface(const Config * configuration,const AttributeMap & attribs,Surface ** outSurface)1416 Error Display::createPbufferSurface(const Config *configuration,
1417 const AttributeMap &attribs,
1418 Surface **outSurface)
1419 {
1420 ASSERT(isInitialized());
1421
1422 if (mImplementation->testDeviceLost())
1423 {
1424 ANGLE_TRY(restoreLostDevice());
1425 }
1426
1427 SurfaceID id = {mSurfaceHandleAllocator.allocate()};
1428 SurfacePointer surface(new PbufferSurface(mImplementation, id, configuration, attribs,
1429 mFrontendFeatures.forceRobustResourceInit.enabled),
1430 this);
1431 ANGLE_TRY(surface->initialize(this));
1432
1433 ASSERT(outSurface != nullptr);
1434 *outSurface = surface.release();
1435 mState.surfaceMap.insert(std::pair((*outSurface)->id().value, *outSurface));
1436
1437 return NoError();
1438 }
1439
createPbufferFromClientBuffer(const Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const AttributeMap & attribs,Surface ** outSurface)1440 Error Display::createPbufferFromClientBuffer(const Config *configuration,
1441 EGLenum buftype,
1442 EGLClientBuffer clientBuffer,
1443 const AttributeMap &attribs,
1444 Surface **outSurface)
1445 {
1446 ASSERT(isInitialized());
1447
1448 if (mImplementation->testDeviceLost())
1449 {
1450 ANGLE_TRY(restoreLostDevice());
1451 }
1452
1453 SurfaceID id = {mSurfaceHandleAllocator.allocate()};
1454 SurfacePointer surface(
1455 new PbufferSurface(mImplementation, id, configuration, buftype, clientBuffer, attribs,
1456 mFrontendFeatures.forceRobustResourceInit.enabled),
1457 this);
1458 ANGLE_TRY(surface->initialize(this));
1459
1460 ASSERT(outSurface != nullptr);
1461 *outSurface = surface.release();
1462 mState.surfaceMap.insert(std::pair((*outSurface)->id().value, *outSurface));
1463
1464 return NoError();
1465 }
1466
createPixmapSurface(const Config * configuration,NativePixmapType nativePixmap,const AttributeMap & attribs,Surface ** outSurface)1467 Error Display::createPixmapSurface(const Config *configuration,
1468 NativePixmapType nativePixmap,
1469 const AttributeMap &attribs,
1470 Surface **outSurface)
1471 {
1472 ASSERT(isInitialized());
1473
1474 if (mImplementation->testDeviceLost())
1475 {
1476 ANGLE_TRY(restoreLostDevice());
1477 }
1478
1479 SurfaceID id = {mSurfaceHandleAllocator.allocate()};
1480 SurfacePointer surface(
1481 new PixmapSurface(mImplementation, id, configuration, nativePixmap, attribs,
1482 mFrontendFeatures.forceRobustResourceInit.enabled),
1483 this);
1484 ANGLE_TRY(surface->initialize(this));
1485
1486 ASSERT(outSurface != nullptr);
1487 *outSurface = surface.release();
1488 mState.surfaceMap.insert(std::pair((*outSurface)->id().value, *outSurface));
1489
1490 return NoError();
1491 }
1492
createImage(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs,Image ** outImage)1493 Error Display::createImage(const gl::Context *context,
1494 EGLenum target,
1495 EGLClientBuffer buffer,
1496 const AttributeMap &attribs,
1497 Image **outImage)
1498 {
1499 ASSERT(isInitialized());
1500
1501 if (mImplementation->testDeviceLost())
1502 {
1503 ANGLE_TRY(restoreLostDevice());
1504 }
1505
1506 egl::ImageSibling *sibling = nullptr;
1507 if (IsTextureTarget(target))
1508 {
1509 sibling = context->getTexture({egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
1510 }
1511 else if (IsRenderbufferTarget(target))
1512 {
1513 sibling = context->getRenderbuffer({egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
1514 }
1515 else if (IsExternalImageTarget(target))
1516 {
1517 sibling = new ExternalImageSibling(mImplementation, context, target, buffer, attribs);
1518 }
1519 else
1520 {
1521 UNREACHABLE();
1522 }
1523 ASSERT(sibling != nullptr);
1524
1525 ImageID id = {mImageHandleAllocator.allocate()};
1526 angle::UniqueObjectPointer<Image, Display> imagePtr(
1527 new Image(mImplementation, id, context, target, sibling, attribs), this);
1528 ANGLE_TRY(imagePtr->initialize(this, context));
1529
1530 Image *image = imagePtr.release();
1531
1532 ASSERT(outImage != nullptr);
1533 *outImage = image;
1534
1535 // Add this image to the list of all images and hold a ref to it.
1536 image->addRef();
1537 mImageMap.insert(std::pair(image->id().value, image));
1538
1539 return NoError();
1540 }
1541
createStream(const AttributeMap & attribs,Stream ** outStream)1542 Error Display::createStream(const AttributeMap &attribs, Stream **outStream)
1543 {
1544 ASSERT(isInitialized());
1545
1546 Stream *stream = new Stream(this, attribs);
1547
1548 ASSERT(stream != nullptr);
1549 mStreamSet.insert(stream);
1550
1551 ASSERT(outStream != nullptr);
1552 *outStream = stream;
1553
1554 return NoError();
1555 }
1556
createContext(const Config * configuration,gl::Context * shareContext,const AttributeMap & attribs,gl::Context ** outContext)1557 Error Display::createContext(const Config *configuration,
1558 gl::Context *shareContext,
1559 const AttributeMap &attribs,
1560 gl::Context **outContext)
1561 {
1562 ASSERT(!mTerminatedByApi);
1563 ASSERT(isInitialized());
1564
1565 if (mImplementation->testDeviceLost())
1566 {
1567 ANGLE_TRY(restoreLostDevice());
1568 }
1569
1570 // This display texture sharing will allow the first context to create the texture share group.
1571 bool usingDisplayTextureShareGroup =
1572 attribs.get(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE;
1573 gl::TextureManager *shareTextures = nullptr;
1574
1575 if (usingDisplayTextureShareGroup)
1576 {
1577 ASSERT((mTextureManager == nullptr) == (mGlobalTextureShareGroupUsers == 0));
1578 if (mTextureManager == nullptr)
1579 {
1580 mTextureManager = new gl::TextureManager();
1581 }
1582
1583 mGlobalTextureShareGroupUsers++;
1584 shareTextures = mTextureManager;
1585 }
1586
1587 // This display semaphore sharing will allow the first context to create the semaphore share
1588 // group.
1589 bool usingDisplaySemaphoreShareGroup =
1590 attribs.get(EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE;
1591 gl::SemaphoreManager *shareSemaphores = nullptr;
1592 if (usingDisplaySemaphoreShareGroup)
1593 {
1594 ASSERT((mSemaphoreManager == nullptr) == (mGlobalSemaphoreShareGroupUsers == 0));
1595 if (mSemaphoreManager == nullptr)
1596 {
1597 mSemaphoreManager = new gl::SemaphoreManager();
1598 }
1599
1600 mGlobalSemaphoreShareGroupUsers++;
1601 shareSemaphores = mSemaphoreManager;
1602 }
1603
1604 ScopedContextMutexLock mutexLock;
1605 ContextMutex *sharedContextMutex = nullptr;
1606 if (kIsContextMutexEnabled)
1607 {
1608 ASSERT(mManagersMutex != nullptr);
1609 if (shareContext != nullptr)
1610 {
1611 sharedContextMutex = shareContext->getContextMutex().getRoot();
1612 }
1613 else if (shareTextures != nullptr || shareSemaphores != nullptr)
1614 {
1615 mutexLock = ScopedContextMutexLock(mManagersMutex);
1616 sharedContextMutex = mManagersMutex->getRoot();
1617 }
1618 // When using shareTextures/Semaphores all Contexts in the Group must use mManagersMutex.
1619 ASSERT((shareTextures == nullptr && shareSemaphores == nullptr) ||
1620 sharedContextMutex == mManagersMutex->getRoot());
1621 }
1622
1623 gl::MemoryProgramCache *programCachePointer = &mMemoryProgramCache;
1624 // Check context creation attributes to see if we are using EGL_ANGLE_program_cache_control.
1625 // If not, keep caching enabled for EGL_ANDROID_blob_cache, which can have its callbacks set
1626 // at any time.
1627 bool usesProgramCacheControl = attribs.contains(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE);
1628 if (usesProgramCacheControl)
1629 {
1630 bool programCacheControlEnabled =
1631 (attribs.get(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE, GL_FALSE) == GL_TRUE);
1632 // A program cache size of zero indicates it should be disabled.
1633 if (!programCacheControlEnabled || mMemoryProgramCache.maxSize() == 0)
1634 {
1635 programCachePointer = nullptr;
1636 }
1637 }
1638
1639 gl::MemoryShaderCache *shaderCachePointer = &mMemoryShaderCache;
1640 // Check if shader caching frontend feature is enabled.
1641 if (!mFrontendFeatures.cacheCompiledShader.enabled)
1642 {
1643 shaderCachePointer = nullptr;
1644 }
1645
1646 gl::Context *context =
1647 new gl::Context(this, configuration, shareContext, shareTextures, shareSemaphores,
1648 sharedContextMutex, programCachePointer, shaderCachePointer, attribs,
1649 mDisplayExtensions, GetClientExtensions());
1650 Error error = context->initialize();
1651 if (error.isError())
1652 {
1653 delete context;
1654 return error;
1655 }
1656
1657 if (shareContext != nullptr)
1658 {
1659 shareContext->setShared();
1660 }
1661
1662 ASSERT(context != nullptr);
1663 {
1664 std::lock_guard<angle::SimpleMutex> lock(mState.contextMapMutex);
1665 mState.contextMap.insert(std::pair(context->id().value, context));
1666 }
1667
1668 ASSERT(outContext != nullptr);
1669 *outContext = context;
1670 return NoError();
1671 }
1672
createSync(const gl::Context * currentContext,EGLenum type,const AttributeMap & attribs,Sync ** outSync)1673 Error Display::createSync(const gl::Context *currentContext,
1674 EGLenum type,
1675 const AttributeMap &attribs,
1676 Sync **outSync)
1677 {
1678 ASSERT(isInitialized());
1679
1680 SyncID id = {mSyncHandleAllocator.allocate()};
1681
1682 if (mImplementation->testDeviceLost())
1683 {
1684 ANGLE_TRY(restoreLostDevice());
1685 }
1686
1687 std::unique_ptr<Sync> sync;
1688
1689 SyncPool &pool = mSyncPools[type];
1690 if (!pool.empty())
1691 {
1692 sync = std::move(pool.back());
1693 pool.pop_back();
1694 }
1695 else
1696 {
1697 sync.reset(new Sync(mImplementation, type));
1698 }
1699
1700 Error err = sync->initialize(this, currentContext, id, attribs);
1701 if (err.isError())
1702 {
1703 sync->onDestroy(this);
1704 return err;
1705 }
1706
1707 *outSync = sync.get();
1708 mSyncMap.insert(std::pair(id.value, std::move(sync)));
1709
1710 return NoError();
1711 }
1712
makeCurrent(Thread * thread,gl::Context * previousContext,egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)1713 Error Display::makeCurrent(Thread *thread,
1714 gl::Context *previousContext,
1715 egl::Surface *drawSurface,
1716 egl::Surface *readSurface,
1717 gl::Context *context)
1718 {
1719 if (!mInitialized)
1720 {
1721 return NoError();
1722 }
1723
1724 bool contextChanged = context != previousContext;
1725 if (previousContext != nullptr && contextChanged)
1726 {
1727 // Need AddRefLock because there may be ContextMutex destruction.
1728 ScopedContextMutexAddRefLock lock(previousContext->getContextMutex());
1729
1730 previousContext->release();
1731 thread->setCurrent(nullptr);
1732
1733 auto error = previousContext->unMakeCurrent(this);
1734 if (!previousContext->isReferenced() && previousContext->isDestroyed())
1735 {
1736 // The previous Context may have been created with a different Display.
1737 Display *previousDisplay = previousContext->getDisplay();
1738 ANGLE_TRY(previousDisplay->releaseContext(previousContext, thread));
1739 }
1740 ANGLE_TRY(error);
1741 }
1742
1743 {
1744 ScopedContextMutexLock lock(context != nullptr ? &context->getContextMutex() : nullptr);
1745
1746 thread->setCurrent(context);
1747
1748 ANGLE_TRY(mImplementation->makeCurrent(this, drawSurface, readSurface, context));
1749
1750 if (context != nullptr)
1751 {
1752 ANGLE_TRY(context->makeCurrent(this, drawSurface, readSurface));
1753 if (contextChanged)
1754 {
1755 context->addRef();
1756 }
1757 }
1758 }
1759
1760 // Tick all the scratch buffers to make sure they get cleaned up eventually if they stop being
1761 // used.
1762 {
1763 std::lock_guard<angle::SimpleMutex> lock(mScratchBufferMutex);
1764
1765 for (angle::ScratchBuffer &scatchBuffer : mScratchBuffers)
1766 {
1767 scatchBuffer.tick();
1768 }
1769 for (angle::ScratchBuffer &zeroFilledBuffer : mZeroFilledBuffers)
1770 {
1771 zeroFilledBuffer.tick();
1772 }
1773 }
1774
1775 // If eglTerminate() has previously been called and Context was changed, perform InternalCleanup
1776 // to invalidate any non-current Contexts, and possibly fully terminate the Display and release
1777 // all of its resources.
1778 if (mTerminatedByApi && contextChanged)
1779 {
1780 return terminate(thread, TerminateReason::InternalCleanup);
1781 }
1782
1783 return NoError();
1784 }
1785
restoreLostDevice()1786 Error Display::restoreLostDevice()
1787 {
1788 {
1789 std::lock_guard<angle::SimpleMutex> lock(mState.contextMapMutex);
1790 for (ContextMap::iterator ctx = mState.contextMap.begin(); ctx != mState.contextMap.end();
1791 ctx++)
1792 {
1793 if (ctx->second->isResetNotificationEnabled())
1794 {
1795 // If reset notifications have been requested, application must delete all contexts
1796 // first
1797 return egl::Error(EGL_CONTEXT_LOST);
1798 }
1799 }
1800 }
1801
1802 return mImplementation->restoreLostDevice(this);
1803 }
1804
destroySurfaceImpl(Surface * surface,SurfaceMap * surfaces)1805 Error Display::destroySurfaceImpl(Surface *surface, SurfaceMap *surfaces)
1806 {
1807 if (surface->getType() == EGL_WINDOW_BIT)
1808 {
1809 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
1810 ASSERT(windowSurfaces);
1811
1812 bool surfaceRemoved = false;
1813 for (WindowSurfaceMap::iterator iter = windowSurfaces->begin();
1814 iter != windowSurfaces->end(); iter++)
1815 {
1816 if (iter->second == surface)
1817 {
1818 windowSurfaces->erase(iter);
1819 surfaceRemoved = true;
1820 break;
1821 }
1822 }
1823
1824 ASSERT(surfaceRemoved);
1825 }
1826
1827 auto iter = surfaces->find(surface->id().value);
1828 ASSERT(iter != surfaces->end());
1829 mSurfaceHandleAllocator.release(surface->id().value);
1830 surfaces->erase(iter);
1831 ANGLE_TRY(surface->onDestroy(this));
1832 return NoError();
1833 }
1834
destroyImageImpl(Image * image,ImageMap * images)1835 void Display::destroyImageImpl(Image *image, ImageMap *images)
1836 {
1837 auto iter = images->find(image->id().value);
1838 ASSERT(iter != images->end());
1839 mImageHandleAllocator.release(image->id().value);
1840 {
1841 // Need AddRefLock because there may be ContextMutex destruction.
1842 ScopedContextMutexAddRefLock lock(image->getContextMutex());
1843 iter->second->release(this);
1844 }
1845 images->erase(iter);
1846 }
1847
destroyStreamImpl(Stream * stream,StreamSet * streams)1848 void Display::destroyStreamImpl(Stream *stream, StreamSet *streams)
1849 {
1850 streams->erase(stream);
1851 SafeDelete(stream);
1852 }
1853
1854 // releaseContext must be called with the context being deleted as current.
1855 // To do that we can only call this in two places, Display::makeCurrent at the point where this
1856 // context is being made uncurrent and in Display::destroyContext where we make the context current
1857 // as part of destruction.
releaseContext(gl::Context * context,Thread * thread)1858 Error Display::releaseContext(gl::Context *context, Thread *thread)
1859 {
1860 // Use scoped_ptr to make sure the context is always freed.
1861 std::unique_ptr<gl::Context> uniqueContextPtr;
1862 {
1863 std::lock_guard<angle::SimpleMutex> lock(mState.contextMapMutex);
1864 uniqueContextPtr = eraseContextImpl(context, &mState.contextMap);
1865 }
1866 return releaseContextImpl(std::move(uniqueContextPtr));
1867 }
1868
eraseContextImpl(gl::Context * context,ContextMap * contexts)1869 std::unique_ptr<gl::Context> Display::eraseContextImpl(gl::Context *context, ContextMap *contexts)
1870 {
1871 ASSERT(!context->isReferenced());
1872
1873 // Use scoped_ptr to make sure the context is always freed.
1874 std::unique_ptr<gl::Context> unique_context(context);
1875 ASSERT(contexts->find(context->id().value) != contexts->end());
1876 contexts->erase(context->id().value);
1877
1878 return unique_context;
1879 }
1880
releaseContextImpl(std::unique_ptr<gl::Context> && context)1881 Error Display::releaseContextImpl(std::unique_ptr<gl::Context> &&context)
1882 {
1883 if (context->usingDisplayTextureShareGroup())
1884 {
1885 ASSERT(mGlobalTextureShareGroupUsers >= 1 && mTextureManager != nullptr);
1886 if (mGlobalTextureShareGroupUsers == 1)
1887 {
1888 // If this is the last context using the global share group, destroy the global
1889 // texture manager so that the textures can be destroyed while a context still
1890 // exists
1891 mTextureManager->release(context.get());
1892 mTextureManager = nullptr;
1893 }
1894 mGlobalTextureShareGroupUsers--;
1895 }
1896
1897 if (context->usingDisplaySemaphoreShareGroup())
1898 {
1899 ASSERT(mGlobalSemaphoreShareGroupUsers >= 1 && mSemaphoreManager != nullptr);
1900 if (mGlobalSemaphoreShareGroupUsers == 1)
1901 {
1902 // If this is the last context using the global share group, destroy the global
1903 // semaphore manager so that the semaphores can be destroyed while a context still
1904 // exists
1905 mSemaphoreManager->release(context.get());
1906 mSemaphoreManager = nullptr;
1907 }
1908 mGlobalSemaphoreShareGroupUsers--;
1909 }
1910
1911 ANGLE_TRY(context->onDestroy(this));
1912
1913 return NoError();
1914 }
1915
destroyContext(Thread * thread,gl::Context * context)1916 Error Display::destroyContext(Thread *thread, gl::Context *context)
1917 {
1918 auto *currentContext = thread->getContext();
1919 auto *currentDrawSurface = thread->getCurrentDrawSurface();
1920 auto *currentReadSurface = thread->getCurrentReadSurface();
1921
1922 context->setIsDestroyed();
1923
1924 // If the context is still current on at least 1 thread, just return since it'll be released
1925 // once no threads have it current anymore.
1926 if (context->isReferenced())
1927 {
1928 return NoError();
1929 }
1930
1931 // For external context, we cannot change the current native context, and the API user should
1932 // make sure the native context is current.
1933 if (context->isExternal())
1934 {
1935 // Need AddRefLock because there may be ContextMutex destruction.
1936 ScopedContextMutexAddRefLock lock(context->getContextMutex());
1937 ANGLE_TRY(releaseContext(context, thread));
1938 }
1939 else
1940 {
1941 // Keep |currentContext| alive, while releasing |context|.
1942 gl::ScopedContextRef scopedContextRef(currentContext);
1943
1944 // keep |currentDrawSurface| and |currentReadSurface| alive as well
1945 // while releasing |context|.
1946 ScopedSurfaceRef drawSurfaceRef(currentDrawSurface);
1947 ScopedSurfaceRef readSurfaceRef(
1948 currentReadSurface == currentDrawSurface ? nullptr : currentReadSurface);
1949
1950 // Make the context current, so we can release resources belong to the context, and then
1951 // when context is released from the current, it will be destroyed.
1952 // TODO(http://anglebug.com/42264840): Don't require a Context to be current in order to
1953 // destroy it.
1954 ANGLE_TRY(makeCurrent(thread, currentContext, nullptr, nullptr, context));
1955 ANGLE_TRY(
1956 makeCurrent(thread, context, currentDrawSurface, currentReadSurface, currentContext));
1957 }
1958
1959 return NoError();
1960 }
1961
destroySyncImpl(SyncID syncId,SyncMap * syncs)1962 void Display::destroySyncImpl(SyncID syncId, SyncMap *syncs)
1963 {
1964 auto iter = syncs->find(syncId.value);
1965 ASSERT(iter != syncs->end());
1966 mSyncHandleAllocator.release(syncId.value);
1967
1968 auto &sync = iter->second;
1969 sync->onDestroy(this);
1970
1971 SyncPool &pool = mSyncPools[sync->getType()];
1972 if (pool.size() < kMaxSyncPoolSizePerType)
1973 {
1974 pool.push_back(std::move(sync));
1975 }
1976
1977 syncs->erase(iter);
1978 }
1979
destroyImage(Image * image)1980 void Display::destroyImage(Image *image)
1981 {
1982 return destroyImageImpl(image, &mImageMap);
1983 }
1984
destroyStream(Stream * stream)1985 void Display::destroyStream(Stream *stream)
1986 {
1987 return destroyStreamImpl(stream, &mStreamSet);
1988 }
1989
destroySurface(Surface * surface)1990 Error Display::destroySurface(Surface *surface)
1991 {
1992 return destroySurfaceImpl(surface, &mState.surfaceMap);
1993 }
1994
destroySync(Sync * sync)1995 void Display::destroySync(Sync *sync)
1996 {
1997 return destroySyncImpl(sync->id(), &mSyncMap);
1998 }
1999
isDeviceLost() const2000 bool Display::isDeviceLost() const
2001 {
2002 ASSERT(isInitialized());
2003 return mState.deviceLost;
2004 }
2005
testDeviceLost()2006 bool Display::testDeviceLost()
2007 {
2008 ASSERT(isInitialized());
2009
2010 if (!mState.deviceLost && mImplementation->testDeviceLost())
2011 {
2012 notifyDeviceLost();
2013 }
2014
2015 return mState.deviceLost;
2016 }
2017
notifyDeviceLost()2018 void Display::notifyDeviceLost()
2019 {
2020 mState.notifyDeviceLost();
2021 }
2022
setBlobCacheFuncs(EGLSetBlobFuncANDROID set,EGLGetBlobFuncANDROID get)2023 void Display::setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get)
2024 {
2025 mBlobCache.setBlobCacheFuncs(set, get);
2026 mImplementation->setBlobCacheFuncs(set, get);
2027 }
2028
2029 // static
GetNativeClientBuffer(const AHardwareBuffer * buffer)2030 EGLClientBuffer Display::GetNativeClientBuffer(const AHardwareBuffer *buffer)
2031 {
2032 return angle::android::AHardwareBufferToClientBuffer(buffer);
2033 }
2034
2035 // static
CreateNativeClientBuffer(const egl::AttributeMap & attribMap,EGLClientBuffer * eglClientBuffer)2036 Error Display::CreateNativeClientBuffer(const egl::AttributeMap &attribMap,
2037 EGLClientBuffer *eglClientBuffer)
2038 {
2039 int androidHardwareBufferFormat = gl::GetAndroidHardwareBufferFormatFromChannelSizes(attribMap);
2040 int width = attribMap.getAsInt(EGL_WIDTH, 0);
2041 int height = attribMap.getAsInt(EGL_HEIGHT, 0);
2042 int usage = attribMap.getAsInt(EGL_NATIVE_BUFFER_USAGE_ANDROID, 0);
2043
2044 // https://developer.android.com/ndk/reference/group/a-hardware-buffer#ahardwarebuffer_lock
2045 // for AHardwareBuffer_lock()
2046 // The passed AHardwareBuffer must have one layer, otherwise the call will fail.
2047 constexpr int kLayerCount = 1;
2048
2049 *eglClientBuffer = angle::android::CreateEGLClientBufferFromAHardwareBuffer(
2050 width, height, kLayerCount, androidHardwareBufferFormat, usage);
2051
2052 return (*eglClientBuffer == nullptr)
2053 ? egl::Error(EGL_BAD_PARAMETER, "native client buffer allocation failed.")
2054 : NoError();
2055 }
2056
waitClient(const gl::Context * context)2057 Error Display::waitClient(const gl::Context *context)
2058 {
2059 return mImplementation->waitClient(context);
2060 }
2061
waitNative(const gl::Context * context,EGLint engine)2062 Error Display::waitNative(const gl::Context *context, EGLint engine)
2063 {
2064 return mImplementation->waitNative(context, engine);
2065 }
2066
getCaps() const2067 const Caps &Display::getCaps() const
2068 {
2069 return mCaps;
2070 }
2071
isInitialized() const2072 bool Display::isInitialized() const
2073 {
2074 return mInitialized;
2075 }
2076
isValidConfig(const Config * config) const2077 bool Display::isValidConfig(const Config *config) const
2078 {
2079 return mConfigSet.contains(config);
2080 }
2081
isValidContext(const gl::ContextID contextID) const2082 bool Display::isValidContext(const gl::ContextID contextID) const
2083 {
2084 return getContext(contextID) != nullptr;
2085 }
2086
isValidSurface(SurfaceID surfaceID) const2087 bool Display::isValidSurface(SurfaceID surfaceID) const
2088 {
2089 return getSurface(surfaceID) != nullptr;
2090 }
2091
isValidImage(ImageID imageID) const2092 bool Display::isValidImage(ImageID imageID) const
2093 {
2094 return getImage(imageID) != nullptr;
2095 }
2096
isValidStream(const Stream * stream) const2097 bool Display::isValidStream(const Stream *stream) const
2098 {
2099 return mStreamSet.find(const_cast<Stream *>(stream)) != mStreamSet.end();
2100 }
2101
isValidSync(SyncID syncID) const2102 bool Display::isValidSync(SyncID syncID) const
2103 {
2104 return getSync(syncID) != nullptr;
2105 }
2106
hasExistingWindowSurface(EGLNativeWindowType window)2107 bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
2108 {
2109 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
2110 ASSERT(windowSurfaces);
2111
2112 return windowSurfaces->find(window) != windowSurfaces->end();
2113 }
2114
GenerateClientExtensions()2115 static ClientExtensions GenerateClientExtensions()
2116 {
2117 ClientExtensions extensions;
2118
2119 extensions.clientExtensions = true;
2120 extensions.platformBase = true;
2121 extensions.platformANGLE = true;
2122
2123 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
2124 extensions.platformANGLED3D = true;
2125 extensions.platformDevice = true;
2126 #endif
2127
2128 #if defined(ANGLE_USE_GBM)
2129 extensions.platformGbmKHR = true;
2130 #endif
2131
2132 #if defined(ANGLE_USE_WAYLAND)
2133 extensions.platformWaylandEXT = true;
2134 #endif
2135
2136 #if defined(ANGLE_PLATFORM_LINUX) && (defined(ANGLE_ENABLE_OPENGL) || defined(ANGLE_ENABLE_VULKAN))
2137 extensions.platformSurfacelessMESA = true;
2138 #endif
2139
2140 #if defined(ANGLE_ENABLE_D3D11)
2141 extensions.platformANGLED3D11ON12 = angle::IsWindows10OrLater();
2142 extensions.platformANGLED3DLUID = true;
2143 extensions.platformANGLEDeviceId = true;
2144 #endif
2145
2146 #if defined(ANGLE_ENABLE_OPENGL)
2147 extensions.platformANGLEOpenGL = true;
2148 #endif
2149
2150 #if defined(ANGLE_ENABLE_NULL)
2151 extensions.platformANGLENULL = true;
2152 #endif
2153
2154 #if defined(ANGLE_ENABLE_WGPU)
2155 extensions.platformANGLEWebgpu = true;
2156 #endif
2157
2158 #if defined(ANGLE_ENABLE_D3D11)
2159 extensions.deviceCreation = true;
2160 extensions.deviceCreationD3D11 = true;
2161 extensions.experimentalPresentPath = true;
2162 #endif
2163
2164 #if defined(ANGLE_ENABLE_VULKAN)
2165 extensions.platformANGLEVulkan = true;
2166 extensions.platformANGLEVulkanDeviceUUID = true;
2167 extensions.platformANGLEDeviceId = true;
2168 #endif
2169
2170 #if defined(ANGLE_ENABLE_SWIFTSHADER)
2171 extensions.platformANGLEDeviceTypeSwiftShader = true;
2172 #endif
2173
2174 #if defined(ANGLE_ENABLE_METAL)
2175 extensions.platformANGLEMetal = true;
2176 extensions.platformANGLEDeviceId = true;
2177 #endif
2178
2179 #if defined(ANGLE_USE_X11)
2180 extensions.x11Visual = true;
2181 #endif
2182
2183 #if defined(ANGLE_PLATFORM_LINUX)
2184 extensions.platformANGLEDeviceTypeEGLANGLE = true;
2185 #endif
2186
2187 #if defined(ANGLE_ENABLE_CGL)
2188 extensions.platformANGLEDeviceContextVolatileCgl = true;
2189 #endif
2190
2191 #if defined(ANGLE_ENABLE_METAL)
2192 extensions.displayPowerPreferenceANGLE = true;
2193 #endif
2194
2195 extensions.clientGetAllProcAddresses = true;
2196 extensions.debug = true;
2197 extensions.featureControlANGLE = true;
2198 extensions.deviceQueryEXT = true;
2199 extensions.noErrorANGLE = true;
2200
2201 return extensions;
2202 }
2203
2204 template <typename T>
GenerateExtensionsString(const T & extensions)2205 static std::string GenerateExtensionsString(const T &extensions)
2206 {
2207 std::vector<std::string> extensionsVector = extensions.getStrings();
2208
2209 std::ostringstream stream;
2210 std::copy(extensionsVector.begin(), extensionsVector.end(),
2211 std::ostream_iterator<std::string>(stream, " "));
2212 return stream.str();
2213 }
2214
2215 // static
GetClientExtensions()2216 const ClientExtensions &Display::GetClientExtensions()
2217 {
2218 static const ClientExtensions clientExtensions = GenerateClientExtensions();
2219 return clientExtensions;
2220 }
2221
2222 // static
GetClientExtensionString()2223 const std::string &Display::GetClientExtensionString()
2224 {
2225 static const angle::base::NoDestructor<std::string> clientExtensionsString(
2226 GenerateExtensionsString(GetClientExtensions()));
2227 return *clientExtensionsString;
2228 }
2229
initDisplayExtensions()2230 void Display::initDisplayExtensions()
2231 {
2232 mDisplayExtensions = mImplementation->getExtensions();
2233
2234 // Some extensions are always available because they are implemented in the EGL layer.
2235 mDisplayExtensions.createContext = true;
2236 mDisplayExtensions.createContextNoError = !mFrontendFeatures.forceGlErrorChecking.enabled;
2237 mDisplayExtensions.createContextWebGLCompatibility = true;
2238 mDisplayExtensions.createContextBindGeneratesResource = true;
2239 mDisplayExtensions.createContextClientArrays = true;
2240 mDisplayExtensions.pixelFormatFloat = true;
2241 mDisplayExtensions.reusableSyncKHR = true;
2242
2243 // Force EGL_KHR_get_all_proc_addresses on.
2244 mDisplayExtensions.getAllProcAddresses = true;
2245
2246 // Enable program cache control since it is not back-end dependent.
2247 mDisplayExtensions.programCacheControlANGLE = true;
2248
2249 // Request extension is implemented in the ANGLE frontend
2250 mDisplayExtensions.createContextExtensionsEnabled = true;
2251
2252 // Blob cache extension is provided by the ANGLE frontend
2253 mDisplayExtensions.blobCache = true;
2254
2255 // The EGL_ANDROID_recordable extension is provided by the ANGLE frontend, and will always
2256 // say that ANativeWindow is not recordable.
2257 mDisplayExtensions.recordable = true;
2258
2259 // All backends support specific context versions
2260 mDisplayExtensions.createContextBackwardsCompatible = true;
2261
2262 // EGL_ANGLE_memory_usage_report is implemented on front end.
2263 mDisplayExtensions.memoryUsageReportANGLE = true;
2264
2265 mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions);
2266 }
2267
isValidNativeWindow(EGLNativeWindowType window) const2268 bool Display::isValidNativeWindow(EGLNativeWindowType window) const
2269 {
2270 return mImplementation->isValidNativeWindow(window);
2271 }
2272
validateClientBuffer(const Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const AttributeMap & attribs) const2273 Error Display::validateClientBuffer(const Config *configuration,
2274 EGLenum buftype,
2275 EGLClientBuffer clientBuffer,
2276 const AttributeMap &attribs) const
2277 {
2278 return mImplementation->validateClientBuffer(configuration, buftype, clientBuffer, attribs);
2279 }
2280
validateImageClientBuffer(const gl::Context * context,EGLenum target,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const2281 Error Display::validateImageClientBuffer(const gl::Context *context,
2282 EGLenum target,
2283 EGLClientBuffer clientBuffer,
2284 const egl::AttributeMap &attribs) const
2285 {
2286 return mImplementation->validateImageClientBuffer(context, target, clientBuffer, attribs);
2287 }
2288
valdiatePixmap(const Config * config,EGLNativePixmapType pixmap,const AttributeMap & attributes) const2289 Error Display::valdiatePixmap(const Config *config,
2290 EGLNativePixmapType pixmap,
2291 const AttributeMap &attributes) const
2292 {
2293 return mImplementation->validatePixmap(config, pixmap, attributes);
2294 }
2295
isValidDisplay(const egl::Display * display)2296 bool Display::isValidDisplay(const egl::Display *display)
2297 {
2298 {
2299 std::lock_guard<angle::SimpleMutex> lock(*ANGLEPlatformDisplayMapMutex());
2300 const ANGLEPlatformDisplayMap *anglePlatformDisplayMap = GetANGLEPlatformDisplayMap();
2301 for (const auto &displayPair : *anglePlatformDisplayMap)
2302 {
2303 if (displayPair.second == display)
2304 {
2305 return true;
2306 }
2307 }
2308 }
2309
2310 {
2311 std::lock_guard<angle::SimpleMutex> lock(*DevicePlatformDisplayMapMutex());
2312 const DevicePlatformDisplayMap *devicePlatformDisplayMap = GetDevicePlatformDisplayMap();
2313 for (const auto &displayPair : *devicePlatformDisplayMap)
2314 {
2315 if (displayPair.second == display)
2316 {
2317 return true;
2318 }
2319 }
2320 }
2321
2322 return false;
2323 }
2324
isValidNativeDisplay(EGLNativeDisplayType display)2325 bool Display::isValidNativeDisplay(EGLNativeDisplayType display)
2326 {
2327 // TODO(jmadill): handle this properly
2328 if (display == EGL_DEFAULT_DISPLAY)
2329 {
2330 return true;
2331 }
2332
2333 #if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_ENABLE_WINDOWS_UWP)
2334 if (display == EGL_SOFTWARE_DISPLAY_ANGLE || display == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
2335 display == EGL_D3D11_ONLY_DISPLAY_ANGLE)
2336 {
2337 return true;
2338 }
2339 return (WindowFromDC(display) != nullptr);
2340 #else
2341 return true;
2342 #endif
2343 }
2344
initVendorString()2345 void Display::initVendorString()
2346 {
2347 mVendorString = "Google Inc.";
2348 std::string vendorStringImpl = mImplementation->getVendorString();
2349 if (!vendorStringImpl.empty())
2350 {
2351 mVendorString += " (" + vendorStringImpl + ")";
2352 }
2353 }
2354
initVersionString()2355 void Display::initVersionString()
2356 {
2357 mVersionString = mImplementation->getVersionString(true);
2358 }
2359
initClientAPIString()2360 void Display::initClientAPIString()
2361 {
2362 mClientAPIString = "OpenGL_ES";
2363 }
2364
initializeFrontendFeatures()2365 void Display::initializeFrontendFeatures()
2366 {
2367 // Enable on all Impls
2368 ANGLE_FEATURE_CONDITION(&mFrontendFeatures, loseContextOnOutOfMemory, true);
2369 ANGLE_FEATURE_CONDITION(&mFrontendFeatures, allowCompressedFormats, true);
2370
2371 // Togglable until work on the extension is complete - anglebug.com/40096838.
2372 ANGLE_FEATURE_CONDITION(&mFrontendFeatures, emulatePixelLocalStorage, true);
2373
2374 ANGLE_FEATURE_CONDITION(&mFrontendFeatures, forceMinimumMaxVertexAttributes, false);
2375
2376 // Reject shaders with undefined behavior. In the compiler, this only applies to WebGL.
2377 ANGLE_FEATURE_CONDITION(&mFrontendFeatures, rejectWebglShadersWithUndefinedBehavior, true);
2378
2379 mImplementation->initializeFrontendFeatures(&mFrontendFeatures);
2380 }
2381
getExtensions() const2382 const DisplayExtensions &Display::getExtensions() const
2383 {
2384 return mDisplayExtensions;
2385 }
2386
getExtensionString() const2387 const std::string &Display::getExtensionString() const
2388 {
2389 return mDisplayExtensionString;
2390 }
2391
getVendorString() const2392 const std::string &Display::getVendorString() const
2393 {
2394 return mVendorString;
2395 }
2396
getVersionString() const2397 const std::string &Display::getVersionString() const
2398 {
2399 return mVersionString;
2400 }
2401
getClientAPIString() const2402 const std::string &Display::getClientAPIString() const
2403 {
2404 return mClientAPIString;
2405 }
2406
getBackendRendererDescription() const2407 std::string Display::getBackendRendererDescription() const
2408 {
2409 return mImplementation->getRendererDescription();
2410 }
2411
getBackendVendorString() const2412 std::string Display::getBackendVendorString() const
2413 {
2414 return mImplementation->getVendorString();
2415 }
2416
getBackendVersionString(bool includeFullVersion) const2417 std::string Display::getBackendVersionString(bool includeFullVersion) const
2418 {
2419 return mImplementation->getVersionString(includeFullVersion);
2420 }
2421
getDevice() const2422 Device *Display::getDevice() const
2423 {
2424 return mDevice;
2425 }
2426
getWGLSurface() const2427 Surface *Display::getWGLSurface() const
2428 {
2429 return mSurface;
2430 }
2431
getMaxSupportedESVersion() const2432 gl::Version Display::getMaxSupportedESVersion() const
2433 {
2434 return mImplementation->getMaxSupportedESVersion();
2435 }
2436
programCacheGetAttrib(EGLenum attrib) const2437 EGLint Display::programCacheGetAttrib(EGLenum attrib) const
2438 {
2439 switch (attrib)
2440 {
2441 case EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE:
2442 return static_cast<EGLint>(BlobCache::kKeyLength);
2443
2444 case EGL_PROGRAM_CACHE_SIZE_ANGLE:
2445 return static_cast<EGLint>(mMemoryProgramCache.entryCount());
2446
2447 default:
2448 UNREACHABLE();
2449 return 0;
2450 }
2451 }
2452
programCacheQuery(EGLint index,void * key,EGLint * keysize,void * binary,EGLint * binarysize)2453 Error Display::programCacheQuery(EGLint index,
2454 void *key,
2455 EGLint *keysize,
2456 void *binary,
2457 EGLint *binarysize)
2458 {
2459 ASSERT(index >= 0 && index < static_cast<EGLint>(mMemoryProgramCache.entryCount()));
2460
2461 const BlobCache::Key *programHash = nullptr;
2462 BlobCache::Value programBinary;
2463 // TODO(jmadill): Make this thread-safe.
2464 bool result =
2465 mMemoryProgramCache.getAt(static_cast<size_t>(index), &programHash, &programBinary);
2466 if (!result)
2467 {
2468 return egl::Error(EGL_BAD_ACCESS, "Program binary not accessible.");
2469 }
2470
2471 ASSERT(keysize && binarysize);
2472
2473 if (key)
2474 {
2475 ASSERT(*keysize == static_cast<EGLint>(BlobCache::kKeyLength));
2476 memcpy(key, programHash->data(), BlobCache::kKeyLength);
2477 }
2478
2479 if (binary)
2480 {
2481 // Note: we check the size here instead of in the validation code, since we need to
2482 // access the cache as atomically as possible. It's possible that the cache contents
2483 // could change between the validation size check and the retrieval.
2484 if (programBinary.size() > static_cast<size_t>(*binarysize))
2485 {
2486 return egl::Error(EGL_BAD_ACCESS, "Program binary too large or changed during access.");
2487 }
2488
2489 memcpy(binary, programBinary.data(), programBinary.size());
2490 }
2491
2492 *binarysize = static_cast<EGLint>(programBinary.size());
2493 *keysize = static_cast<EGLint>(BlobCache::kKeyLength);
2494
2495 return NoError();
2496 }
2497
programCachePopulate(const void * key,EGLint keysize,const void * binary,EGLint binarysize)2498 Error Display::programCachePopulate(const void *key,
2499 EGLint keysize,
2500 const void *binary,
2501 EGLint binarysize)
2502 {
2503 ASSERT(keysize == static_cast<EGLint>(BlobCache::kKeyLength));
2504
2505 BlobCache::Key programHash;
2506 memcpy(programHash.data(), key, BlobCache::kKeyLength);
2507
2508 if (!mMemoryProgramCache.putBinary(programHash, reinterpret_cast<const uint8_t *>(binary),
2509 static_cast<size_t>(binarysize)))
2510 {
2511 return egl::Error(EGL_BAD_ACCESS, "Failed to copy program binary into the cache.");
2512 }
2513
2514 return NoError();
2515 }
2516
programCacheResize(EGLint limit,EGLenum mode)2517 EGLint Display::programCacheResize(EGLint limit, EGLenum mode)
2518 {
2519 switch (mode)
2520 {
2521 case EGL_PROGRAM_CACHE_RESIZE_ANGLE:
2522 {
2523 size_t initialSize = mMemoryProgramCache.size();
2524 mMemoryProgramCache.resize(static_cast<size_t>(limit));
2525 return static_cast<EGLint>(initialSize);
2526 }
2527
2528 case EGL_PROGRAM_CACHE_TRIM_ANGLE:
2529 return static_cast<EGLint>(mMemoryProgramCache.trim(static_cast<size_t>(limit)));
2530
2531 default:
2532 UNREACHABLE();
2533 return 0;
2534 }
2535 }
2536
overrideFrontendFeatures(const std::vector<std::string> & featureNames,bool enabled)2537 void Display::overrideFrontendFeatures(const std::vector<std::string> &featureNames, bool enabled)
2538 {
2539 mFrontendFeatures.overrideFeatures(featureNames, enabled);
2540 }
2541
queryStringi(const EGLint name,const EGLint index)2542 const char *Display::queryStringi(const EGLint name, const EGLint index)
2543 {
2544 const char *result = nullptr;
2545 switch (name)
2546 {
2547 case EGL_FEATURE_NAME_ANGLE:
2548 result = mFeatures[index]->name;
2549 break;
2550 case EGL_FEATURE_CATEGORY_ANGLE:
2551 result = angle::FeatureCategoryToString(mFeatures[index]->category);
2552 break;
2553 case EGL_FEATURE_STATUS_ANGLE:
2554 result = angle::FeatureStatusToString(mFeatures[index]->enabled);
2555 break;
2556 default:
2557 UNREACHABLE();
2558 return nullptr;
2559 }
2560 return result;
2561 }
2562
queryAttrib(const EGLint attribute)2563 EGLAttrib Display::queryAttrib(const EGLint attribute)
2564 {
2565 EGLAttrib value = 0;
2566 switch (attribute)
2567 {
2568 case EGL_DEVICE_EXT:
2569 value = reinterpret_cast<EGLAttrib>(mDevice);
2570 break;
2571
2572 case EGL_FEATURE_COUNT_ANGLE:
2573 value = mFeatures.size();
2574 break;
2575
2576 default:
2577 UNREACHABLE();
2578 }
2579 return value;
2580 }
2581
requestScratchBuffer()2582 angle::ScratchBuffer Display::requestScratchBuffer()
2583 {
2584 return requestScratchBufferImpl(&mScratchBuffers);
2585 }
2586
returnScratchBuffer(angle::ScratchBuffer scratchBuffer)2587 void Display::returnScratchBuffer(angle::ScratchBuffer scratchBuffer)
2588 {
2589 returnScratchBufferImpl(std::move(scratchBuffer), &mScratchBuffers);
2590 }
2591
requestZeroFilledBuffer()2592 angle::ScratchBuffer Display::requestZeroFilledBuffer()
2593 {
2594 return requestScratchBufferImpl(&mZeroFilledBuffers);
2595 }
2596
returnZeroFilledBuffer(angle::ScratchBuffer zeroFilledBuffer)2597 void Display::returnZeroFilledBuffer(angle::ScratchBuffer zeroFilledBuffer)
2598 {
2599 returnScratchBufferImpl(std::move(zeroFilledBuffer), &mZeroFilledBuffers);
2600 }
2601
requestScratchBufferImpl(std::vector<angle::ScratchBuffer> * bufferVector)2602 angle::ScratchBuffer Display::requestScratchBufferImpl(
2603 std::vector<angle::ScratchBuffer> *bufferVector)
2604 {
2605 std::lock_guard<angle::SimpleMutex> lock(mScratchBufferMutex);
2606 if (!bufferVector->empty())
2607 {
2608 angle::ScratchBuffer buffer = std::move(bufferVector->back());
2609 bufferVector->pop_back();
2610 return buffer;
2611 }
2612
2613 return angle::ScratchBuffer(kScratchBufferLifetime);
2614 }
2615
returnScratchBufferImpl(angle::ScratchBuffer scratchBuffer,std::vector<angle::ScratchBuffer> * bufferVector)2616 void Display::returnScratchBufferImpl(angle::ScratchBuffer scratchBuffer,
2617 std::vector<angle::ScratchBuffer> *bufferVector)
2618 {
2619 std::lock_guard<angle::SimpleMutex> lock(mScratchBufferMutex);
2620 bufferVector->push_back(std::move(scratchBuffer));
2621 }
2622
handleGPUSwitch()2623 Error Display::handleGPUSwitch()
2624 {
2625 ANGLE_TRY(mImplementation->handleGPUSwitch());
2626 initVendorString();
2627 return NoError();
2628 }
2629
forceGPUSwitch(EGLint gpuIDHigh,EGLint gpuIDLow)2630 Error Display::forceGPUSwitch(EGLint gpuIDHigh, EGLint gpuIDLow)
2631 {
2632 ANGLE_TRY(mImplementation->forceGPUSwitch(gpuIDHigh, gpuIDLow));
2633 initVendorString();
2634 return NoError();
2635 }
2636
waitUntilWorkScheduled()2637 Error Display::waitUntilWorkScheduled()
2638 {
2639 ANGLE_TRY(mImplementation->waitUntilWorkScheduled());
2640 return NoError();
2641 }
2642
lockVulkanQueue()2643 void Display::lockVulkanQueue()
2644 {
2645 return mImplementation->lockVulkanQueue();
2646 }
2647
unlockVulkanQueue()2648 void Display::unlockVulkanQueue()
2649 {
2650 return mImplementation->unlockVulkanQueue();
2651 }
2652
supportsDmaBufFormat(EGLint format) const2653 bool Display::supportsDmaBufFormat(EGLint format) const
2654 {
2655 return mImplementation->supportsDmaBufFormat(format);
2656 }
2657
queryDmaBufFormats(EGLint max_formats,EGLint * formats,EGLint * num_formats)2658 Error Display::queryDmaBufFormats(EGLint max_formats, EGLint *formats, EGLint *num_formats)
2659 {
2660 ANGLE_TRY(mImplementation->queryDmaBufFormats(max_formats, formats, num_formats));
2661 return NoError();
2662 }
2663
queryDmaBufModifiers(EGLint format,EGLint max_modifiers,EGLuint64KHR * modifiers,EGLBoolean * external_only,EGLint * num_modifiers)2664 Error Display::queryDmaBufModifiers(EGLint format,
2665 EGLint max_modifiers,
2666 EGLuint64KHR *modifiers,
2667 EGLBoolean *external_only,
2668 EGLint *num_modifiers)
2669 {
2670 ANGLE_TRY(mImplementation->queryDmaBufModifiers(format, max_modifiers, modifiers, external_only,
2671 num_modifiers));
2672 return NoError();
2673 }
2674
querySupportedCompressionRates(const Config * configuration,const AttributeMap & attributes,EGLint * rates,EGLint rate_size,EGLint * num_rates) const2675 Error Display::querySupportedCompressionRates(const Config *configuration,
2676 const AttributeMap &attributes,
2677 EGLint *rates,
2678 EGLint rate_size,
2679 EGLint *num_rates) const
2680 {
2681 ANGLE_TRY(mImplementation->querySupportedCompressionRates(configuration, attributes, rates,
2682 rate_size, num_rates));
2683
2684 return NoError();
2685 }
2686
getImageLoadContext() const2687 angle::ImageLoadContext Display::getImageLoadContext() const
2688 {
2689 angle::ImageLoadContext imageLoadContext;
2690
2691 imageLoadContext.singleThreadPool = mState.singleThreadPool;
2692 imageLoadContext.multiThreadPool = mFrontendFeatures.singleThreadedTextureDecompression.enabled
2693 ? nullptr
2694 : mState.multiThreadPool;
2695
2696 return imageLoadContext;
2697 }
2698
getContext(gl::ContextID contextID) const2699 const gl::Context *Display::getContext(gl::ContextID contextID) const
2700 {
2701 std::lock_guard<angle::SimpleMutex> lock(mState.contextMapMutex);
2702 auto iter = mState.contextMap.find(contextID.value);
2703 return iter != mState.contextMap.end() ? iter->second : nullptr;
2704 }
2705
getSurface(egl::SurfaceID surfaceID) const2706 const egl::Surface *Display::getSurface(egl::SurfaceID surfaceID) const
2707 {
2708 auto iter = mState.surfaceMap.find(surfaceID.value);
2709 return iter != mState.surfaceMap.end() ? iter->second : nullptr;
2710 }
2711
getImage(egl::ImageID imageID) const2712 const egl::Image *Display::getImage(egl::ImageID imageID) const
2713 {
2714 auto iter = mImageMap.find(imageID.value);
2715 return iter != mImageMap.end() ? iter->second : nullptr;
2716 }
2717
getSync(egl::SyncID syncID) const2718 const egl::Sync *Display::getSync(egl::SyncID syncID) const
2719 {
2720 auto iter = mSyncMap.find(syncID.value);
2721 return iter != mSyncMap.end() ? iter->second.get() : nullptr;
2722 }
2723
getContext(gl::ContextID contextID)2724 gl::Context *Display::getContext(gl::ContextID contextID)
2725 {
2726 std::lock_guard<angle::SimpleMutex> lock(mState.contextMapMutex);
2727 auto iter = mState.contextMap.find(contextID.value);
2728 return iter != mState.contextMap.end() ? iter->second : nullptr;
2729 }
2730
getSurface(egl::SurfaceID surfaceID)2731 egl::Surface *Display::getSurface(egl::SurfaceID surfaceID)
2732 {
2733 auto iter = mState.surfaceMap.find(surfaceID.value);
2734 return iter != mState.surfaceMap.end() ? iter->second : nullptr;
2735 }
2736
getImage(egl::ImageID imageID)2737 egl::Image *Display::getImage(egl::ImageID imageID)
2738 {
2739 auto iter = mImageMap.find(imageID.value);
2740 return iter != mImageMap.end() ? iter->second : nullptr;
2741 }
2742
getSync(egl::SyncID syncID)2743 egl::Sync *Display::getSync(egl::SyncID syncID)
2744 {
2745 auto iter = mSyncMap.find(syncID.value);
2746 return iter != mSyncMap.end() ? iter->second.get() : nullptr;
2747 }
2748
2749 // static
InitTLS()2750 void Display::InitTLS()
2751 {
2752 TLSData *tlsData = new TLSData;
2753
2754 #if defined(ANGLE_PLATFORM_APPLE)
2755 SetDisplayTLS(tlsData);
2756 #else
2757 gDisplayTLS = tlsData;
2758 #endif
2759 }
2760
2761 // static
GetCurrentThreadUnlockedTailCall()2762 angle::UnlockedTailCall *Display::GetCurrentThreadUnlockedTailCall()
2763 {
2764 return &GetDisplayTLS()->unlockedTailCall;
2765 }
2766
2767 // static
GetCurrentThreadErrorScratchSpace()2768 Error *Display::GetCurrentThreadErrorScratchSpace()
2769 {
2770 return &GetDisplayTLS()->errorScratchSpace;
2771 }
2772 } // namespace egl
2773