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