1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // Display.cpp: Implements the egl::Display class, representing the abstract
8 // display on which graphics are drawn. Implements EGLDisplay.
9 // [EGL 1.4] section 2.1.2 page 3.
10
11 #include "libANGLE/Display.h"
12
13 #include <algorithm>
14 #include <iterator>
15 #include <map>
16 #include <sstream>
17 #include <vector>
18
19 #include <EGL/eglext.h>
20 #include <platform/Platform.h>
21
22 #include "anglebase/no_destructor.h"
23 #include "common/android_util.h"
24 #include "common/debug.h"
25 #include "common/mathutil.h"
26 #include "common/platform.h"
27 #include "common/string_utils.h"
28 #include "common/system_utils.h"
29 #include "common/utilities.h"
30 #include "libANGLE/Context.h"
31 #include "libANGLE/Device.h"
32 #include "libANGLE/EGLSync.h"
33 #include "libANGLE/Image.h"
34 #include "libANGLE/ResourceManager.h"
35 #include "libANGLE/Stream.h"
36 #include "libANGLE/Surface.h"
37 #include "libANGLE/Thread.h"
38 #include "libANGLE/histogram_macros.h"
39 #include "libANGLE/renderer/DeviceImpl.h"
40 #include "libANGLE/renderer/DisplayImpl.h"
41 #include "libANGLE/renderer/ImageImpl.h"
42 #include "libANGLE/trace.h"
43
44 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
45 # include <versionhelpers.h>
46
47 # include "libANGLE/renderer/d3d/DisplayD3D.h"
48 #endif
49
50 #if defined(ANGLE_ENABLE_OPENGL)
51 # if defined(ANGLE_PLATFORM_WINDOWS)
52 # include "libANGLE/renderer/gl/wgl/DisplayWGL.h"
53 # elif defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
54 # include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
55 # elif defined(ANGLE_PLATFORM_IOS)
56 # include "libANGLE/renderer/gl/eagl/DisplayEAGL.h"
57 # elif defined(ANGLE_PLATFORM_LINUX)
58 # if defined(ANGLE_USE_OZONE)
59 # include "libANGLE/renderer/gl/egl/ozone/DisplayOzone.h"
60 # else
61 # include "libANGLE/renderer/gl/egl/DisplayEGL.h"
62 # if defined(ANGLE_USE_X11)
63 # include "libANGLE/renderer/gl/glx/DisplayGLX.h"
64 # endif
65 # endif
66 # elif defined(ANGLE_PLATFORM_ANDROID)
67 # include "libANGLE/renderer/gl/egl/android/DisplayAndroid.h"
68 # else
69 # error Unsupported OpenGL platform.
70 # endif
71 #endif
72
73 #if defined(ANGLE_ENABLE_NULL)
74 # include "libANGLE/renderer/null/DisplayNULL.h"
75 #endif // defined(ANGLE_ENABLE_NULL)
76
77 #if defined(ANGLE_ENABLE_VULKAN)
78 # include "libANGLE/renderer/vulkan/DisplayVk_api.h"
79 #endif // defined(ANGLE_ENABLE_VULKAN)
80
81 #if defined(ANGLE_ENABLE_METAL)
82 # include "libANGLE/renderer/metal/DisplayMtl_api.h"
83 #endif // defined(ANGLE_ENABLE_METAL)
84
85 namespace egl
86 {
87
88 namespace
89 {
90
91 typedef std::map<EGLNativeWindowType, Surface *> WindowSurfaceMap;
92 // Get a map of all EGL window surfaces to validate that no window has more than one EGL surface
93 // associated with it.
GetWindowSurfaces()94 static WindowSurfaceMap *GetWindowSurfaces()
95 {
96 static angle::base::NoDestructor<WindowSurfaceMap> windowSurfaces;
97 return windowSurfaces.get();
98 }
99
100 typedef std::map<EGLNativeDisplayType, Display *> ANGLEPlatformDisplayMap;
GetANGLEPlatformDisplayMap()101 static ANGLEPlatformDisplayMap *GetANGLEPlatformDisplayMap()
102 {
103 static angle::base::NoDestructor<ANGLEPlatformDisplayMap> displays;
104 return displays.get();
105 }
106
107 typedef std::map<Device *, Display *> DevicePlatformDisplayMap;
GetDevicePlatformDisplayMap()108 static DevicePlatformDisplayMap *GetDevicePlatformDisplayMap()
109 {
110 static angle::base::NoDestructor<DevicePlatformDisplayMap> displays;
111 return displays.get();
112 }
113
CreateDisplayFromDevice(Device * eglDevice,const DisplayState & state)114 rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice, const DisplayState &state)
115 {
116 rx::DisplayImpl *impl = nullptr;
117
118 switch (eglDevice->getType())
119 {
120 #if defined(ANGLE_ENABLE_D3D11)
121 case EGL_D3D11_DEVICE_ANGLE:
122 impl = new rx::DisplayD3D(state);
123 break;
124 #endif
125 #if defined(ANGLE_ENABLE_D3D9)
126 case EGL_D3D9_DEVICE_ANGLE:
127 // Currently the only way to get EGLDeviceEXT representing a D3D9 device
128 // is to retrieve one from an already-existing EGLDisplay.
129 // When eglGetPlatformDisplayEXT is called with a D3D9 EGLDeviceEXT,
130 // the already-existing display should be returned.
131 // Therefore this codepath to create a new display from the device
132 // should never be hit.
133 UNREACHABLE();
134 break;
135 #endif
136 default:
137 UNREACHABLE();
138 break;
139 }
140
141 ASSERT(impl != nullptr);
142 return impl;
143 }
144
145 // On platforms with support for multiple back-ends, allow an environment variable to control
146 // the default. This is useful to run angle with benchmarks without having to modify the
147 // benchmark source. Possible values for this environment variable (ANGLE_DEFAULT_PLATFORM)
148 // are: vulkan, gl, d3d11, null.
GetDisplayTypeFromEnvironment()149 EGLAttrib GetDisplayTypeFromEnvironment()
150 {
151 std::string angleDefaultEnv = angle::GetEnvironmentVar("ANGLE_DEFAULT_PLATFORM");
152 angle::ToLower(&angleDefaultEnv);
153
154 #if defined(ANGLE_ENABLE_VULKAN)
155 if ((angleDefaultEnv == "vulkan") || (angleDefaultEnv == "vulkan-null") ||
156 (angleDefaultEnv == "swiftshader"))
157 {
158 return EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
159 }
160 #endif
161
162 #if defined(ANGLE_ENABLE_OPENGL)
163 if (angleDefaultEnv == "gl")
164 {
165 return EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
166 }
167 #endif
168
169 #if defined(ANGLE_ENABLE_D3D11)
170 if (angleDefaultEnv == "d3d11")
171 {
172 return EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
173 }
174 #endif
175
176 #if defined(ANGLE_ENABLE_NULL)
177 if (angleDefaultEnv == "null")
178 {
179 return EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE;
180 }
181 #endif
182
183 #if defined(ANGLE_ENABLE_D3D11)
184 return EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
185 #elif defined(ANGLE_ENABLE_D3D9)
186 return EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
187 #elif defined(ANGLE_ENABLE_VULKAN) && defined(ANGLE_PLATFORM_ANDROID)
188 return EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
189 #elif defined(ANGLE_ENABLE_OPENGL)
190 # if defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_USE_OZONE)
191 return EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
192 # else
193 return EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
194 # endif
195 #elif defined(ANGLE_ENABLE_METAL)
196 return EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE;
197 #elif defined(ANGLE_ENABLE_VULKAN)
198 return EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
199 #elif defined(ANGLE_ENABLE_NULL)
200 return EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE;
201 #else
202 # error No default ANGLE platform type
203 #endif
204 }
205
GetDeviceTypeFromEnvironment()206 EGLAttrib GetDeviceTypeFromEnvironment()
207 {
208 std::string angleDefaultEnv = angle::GetEnvironmentVar("ANGLE_DEFAULT_PLATFORM");
209 angle::ToLower(&angleDefaultEnv);
210
211 #if defined(ANGLE_ENABLE_VULKAN)
212 if (angleDefaultEnv == "vulkan-null")
213 {
214 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE;
215 }
216 else if (angleDefaultEnv == "swiftshader")
217 {
218 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE;
219 }
220 #endif
221 return EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
222 }
223
CreateDisplayFromAttribs(EGLAttrib displayType,EGLAttrib deviceType,const DisplayState & state)224 rx::DisplayImpl *CreateDisplayFromAttribs(EGLAttrib displayType,
225 EGLAttrib deviceType,
226 const DisplayState &state)
227 {
228 ASSERT(displayType != EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
229 rx::DisplayImpl *impl = nullptr;
230
231 switch (displayType)
232 {
233 case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
234 UNREACHABLE();
235 break;
236
237 case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
238 case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
239 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
240 impl = new rx::DisplayD3D(state);
241 #else
242 // A D3D display was requested on a platform that doesn't support it
243 UNREACHABLE();
244 #endif
245 break;
246
247 case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
248 #if defined(ANGLE_ENABLE_OPENGL)
249 # if defined(ANGLE_PLATFORM_WINDOWS)
250 impl = new rx::DisplayWGL(state);
251 # elif defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
252 impl = new rx::DisplayCGL(state);
253 # elif defined(ANGLE_PLATFORM_IOS)
254 impl = new rx::DisplayEAGL(state);
255 # elif defined(ANGLE_PLATFORM_LINUX)
256 # if defined(ANGLE_USE_OZONE)
257 // This might work but has never been tried, so disallow for now.
258 impl = nullptr;
259 # else
260 if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE)
261 {
262 impl = new rx::DisplayEGL(state);
263 }
264 # if defined(ANGLE_USE_X11)
265 else
266 {
267 impl = new rx::DisplayGLX(state);
268 }
269 # endif
270 # endif
271 # elif defined(ANGLE_PLATFORM_ANDROID)
272 // No GL support on this platform, fail display creation.
273 impl = nullptr;
274 # else
275 # error Unsupported OpenGL platform.
276 # endif
277 #else
278 // No display available
279 UNREACHABLE();
280 #endif // defined(ANGLE_ENABLE_OPENGL)
281 break;
282
283 case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
284 #if defined(ANGLE_ENABLE_OPENGL)
285 # if defined(ANGLE_PLATFORM_WINDOWS)
286 impl = new rx::DisplayWGL(state);
287 # elif defined(ANGLE_PLATFORM_LINUX)
288 # if defined(ANGLE_USE_OZONE)
289 impl = new rx::DisplayOzone(state);
290 # else
291 if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE)
292 {
293 impl = new rx::DisplayEGL(state);
294 }
295 # if defined(ANGLE_USE_X11)
296 else
297 {
298 impl = new rx::DisplayGLX(state);
299 }
300 # endif
301 # endif
302 # elif defined(ANGLE_PLATFORM_ANDROID)
303 impl = new rx::DisplayAndroid(state);
304 # else
305 // No GLES support on this platform, fail display creation.
306 impl = nullptr;
307 # endif
308 #endif // defined(ANGLE_ENABLE_OPENGL)
309 break;
310
311 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
312 #if defined(ANGLE_ENABLE_VULKAN)
313 # if defined(ANGLE_PLATFORM_WINDOWS)
314 if (rx::IsVulkanWin32DisplayAvailable())
315 {
316 impl = rx::CreateVulkanWin32Display(state);
317 }
318 # elif defined(ANGLE_PLATFORM_LINUX)
319 if (rx::IsVulkanXcbDisplayAvailable())
320 {
321 impl = rx::CreateVulkanXcbDisplay(state);
322 }
323 # elif defined(ANGLE_PLATFORM_ANDROID)
324 if (rx::IsVulkanAndroidDisplayAvailable())
325 {
326 impl = rx::CreateVulkanAndroidDisplay(state);
327 }
328 # elif defined(ANGLE_PLATFORM_FUCHSIA)
329 if (rx::IsVulkanFuchsiaDisplayAvailable())
330 {
331 impl = rx::CreateVulkanFuchsiaDisplay(state);
332 }
333 # elif defined(ANGLE_PLATFORM_GGP)
334 if (rx::IsVulkanGGPDisplayAvailable())
335 {
336 impl = rx::CreateVulkanGGPDisplay(state);
337 }
338 # elif defined(ANGLE_PLATFORM_APPLE)
339 if (rx::IsVulkanMacDisplayAvailable())
340 {
341 impl = rx::CreateVulkanMacDisplay(state);
342 }
343 # else
344 # error Unsupported Vulkan platform.
345 # endif
346 #else
347 // No display available
348 UNREACHABLE();
349 #endif // defined(ANGLE_ENABLE_VULKAN)
350 break;
351 case EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE:
352 #if defined(ANGLE_ENABLE_METAL)
353 if (rx::IsMetalDisplayAvailable())
354 {
355 impl = rx::CreateMetalDisplay(state);
356 break;
357 }
358 #endif
359 // No display available
360 UNREACHABLE();
361 break;
362 case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE:
363 #if defined(ANGLE_ENABLE_NULL)
364 impl = new rx::DisplayNULL(state);
365 #else
366 // No display available
367 UNREACHABLE();
368 #endif // defined(ANGLE_ENABLE_NULL)
369 break;
370
371 default:
372 UNREACHABLE();
373 break;
374 }
375
376 return impl;
377 }
378
Display_logError(angle::PlatformMethods * platform,const char * errorMessage)379 void Display_logError(angle::PlatformMethods *platform, const char *errorMessage)
380 {
381 gl::Trace(gl::LOG_ERR, errorMessage);
382 }
383
Display_logWarning(angle::PlatformMethods * platform,const char * warningMessage)384 void Display_logWarning(angle::PlatformMethods *platform, const char *warningMessage)
385 {
386 gl::Trace(gl::LOG_WARN, warningMessage);
387 }
388
Display_logInfo(angle::PlatformMethods * platform,const char * infoMessage)389 void Display_logInfo(angle::PlatformMethods *platform, const char *infoMessage)
390 {
391 // Uncomment to get info spam
392 #if defined(ANGLE_ENABLE_DEBUG_TRACE)
393 gl::Trace(gl::LOG_INFO, infoMessage);
394 #endif
395 }
396
EGLStringArrayToStringVector(const char ** ary)397 const std::vector<std::string> EGLStringArrayToStringVector(const char **ary)
398 {
399 std::vector<std::string> vec;
400 if (ary != nullptr)
401 {
402 for (; *ary != nullptr; ary++)
403 {
404 vec.push_back(std::string(*ary));
405 }
406 }
407 return vec;
408 }
409
ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display)410 void ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display)
411 {
412 angle::PlatformMethods *platformMethods = ANGLEPlatformCurrent();
413
414 ANGLEResetDisplayPlatform(display);
415 platformMethods->logError = Display_logError;
416 platformMethods->logWarning = Display_logWarning;
417 platformMethods->logInfo = Display_logInfo;
418 }
419
420 static constexpr uint32_t kScratchBufferLifetime = 64u;
421
422 } // anonymous namespace
423
DisplayState(EGLNativeDisplayType nativeDisplayId)424 DisplayState::DisplayState(EGLNativeDisplayType nativeDisplayId)
425 : label(nullptr), featuresAllDisabled(false), displayId(nativeDisplayId)
426 {}
427
~DisplayState()428 DisplayState::~DisplayState() {}
429
430 // static
GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay,const AttributeMap & attribMap)431 Display *Display::GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay,
432 const AttributeMap &attribMap)
433 {
434 Display *display = nullptr;
435
436 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
437 const auto &iter = displays->find(nativeDisplay);
438 if (iter != displays->end())
439 {
440 display = iter->second;
441 }
442
443 if (display == nullptr)
444 {
445 // Validate the native display
446 if (!Display::isValidNativeDisplay(nativeDisplay))
447 {
448 return nullptr;
449 }
450
451 display = new Display(EGL_PLATFORM_ANGLE_ANGLE, nativeDisplay, nullptr);
452 displays->insert(std::make_pair(nativeDisplay, display));
453 }
454
455 // Apply new attributes if the display is not initialized yet.
456 if (!display->isInitialized())
457 {
458 display->setAttributes(attribMap);
459
460 display->updateAttribsFromEnvironment(attribMap);
461
462 EGLAttrib displayType = display->mAttributeMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
463 EGLAttrib deviceType = display->mAttributeMap.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
464 rx::DisplayImpl *impl =
465 CreateDisplayFromAttribs(displayType, deviceType, display->getState());
466 if (impl == nullptr)
467 {
468 // No valid display implementation for these attributes
469 return nullptr;
470 }
471
472 display->setupDisplayPlatform(impl);
473 }
474
475 return display;
476 }
477
478 // static
GetExistingDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay)479 Display *Display::GetExistingDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay)
480 {
481 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
482 const auto &iter = displays->find(nativeDisplay);
483
484 // Check that there is a matching display
485 if (iter == displays->end())
486 {
487 return nullptr;
488 }
489
490 return iter->second;
491 }
492
493 // static
GetDisplayFromDevice(Device * device,const AttributeMap & attribMap)494 Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attribMap)
495 {
496 Display *display = nullptr;
497
498 ASSERT(Device::IsValidDevice(device));
499
500 ANGLEPlatformDisplayMap *anglePlatformDisplays = GetANGLEPlatformDisplayMap();
501 DevicePlatformDisplayMap *devicePlatformDisplays = GetDevicePlatformDisplayMap();
502
503 // First see if this eglDevice is in use by a Display created using ANGLE platform
504 for (auto &displayMapEntry : *anglePlatformDisplays)
505 {
506 egl::Display *iterDisplay = displayMapEntry.second;
507 if (iterDisplay->getDevice() == device)
508 {
509 display = iterDisplay;
510 }
511 }
512
513 if (display == nullptr)
514 {
515 // See if the eglDevice is in use by a Display created using the DEVICE platform
516 const auto &iter = devicePlatformDisplays->find(device);
517 if (iter != devicePlatformDisplays->end())
518 {
519 display = iter->second;
520 }
521 }
522
523 if (display == nullptr)
524 {
525 // Otherwise create a new Display
526 display = new Display(EGL_PLATFORM_DEVICE_EXT, 0, device);
527 devicePlatformDisplays->insert(std::make_pair(device, display));
528 }
529
530 // Apply new attributes if the display is not initialized yet.
531 if (!display->isInitialized())
532 {
533 display->setAttributes(attribMap);
534 rx::DisplayImpl *impl = CreateDisplayFromDevice(device, display->getState());
535 display->setupDisplayPlatform(impl);
536 }
537
538 return display;
539 }
540
Display(EGLenum platform,EGLNativeDisplayType displayId,Device * eglDevice)541 Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice)
542 : mState(displayId),
543 mImplementation(nullptr),
544 mAttributeMap(),
545 mConfigSet(),
546 mContextSet(),
547 mStreamSet(),
548 mInitialized(false),
549 mDeviceLost(false),
550 mCaps(),
551 mDisplayExtensions(),
552 mDisplayExtensionString(),
553 mVendorString(),
554 mDevice(eglDevice),
555 mSurface(nullptr),
556 mPlatform(platform),
557 mTextureManager(nullptr),
558 mBlobCache(gl::kDefaultMaxProgramCacheMemoryBytes),
559 mMemoryProgramCache(mBlobCache),
560 mGlobalTextureShareGroupUsers(0)
561 {}
562
~Display()563 Display::~Display()
564 {
565 // TODO(jmadill): When is this called?
566 // terminate();
567
568 if (mPlatform == EGL_PLATFORM_ANGLE_ANGLE)
569 {
570 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
571 ANGLEPlatformDisplayMap::iterator iter = displays->find(mState.displayId);
572 if (iter != displays->end())
573 {
574 displays->erase(iter);
575 }
576 }
577 else if (mPlatform == EGL_PLATFORM_DEVICE_EXT)
578 {
579 DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap();
580 DevicePlatformDisplayMap::iterator iter = displays->find(mDevice);
581 if (iter != displays->end())
582 {
583 displays->erase(iter);
584 }
585 }
586 else
587 {
588 UNREACHABLE();
589 }
590
591 SafeDelete(mDevice);
592 SafeDelete(mImplementation);
593 }
594
setLabel(EGLLabelKHR label)595 void Display::setLabel(EGLLabelKHR label)
596 {
597 mState.label = label;
598 }
599
getLabel() const600 EGLLabelKHR Display::getLabel() const
601 {
602 return mState.label;
603 }
604
setupDisplayPlatform(rx::DisplayImpl * impl)605 void Display::setupDisplayPlatform(rx::DisplayImpl *impl)
606 {
607 ASSERT(!mInitialized);
608
609 ASSERT(impl != nullptr);
610 SafeDelete(mImplementation);
611 mImplementation = impl;
612
613 // TODO(jmadill): Store Platform in Display and init here.
614 const angle::PlatformMethods *platformMethods =
615 reinterpret_cast<const angle::PlatformMethods *>(
616 mAttributeMap.get(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX, 0));
617 if (platformMethods != nullptr)
618 {
619 *ANGLEPlatformCurrent() = *platformMethods;
620 }
621 else
622 {
623 ANGLESetDefaultDisplayPlatform(this);
624 }
625
626 const char **featuresForceEnabled =
627 reinterpret_cast<const char **>(mAttributeMap.get(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, 0));
628 const char **featuresForceDisabled =
629 reinterpret_cast<const char **>(mAttributeMap.get(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, 0));
630 mState.featureOverridesEnabled = EGLStringArrayToStringVector(featuresForceEnabled);
631 mState.featureOverridesDisabled = EGLStringArrayToStringVector(featuresForceDisabled);
632 mState.featuresAllDisabled =
633 static_cast<bool>(mAttributeMap.get(EGL_FEATURE_ALL_DISABLED_ANGLE, 0));
634 }
635
updateAttribsFromEnvironment(const AttributeMap & attribMap)636 void Display::updateAttribsFromEnvironment(const AttributeMap &attribMap)
637 {
638 EGLAttrib displayType =
639 attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
640 if (displayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
641 {
642 displayType = GetDisplayTypeFromEnvironment();
643 mAttributeMap.insert(EGL_PLATFORM_ANGLE_TYPE_ANGLE, displayType);
644 }
645 EGLAttrib deviceType = attribMap.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, 0);
646 if (deviceType == 0)
647 {
648 deviceType = GetDeviceTypeFromEnvironment();
649 mAttributeMap.insert(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, deviceType);
650 }
651 }
652
initialize()653 Error Display::initialize()
654 {
655 ASSERT(mImplementation != nullptr);
656 mImplementation->setBlobCache(&mBlobCache);
657
658 // Enable shader caching if debug layers are turned on. This allows us to test that shaders are
659 // properly saved & restored on all platforms. The cache won't allocate space until it's used
660 // and will be ignored entirely if the application / system sets it's own cache functions.
661 if (rx::ShouldUseDebugLayers(mAttributeMap))
662 {
663 mBlobCache.resize(1024 * 1024);
664 }
665
666 gl::InitializeDebugAnnotations(&mAnnotator);
667
668 gl::InitializeDebugMutexIfNeeded();
669
670 SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.DisplayInitializeMS");
671 ANGLE_TRACE_EVENT0("gpu.angle", "egl::Display::initialize");
672
673 if (isInitialized())
674 {
675 return NoError();
676 }
677
678 Error error = mImplementation->initialize(this);
679 if (error.isError())
680 {
681 // Log extended error message here
682 ERR() << "ANGLE Display::initialize error " << error.getID() << ": " << error.getMessage();
683 return error;
684 }
685
686 mCaps = mImplementation->getCaps();
687
688 mConfigSet = mImplementation->generateConfigs();
689 if (mConfigSet.size() == 0)
690 {
691 mImplementation->terminate();
692 return EglNotInitialized();
693 }
694
695 // OpenGL ES1 is implemented in the frontend, explicitly add ES1 support to all configs
696 for (auto &config : mConfigSet)
697 {
698 // TODO(geofflang): Enable the conformant bit once we pass enough tests
699 // config.second.conformant |= EGL_OPENGL_ES_BIT;
700
701 config.second.renderableType |= EGL_OPENGL_ES_BIT;
702 }
703
704 if (!mState.featuresAllDisabled)
705 {
706 initializeFrontendFeatures();
707 }
708
709 mFeatures.clear();
710 mFrontendFeatures.populateFeatureList(&mFeatures);
711 mImplementation->populateFeatureList(&mFeatures);
712
713 initDisplayExtensions();
714 initVendorString();
715
716 // Populate the Display's EGLDeviceEXT if the Display wasn't created using one
717 if (mPlatform != EGL_PLATFORM_DEVICE_EXT)
718 {
719 if (mDisplayExtensions.deviceQuery)
720 {
721 std::unique_ptr<rx::DeviceImpl> impl(mImplementation->createDevice());
722 ASSERT(impl != nullptr);
723 error = impl->initialize();
724 if (error.isError())
725 {
726 ERR() << "Failed to initialize display because device creation failed: "
727 << error.getMessage();
728 mImplementation->terminate();
729 return error;
730 }
731 mDevice = new Device(this, impl.release());
732 }
733 else
734 {
735 mDevice = nullptr;
736 }
737 }
738 else
739 {
740 // For EGL_PLATFORM_DEVICE_EXT, mDevice should always be populated using
741 // an external device
742 ASSERT(mDevice != nullptr);
743 }
744
745 mInitialized = true;
746
747 return NoError();
748 }
749
terminate(const Thread * thread)750 Error Display::terminate(const Thread *thread)
751 {
752 if (!mInitialized)
753 {
754 return NoError();
755 }
756
757 mMemoryProgramCache.clear();
758 mBlobCache.setBlobCacheFuncs(nullptr, nullptr);
759
760 while (!mContextSet.empty())
761 {
762 ANGLE_TRY(destroyContext(thread, *mContextSet.begin()));
763 }
764
765 ANGLE_TRY(makeCurrent(thread, nullptr, nullptr, nullptr));
766
767 // The global texture manager should be deleted with the last context that uses it.
768 ASSERT(mGlobalTextureShareGroupUsers == 0 && mTextureManager == nullptr);
769
770 while (!mImageSet.empty())
771 {
772 destroyImage(*mImageSet.begin());
773 }
774
775 while (!mStreamSet.empty())
776 {
777 destroyStream(*mStreamSet.begin());
778 }
779
780 while (!mSyncSet.empty())
781 {
782 destroySync(*mSyncSet.begin());
783 }
784
785 while (!mState.surfaceSet.empty())
786 {
787 ANGLE_TRY(destroySurface(*mState.surfaceSet.begin()));
788 }
789
790 mConfigSet.clear();
791
792 if (mDevice != nullptr && mDevice->getOwningDisplay() != nullptr)
793 {
794 // Don't delete the device if it was created externally using eglCreateDeviceANGLE
795 // We also shouldn't set it to null in case eglInitialize() is called again later
796 SafeDelete(mDevice);
797 }
798
799 mImplementation->terminate();
800
801 mDeviceLost = false;
802
803 mInitialized = false;
804
805 gl::UninitializeDebugAnnotations();
806
807 // TODO(jmadill): Store Platform in Display and deinit here.
808 ANGLEResetDisplayPlatform(this);
809
810 return NoError();
811 }
812
getConfigs(const egl::AttributeMap & attribs) const813 std::vector<const Config *> Display::getConfigs(const egl::AttributeMap &attribs) const
814 {
815 return mConfigSet.filter(attribs);
816 }
817
chooseConfig(const egl::AttributeMap & attribs) const818 std::vector<const Config *> Display::chooseConfig(const egl::AttributeMap &attribs) const
819 {
820 egl::AttributeMap attribsWithDefaults = AttributeMap();
821
822 // Insert default values for attributes that have either an Exact or Mask selection criteria,
823 // and a default value that matters (e.g. isn't EGL_DONT_CARE):
824 attribsWithDefaults.insert(EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
825 attribsWithDefaults.insert(EGL_LEVEL, 0);
826 attribsWithDefaults.insert(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT);
827 attribsWithDefaults.insert(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
828 attribsWithDefaults.insert(EGL_TRANSPARENT_TYPE, EGL_NONE);
829 if (getExtensions().pixelFormatFloat)
830 {
831 attribsWithDefaults.insert(EGL_COLOR_COMPONENT_TYPE_EXT,
832 EGL_COLOR_COMPONENT_TYPE_FIXED_EXT);
833 }
834
835 // Add the caller-specified values (Note: the poorly-named insert() method will replace any
836 // of the default values from above):
837 for (auto attribIter = attribs.begin(); attribIter != attribs.end(); attribIter++)
838 {
839 attribsWithDefaults.insert(attribIter->first, attribIter->second);
840 }
841
842 return mConfigSet.filter(attribsWithDefaults);
843 }
844
createWindowSurface(const Config * configuration,EGLNativeWindowType window,const AttributeMap & attribs,Surface ** outSurface)845 Error Display::createWindowSurface(const Config *configuration,
846 EGLNativeWindowType window,
847 const AttributeMap &attribs,
848 Surface **outSurface)
849 {
850 if (mImplementation->testDeviceLost())
851 {
852 ANGLE_TRY(restoreLostDevice());
853 }
854
855 SurfacePointer surface(new WindowSurface(mImplementation, configuration, window, attribs),
856 this);
857 ANGLE_TRY(surface->initialize(this));
858
859 ASSERT(outSurface != nullptr);
860 *outSurface = surface.release();
861 mState.surfaceSet.insert(*outSurface);
862
863 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
864 ASSERT(windowSurfaces && windowSurfaces->find(window) == windowSurfaces->end());
865 windowSurfaces->insert(std::make_pair(window, *outSurface));
866
867 mSurface = *outSurface;
868
869 return NoError();
870 }
871
createPbufferSurface(const Config * configuration,const AttributeMap & attribs,Surface ** outSurface)872 Error Display::createPbufferSurface(const Config *configuration,
873 const AttributeMap &attribs,
874 Surface **outSurface)
875 {
876 ASSERT(isInitialized());
877
878 if (mImplementation->testDeviceLost())
879 {
880 ANGLE_TRY(restoreLostDevice());
881 }
882
883 SurfacePointer surface(new PbufferSurface(mImplementation, configuration, attribs), this);
884 ANGLE_TRY(surface->initialize(this));
885
886 ASSERT(outSurface != nullptr);
887 *outSurface = surface.release();
888 mState.surfaceSet.insert(*outSurface);
889
890 return NoError();
891 }
892
createPbufferFromClientBuffer(const Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const AttributeMap & attribs,Surface ** outSurface)893 Error Display::createPbufferFromClientBuffer(const Config *configuration,
894 EGLenum buftype,
895 EGLClientBuffer clientBuffer,
896 const AttributeMap &attribs,
897 Surface **outSurface)
898 {
899 ASSERT(isInitialized());
900
901 if (mImplementation->testDeviceLost())
902 {
903 ANGLE_TRY(restoreLostDevice());
904 }
905
906 SurfacePointer surface(
907 new PbufferSurface(mImplementation, configuration, buftype, clientBuffer, attribs), this);
908 ANGLE_TRY(surface->initialize(this));
909
910 ASSERT(outSurface != nullptr);
911 *outSurface = surface.release();
912 mState.surfaceSet.insert(*outSurface);
913
914 return NoError();
915 }
916
createPixmapSurface(const Config * configuration,NativePixmapType nativePixmap,const AttributeMap & attribs,Surface ** outSurface)917 Error Display::createPixmapSurface(const Config *configuration,
918 NativePixmapType nativePixmap,
919 const AttributeMap &attribs,
920 Surface **outSurface)
921 {
922 ASSERT(isInitialized());
923
924 if (mImplementation->testDeviceLost())
925 {
926 ANGLE_TRY(restoreLostDevice());
927 }
928
929 SurfacePointer surface(new PixmapSurface(mImplementation, configuration, nativePixmap, attribs),
930 this);
931 ANGLE_TRY(surface->initialize(this));
932
933 ASSERT(outSurface != nullptr);
934 *outSurface = surface.release();
935 mState.surfaceSet.insert(*outSurface);
936
937 return NoError();
938 }
939
createImage(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs,Image ** outImage)940 Error Display::createImage(const gl::Context *context,
941 EGLenum target,
942 EGLClientBuffer buffer,
943 const AttributeMap &attribs,
944 Image **outImage)
945 {
946 ASSERT(isInitialized());
947
948 if (mImplementation->testDeviceLost())
949 {
950 ANGLE_TRY(restoreLostDevice());
951 }
952
953 egl::ImageSibling *sibling = nullptr;
954 if (IsTextureTarget(target))
955 {
956 sibling = context->getTexture({egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
957 }
958 else if (IsRenderbufferTarget(target))
959 {
960 sibling = context->getRenderbuffer({egl_gl::EGLClientBufferToGLObjectHandle(buffer)});
961 }
962 else if (IsExternalImageTarget(target))
963 {
964 sibling = new ExternalImageSibling(mImplementation, context, target, buffer, attribs);
965 }
966 else
967 {
968 UNREACHABLE();
969 }
970 ASSERT(sibling != nullptr);
971
972 angle::UniqueObjectPointer<Image, Display> imagePtr(
973 new Image(mImplementation, context, target, sibling, attribs), this);
974 ANGLE_TRY(imagePtr->initialize(this));
975
976 Image *image = imagePtr.release();
977
978 ASSERT(outImage != nullptr);
979 *outImage = image;
980
981 // Add this image to the list of all images and hold a ref to it.
982 image->addRef();
983 mImageSet.insert(image);
984
985 return NoError();
986 }
987
createStream(const AttributeMap & attribs,Stream ** outStream)988 Error Display::createStream(const AttributeMap &attribs, Stream **outStream)
989 {
990 ASSERT(isInitialized());
991
992 Stream *stream = new Stream(this, attribs);
993
994 ASSERT(stream != nullptr);
995 mStreamSet.insert(stream);
996
997 ASSERT(outStream != nullptr);
998 *outStream = stream;
999
1000 return NoError();
1001 }
1002
createContext(const Config * configuration,gl::Context * shareContext,EGLenum clientType,const AttributeMap & attribs,gl::Context ** outContext)1003 Error Display::createContext(const Config *configuration,
1004 gl::Context *shareContext,
1005 EGLenum clientType,
1006 const AttributeMap &attribs,
1007 gl::Context **outContext)
1008 {
1009 ASSERT(isInitialized());
1010
1011 if (mImplementation->testDeviceLost())
1012 {
1013 ANGLE_TRY(restoreLostDevice());
1014 }
1015
1016 // This display texture sharing will allow the first context to create the texture share group.
1017 bool usingDisplayTextureShareGroup =
1018 attribs.get(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE;
1019 gl::TextureManager *shareTextures = nullptr;
1020
1021 if (usingDisplayTextureShareGroup)
1022 {
1023 ASSERT((mTextureManager == nullptr) == (mGlobalTextureShareGroupUsers == 0));
1024 if (mTextureManager == nullptr)
1025 {
1026 mTextureManager = new gl::TextureManager();
1027 }
1028
1029 mGlobalTextureShareGroupUsers++;
1030 shareTextures = mTextureManager;
1031 }
1032
1033 gl::MemoryProgramCache *cachePointer = &mMemoryProgramCache;
1034
1035 // Check context creation attributes to see if we are using EGL_ANGLE_program_cache_control.
1036 // If not, keep caching enabled for EGL_ANDROID_blob_cache, which can have its callbacks set
1037 // at any time.
1038 bool usesProgramCacheControl =
1039 mAttributeMap.contains(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE);
1040 if (usesProgramCacheControl)
1041 {
1042 bool programCacheControlEnabled =
1043 (mAttributeMap.get(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE, GL_FALSE) ==
1044 GL_TRUE);
1045 // A program cache size of zero indicates it should be disabled.
1046 if (!programCacheControlEnabled || mMemoryProgramCache.maxSize() == 0)
1047 {
1048 cachePointer = nullptr;
1049 }
1050 }
1051
1052 gl::Context *context =
1053 new gl::Context(this, configuration, shareContext, shareTextures, cachePointer, clientType,
1054 attribs, mDisplayExtensions, GetClientExtensions());
1055 if (shareContext != nullptr)
1056 {
1057 shareContext->setShared();
1058 }
1059
1060 ASSERT(context != nullptr);
1061 mContextSet.insert(context);
1062
1063 ASSERT(outContext != nullptr);
1064 *outContext = context;
1065 return NoError();
1066 }
1067
createSync(const gl::Context * currentContext,EGLenum type,const AttributeMap & attribs,Sync ** outSync)1068 Error Display::createSync(const gl::Context *currentContext,
1069 EGLenum type,
1070 const AttributeMap &attribs,
1071 Sync **outSync)
1072 {
1073 ASSERT(isInitialized());
1074
1075 if (mImplementation->testDeviceLost())
1076 {
1077 ANGLE_TRY(restoreLostDevice());
1078 }
1079
1080 angle::UniqueObjectPointer<egl::Sync, Display> syncPtr(new Sync(mImplementation, type, attribs),
1081 this);
1082
1083 ANGLE_TRY(syncPtr->initialize(this, currentContext));
1084
1085 Sync *sync = syncPtr.release();
1086
1087 sync->addRef();
1088 mSyncSet.insert(sync);
1089
1090 *outSync = sync;
1091 return NoError();
1092 }
1093
makeCurrent(const Thread * thread,egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)1094 Error Display::makeCurrent(const Thread *thread,
1095 egl::Surface *drawSurface,
1096 egl::Surface *readSurface,
1097 gl::Context *context)
1098 {
1099 if (!mInitialized)
1100 {
1101 return NoError();
1102 }
1103
1104 gl::Context *previousContext = thread->getContext();
1105 if (previousContext)
1106 {
1107 ANGLE_TRY(previousContext->unMakeCurrent(this));
1108 }
1109
1110 ANGLE_TRY(mImplementation->makeCurrent(drawSurface, readSurface, context));
1111
1112 if (context != nullptr)
1113 {
1114 ANGLE_TRY(context->makeCurrent(this, drawSurface, readSurface));
1115 }
1116
1117 // Tick all the scratch buffers to make sure they get cleaned up eventually if they stop being
1118 // used.
1119 {
1120 std::lock_guard<std::mutex> lock(mScratchBufferMutex);
1121
1122 for (angle::ScratchBuffer &scatchBuffer : mScratchBuffers)
1123 {
1124 scatchBuffer.tick();
1125 }
1126 for (angle::ScratchBuffer &zeroFilledBuffer : mZeroFilledBuffers)
1127 {
1128 zeroFilledBuffer.tick();
1129 }
1130 }
1131
1132 return NoError();
1133 }
1134
restoreLostDevice()1135 Error Display::restoreLostDevice()
1136 {
1137 for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
1138 {
1139 if ((*ctx)->isResetNotificationEnabled())
1140 {
1141 // If reset notifications have been requested, application must delete all contexts
1142 // first
1143 return EglContextLost();
1144 }
1145 }
1146
1147 return mImplementation->restoreLostDevice(this);
1148 }
1149
destroySurface(Surface * surface)1150 Error Display::destroySurface(Surface *surface)
1151 {
1152 if (surface->getType() == EGL_WINDOW_BIT)
1153 {
1154 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
1155 ASSERT(windowSurfaces);
1156
1157 bool surfaceRemoved = false;
1158 for (WindowSurfaceMap::iterator iter = windowSurfaces->begin();
1159 iter != windowSurfaces->end(); iter++)
1160 {
1161 if (iter->second == surface)
1162 {
1163 windowSurfaces->erase(iter);
1164 surfaceRemoved = true;
1165 break;
1166 }
1167 }
1168
1169 ASSERT(surfaceRemoved);
1170 }
1171
1172 mState.surfaceSet.erase(surface);
1173 ANGLE_TRY(surface->onDestroy(this));
1174 return NoError();
1175 }
1176
destroyImage(egl::Image * image)1177 void Display::destroyImage(egl::Image *image)
1178 {
1179 auto iter = mImageSet.find(image);
1180 ASSERT(iter != mImageSet.end());
1181 (*iter)->release(this);
1182 mImageSet.erase(iter);
1183 }
1184
destroyStream(egl::Stream * stream)1185 void Display::destroyStream(egl::Stream *stream)
1186 {
1187 mStreamSet.erase(stream);
1188 SafeDelete(stream);
1189 }
1190
destroyContext(const Thread * thread,gl::Context * context)1191 Error Display::destroyContext(const Thread *thread, gl::Context *context)
1192 {
1193 gl::Context *currentContext = thread->getContext();
1194 Surface *currentDrawSurface = thread->getCurrentDrawSurface();
1195 Surface *currentReadSurface = thread->getCurrentReadSurface();
1196 bool changeContextForDeletion = context != currentContext;
1197
1198 // Make the context being deleted current during it's deletion. This allows it to delete
1199 // any resources it's holding.
1200 if (changeContextForDeletion)
1201 {
1202 ANGLE_TRY(makeCurrent(thread, nullptr, nullptr, context));
1203 }
1204
1205 if (context->usingDisplayTextureShareGroup())
1206 {
1207 ASSERT(mGlobalTextureShareGroupUsers >= 1 && mTextureManager != nullptr);
1208 if (mGlobalTextureShareGroupUsers == 1)
1209 {
1210 // If this is the last context using the global share group, destroy the global
1211 // texture manager so that the textures can be destroyed while a context still
1212 // exists
1213 mTextureManager->release(context);
1214 mTextureManager = nullptr;
1215 }
1216 mGlobalTextureShareGroupUsers--;
1217 }
1218
1219 ANGLE_TRY(context->onDestroy(this));
1220 mContextSet.erase(context);
1221 SafeDelete(context);
1222
1223 // Set the previous context back to current
1224 if (changeContextForDeletion)
1225 {
1226 ANGLE_TRY(makeCurrent(thread, currentDrawSurface, currentReadSurface, currentContext));
1227 }
1228
1229 return NoError();
1230 }
1231
destroySync(egl::Sync * sync)1232 void Display::destroySync(egl::Sync *sync)
1233 {
1234 auto iter = mSyncSet.find(sync);
1235 ASSERT(iter != mSyncSet.end());
1236 (*iter)->release(this);
1237 mSyncSet.erase(iter);
1238 }
1239
isDeviceLost() const1240 bool Display::isDeviceLost() const
1241 {
1242 ASSERT(isInitialized());
1243 return mDeviceLost;
1244 }
1245
testDeviceLost()1246 bool Display::testDeviceLost()
1247 {
1248 ASSERT(isInitialized());
1249
1250 if (!mDeviceLost && mImplementation->testDeviceLost())
1251 {
1252 notifyDeviceLost();
1253 }
1254
1255 return mDeviceLost;
1256 }
1257
notifyDeviceLost()1258 void Display::notifyDeviceLost()
1259 {
1260 if (mDeviceLost)
1261 {
1262 return;
1263 }
1264
1265 for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end();
1266 context++)
1267 {
1268 (*context)->markContextLost(gl::GraphicsResetStatus::UnknownContextReset);
1269 }
1270
1271 mDeviceLost = true;
1272 }
1273
setBlobCacheFuncs(EGLSetBlobFuncANDROID set,EGLGetBlobFuncANDROID get)1274 void Display::setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get)
1275 {
1276 mBlobCache.setBlobCacheFuncs(set, get);
1277 mImplementation->setBlobCacheFuncs(set, get);
1278 }
1279
1280 // static
GetNativeClientBuffer(const AHardwareBuffer * buffer)1281 EGLClientBuffer Display::GetNativeClientBuffer(const AHardwareBuffer *buffer)
1282 {
1283 return angle::android::AHardwareBufferToClientBuffer(buffer);
1284 }
1285
waitClient(const gl::Context * context)1286 Error Display::waitClient(const gl::Context *context)
1287 {
1288 return mImplementation->waitClient(context);
1289 }
1290
waitNative(const gl::Context * context,EGLint engine)1291 Error Display::waitNative(const gl::Context *context, EGLint engine)
1292 {
1293 return mImplementation->waitNative(context, engine);
1294 }
1295
getCaps() const1296 const Caps &Display::getCaps() const
1297 {
1298 return mCaps;
1299 }
1300
isInitialized() const1301 bool Display::isInitialized() const
1302 {
1303 return mInitialized;
1304 }
1305
isValidConfig(const Config * config) const1306 bool Display::isValidConfig(const Config *config) const
1307 {
1308 return mConfigSet.contains(config);
1309 }
1310
isValidContext(const gl::Context * context) const1311 bool Display::isValidContext(const gl::Context *context) const
1312 {
1313 return mContextSet.find(const_cast<gl::Context *>(context)) != mContextSet.end();
1314 }
1315
isValidSurface(const Surface * surface) const1316 bool Display::isValidSurface(const Surface *surface) const
1317 {
1318 return mState.surfaceSet.find(const_cast<Surface *>(surface)) != mState.surfaceSet.end();
1319 }
1320
isValidImage(const Image * image) const1321 bool Display::isValidImage(const Image *image) const
1322 {
1323 return mImageSet.find(const_cast<Image *>(image)) != mImageSet.end();
1324 }
1325
isValidStream(const Stream * stream) const1326 bool Display::isValidStream(const Stream *stream) const
1327 {
1328 return mStreamSet.find(const_cast<Stream *>(stream)) != mStreamSet.end();
1329 }
1330
isValidSync(const Sync * sync) const1331 bool Display::isValidSync(const Sync *sync) const
1332 {
1333 return mSyncSet.find(const_cast<Sync *>(sync)) != mSyncSet.end();
1334 }
1335
hasExistingWindowSurface(EGLNativeWindowType window)1336 bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
1337 {
1338 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
1339 ASSERT(windowSurfaces);
1340
1341 return windowSurfaces->find(window) != windowSurfaces->end();
1342 }
1343
GenerateClientExtensions()1344 static ClientExtensions GenerateClientExtensions()
1345 {
1346 ClientExtensions extensions;
1347
1348 extensions.clientExtensions = true;
1349 extensions.platformBase = true;
1350 extensions.platformANGLE = true;
1351
1352 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
1353 extensions.platformANGLED3D = true;
1354 extensions.platformDevice = true;
1355 #endif
1356
1357 #if defined(ANGLE_ENABLE_D3D11)
1358 # if defined(ANGLE_ENABLE_WINDOWS_UWP)
1359 extensions.platformANGLED3D11ON12 = true;
1360 # else
1361 extensions.platformANGLED3D11ON12 = IsWindows10OrGreater();
1362 # endif
1363 #endif
1364
1365 #if defined(ANGLE_ENABLE_OPENGL)
1366 extensions.platformANGLEOpenGL = true;
1367
1368 // Selecting context virtualization is currently only supported in the OpenGL backend.
1369 extensions.platformANGLEContextVirtualization = true;
1370 #endif
1371
1372 #if defined(ANGLE_ENABLE_NULL)
1373 extensions.platformANGLENULL = true;
1374 #endif
1375
1376 #if defined(ANGLE_ENABLE_D3D11)
1377 extensions.deviceCreation = true;
1378 extensions.deviceCreationD3D11 = true;
1379 extensions.experimentalPresentPath = true;
1380 #endif
1381
1382 #if defined(ANGLE_ENABLE_VULKAN)
1383 extensions.platformANGLEVulkan = true;
1384 #endif
1385
1386 #if defined(ANGLE_ENABLE_SWIFTSHADER)
1387 extensions.platformANGLEDeviceTypeSwiftShader = true;
1388 #endif
1389
1390 #if defined(ANGLE_ENABLE_METAL)
1391 extensions.platformANGLEMetal = true;
1392 #endif
1393
1394 #if defined(ANGLE_USE_X11)
1395 extensions.x11Visual = true;
1396 #endif
1397
1398 #if defined(ANGLE_PLATFORM_LINUX) && !defined(ANGLE_USE_OZONE)
1399 extensions.platformANGLEDeviceTypeEGLANGLE = true;
1400 #endif
1401
1402 extensions.clientGetAllProcAddresses = true;
1403 extensions.debug = true;
1404 extensions.explicitContext = true;
1405 extensions.featureControlANGLE = true;
1406
1407 return extensions;
1408 }
1409
1410 template <typename T>
GenerateExtensionsString(const T & extensions)1411 static std::string GenerateExtensionsString(const T &extensions)
1412 {
1413 std::vector<std::string> extensionsVector = extensions.getStrings();
1414
1415 std::ostringstream stream;
1416 std::copy(extensionsVector.begin(), extensionsVector.end(),
1417 std::ostream_iterator<std::string>(stream, " "));
1418 return stream.str();
1419 }
1420
1421 // static
GetClientExtensions()1422 const ClientExtensions &Display::GetClientExtensions()
1423 {
1424 static const ClientExtensions clientExtensions = GenerateClientExtensions();
1425 return clientExtensions;
1426 }
1427
1428 // static
GetClientExtensionString()1429 const std::string &Display::GetClientExtensionString()
1430 {
1431 static const angle::base::NoDestructor<std::string> clientExtensionsString(
1432 GenerateExtensionsString(GetClientExtensions()));
1433 return *clientExtensionsString;
1434 }
1435
initDisplayExtensions()1436 void Display::initDisplayExtensions()
1437 {
1438 mDisplayExtensions = mImplementation->getExtensions();
1439
1440 // Some extensions are always available because they are implemented in the EGL layer.
1441 mDisplayExtensions.createContext = true;
1442 mDisplayExtensions.createContextNoError = true;
1443 mDisplayExtensions.createContextWebGLCompatibility = true;
1444 mDisplayExtensions.createContextBindGeneratesResource = true;
1445 mDisplayExtensions.createContextClientArrays = true;
1446 mDisplayExtensions.pixelFormatFloat = true;
1447
1448 // Force EGL_KHR_get_all_proc_addresses on.
1449 mDisplayExtensions.getAllProcAddresses = true;
1450
1451 // Enable program cache control since it is not back-end dependent.
1452 mDisplayExtensions.programCacheControl = true;
1453
1454 // Request extension is implemented in the ANGLE frontend
1455 mDisplayExtensions.createContextExtensionsEnabled = true;
1456
1457 // Blob cache extension is provided by the ANGLE frontend
1458 mDisplayExtensions.blobCache = true;
1459
1460 // The EGL_ANDROID_recordable extension is provided by the ANGLE frontend, and will always
1461 // say that ANativeWindow is not recordable.
1462 mDisplayExtensions.recordable = true;
1463
1464 // All backends support specific context versions
1465 mDisplayExtensions.createContextBackwardsCompatible = true;
1466
1467 mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions);
1468 }
1469
isValidNativeWindow(EGLNativeWindowType window) const1470 bool Display::isValidNativeWindow(EGLNativeWindowType window) const
1471 {
1472 return mImplementation->isValidNativeWindow(window);
1473 }
1474
validateClientBuffer(const Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const AttributeMap & attribs) const1475 Error Display::validateClientBuffer(const Config *configuration,
1476 EGLenum buftype,
1477 EGLClientBuffer clientBuffer,
1478 const AttributeMap &attribs) const
1479 {
1480 return mImplementation->validateClientBuffer(configuration, buftype, clientBuffer, attribs);
1481 }
1482
validateImageClientBuffer(const gl::Context * context,EGLenum target,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const1483 Error Display::validateImageClientBuffer(const gl::Context *context,
1484 EGLenum target,
1485 EGLClientBuffer clientBuffer,
1486 const egl::AttributeMap &attribs) const
1487 {
1488 return mImplementation->validateImageClientBuffer(context, target, clientBuffer, attribs);
1489 }
1490
isValidDisplay(const egl::Display * display)1491 bool Display::isValidDisplay(const egl::Display *display)
1492 {
1493 const ANGLEPlatformDisplayMap *anglePlatformDisplayMap = GetANGLEPlatformDisplayMap();
1494 for (const auto &displayPair : *anglePlatformDisplayMap)
1495 {
1496 if (displayPair.second == display)
1497 {
1498 return true;
1499 }
1500 }
1501
1502 const DevicePlatformDisplayMap *devicePlatformDisplayMap = GetDevicePlatformDisplayMap();
1503 for (const auto &displayPair : *devicePlatformDisplayMap)
1504 {
1505 if (displayPair.second == display)
1506 {
1507 return true;
1508 }
1509 }
1510
1511 return false;
1512 }
1513
isValidNativeDisplay(EGLNativeDisplayType display)1514 bool Display::isValidNativeDisplay(EGLNativeDisplayType display)
1515 {
1516 // TODO(jmadill): handle this properly
1517 if (display == EGL_DEFAULT_DISPLAY)
1518 {
1519 return true;
1520 }
1521
1522 #if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_ENABLE_WINDOWS_UWP)
1523 if (display == EGL_SOFTWARE_DISPLAY_ANGLE || display == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
1524 display == EGL_D3D11_ONLY_DISPLAY_ANGLE)
1525 {
1526 return true;
1527 }
1528 return (WindowFromDC(display) != nullptr);
1529 #else
1530 return true;
1531 #endif
1532 }
1533
initVendorString()1534 void Display::initVendorString()
1535 {
1536 mVendorString = mImplementation->getVendorString();
1537 }
1538
initializeFrontendFeatures()1539 void Display::initializeFrontendFeatures()
1540 {
1541 // Enable on all Impls
1542 ANGLE_FEATURE_CONDITION((&mFrontendFeatures), loseContextOnOutOfMemory, true);
1543 ANGLE_FEATURE_CONDITION((&mFrontendFeatures), scalarizeVecAndMatConstructorArgs, true);
1544
1545 mImplementation->initializeFrontendFeatures(&mFrontendFeatures);
1546
1547 rx::ApplyFeatureOverrides(&mFrontendFeatures, mState);
1548 }
1549
getExtensions() const1550 const DisplayExtensions &Display::getExtensions() const
1551 {
1552 return mDisplayExtensions;
1553 }
1554
getExtensionString() const1555 const std::string &Display::getExtensionString() const
1556 {
1557 return mDisplayExtensionString;
1558 }
1559
getVendorString() const1560 const std::string &Display::getVendorString() const
1561 {
1562 return mVendorString;
1563 }
1564
getDevice() const1565 Device *Display::getDevice() const
1566 {
1567 return mDevice;
1568 }
1569
getWGLSurface() const1570 Surface *Display::getWGLSurface() const
1571 {
1572 return mSurface;
1573 }
1574
getMaxSupportedESVersion() const1575 gl::Version Display::getMaxSupportedESVersion() const
1576 {
1577 return mImplementation->getMaxSupportedESVersion();
1578 }
1579
programCacheGetAttrib(EGLenum attrib) const1580 EGLint Display::programCacheGetAttrib(EGLenum attrib) const
1581 {
1582 switch (attrib)
1583 {
1584 case EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE:
1585 return static_cast<EGLint>(BlobCache::kKeyLength);
1586
1587 case EGL_PROGRAM_CACHE_SIZE_ANGLE:
1588 return static_cast<EGLint>(mMemoryProgramCache.entryCount());
1589
1590 default:
1591 UNREACHABLE();
1592 return 0;
1593 }
1594 }
1595
programCacheQuery(EGLint index,void * key,EGLint * keysize,void * binary,EGLint * binarysize)1596 Error Display::programCacheQuery(EGLint index,
1597 void *key,
1598 EGLint *keysize,
1599 void *binary,
1600 EGLint *binarysize)
1601 {
1602 ASSERT(index >= 0 && index < static_cast<EGLint>(mMemoryProgramCache.entryCount()));
1603
1604 const BlobCache::Key *programHash = nullptr;
1605 BlobCache::Value programBinary;
1606 // TODO(jmadill): Make this thread-safe.
1607 bool result =
1608 mMemoryProgramCache.getAt(static_cast<size_t>(index), &programHash, &programBinary);
1609 if (!result)
1610 {
1611 return EglBadAccess() << "Program binary not accessible.";
1612 }
1613
1614 ASSERT(keysize && binarysize);
1615
1616 if (key)
1617 {
1618 ASSERT(*keysize == static_cast<EGLint>(BlobCache::kKeyLength));
1619 memcpy(key, programHash->data(), BlobCache::kKeyLength);
1620 }
1621
1622 if (binary)
1623 {
1624 // Note: we check the size here instead of in the validation code, since we need to
1625 // access the cache as atomically as possible. It's possible that the cache contents
1626 // could change between the validation size check and the retrieval.
1627 if (programBinary.size() > static_cast<size_t>(*binarysize))
1628 {
1629 return EglBadAccess() << "Program binary too large or changed during access.";
1630 }
1631
1632 memcpy(binary, programBinary.data(), programBinary.size());
1633 }
1634
1635 *binarysize = static_cast<EGLint>(programBinary.size());
1636 *keysize = static_cast<EGLint>(BlobCache::kKeyLength);
1637
1638 return NoError();
1639 }
1640
programCachePopulate(const void * key,EGLint keysize,const void * binary,EGLint binarysize)1641 Error Display::programCachePopulate(const void *key,
1642 EGLint keysize,
1643 const void *binary,
1644 EGLint binarysize)
1645 {
1646 ASSERT(keysize == static_cast<EGLint>(BlobCache::kKeyLength));
1647
1648 BlobCache::Key programHash;
1649 memcpy(programHash.data(), key, BlobCache::kKeyLength);
1650
1651 if (!mMemoryProgramCache.putBinary(programHash, reinterpret_cast<const uint8_t *>(binary),
1652 static_cast<size_t>(binarysize)))
1653 {
1654 return EglBadAccess() << "Failed to copy program binary into the cache.";
1655 }
1656
1657 return NoError();
1658 }
1659
programCacheResize(EGLint limit,EGLenum mode)1660 EGLint Display::programCacheResize(EGLint limit, EGLenum mode)
1661 {
1662 switch (mode)
1663 {
1664 case EGL_PROGRAM_CACHE_RESIZE_ANGLE:
1665 {
1666 size_t initialSize = mMemoryProgramCache.size();
1667 mMemoryProgramCache.resize(static_cast<size_t>(limit));
1668 return static_cast<EGLint>(initialSize);
1669 }
1670
1671 case EGL_PROGRAM_CACHE_TRIM_ANGLE:
1672 return static_cast<EGLint>(mMemoryProgramCache.trim(static_cast<size_t>(limit)));
1673
1674 default:
1675 UNREACHABLE();
1676 return 0;
1677 }
1678 }
1679
queryStringi(const EGLint name,const EGLint index)1680 const char *Display::queryStringi(const EGLint name, const EGLint index)
1681 {
1682 const char *result = nullptr;
1683 switch (name)
1684 {
1685 case EGL_FEATURE_NAME_ANGLE:
1686 result = mFeatures[index]->name;
1687 break;
1688 case EGL_FEATURE_CATEGORY_ANGLE:
1689 result = angle::FeatureCategoryToString(mFeatures[index]->category);
1690 break;
1691 case EGL_FEATURE_DESCRIPTION_ANGLE:
1692 result = mFeatures[index]->description;
1693 break;
1694 case EGL_FEATURE_BUG_ANGLE:
1695 result = mFeatures[index]->bug;
1696 break;
1697 case EGL_FEATURE_STATUS_ANGLE:
1698 result = angle::FeatureStatusToString(mFeatures[index]->enabled);
1699 break;
1700 case EGL_FEATURE_CONDITION_ANGLE:
1701 result = mFeatures[index]->condition;
1702 break;
1703 default:
1704 UNREACHABLE();
1705 return nullptr;
1706 }
1707 return result;
1708 }
1709
queryAttrib(const EGLint attribute)1710 EGLAttrib Display::queryAttrib(const EGLint attribute)
1711 {
1712 EGLAttrib value = 0;
1713 switch (attribute)
1714 {
1715 case EGL_DEVICE_EXT:
1716 value = reinterpret_cast<EGLAttrib>(mDevice);
1717 break;
1718
1719 case EGL_FEATURE_COUNT_ANGLE:
1720 value = mFeatures.size();
1721 break;
1722
1723 default:
1724 UNREACHABLE();
1725 }
1726 return value;
1727 }
1728
requestScratchBuffer()1729 angle::ScratchBuffer Display::requestScratchBuffer()
1730 {
1731 return requestScratchBufferImpl(&mScratchBuffers);
1732 }
1733
returnScratchBuffer(angle::ScratchBuffer scratchBuffer)1734 void Display::returnScratchBuffer(angle::ScratchBuffer scratchBuffer)
1735 {
1736 returnScratchBufferImpl(std::move(scratchBuffer), &mScratchBuffers);
1737 }
1738
requestZeroFilledBuffer()1739 angle::ScratchBuffer Display::requestZeroFilledBuffer()
1740 {
1741 return requestScratchBufferImpl(&mZeroFilledBuffers);
1742 }
1743
returnZeroFilledBuffer(angle::ScratchBuffer zeroFilledBuffer)1744 void Display::returnZeroFilledBuffer(angle::ScratchBuffer zeroFilledBuffer)
1745 {
1746 returnScratchBufferImpl(std::move(zeroFilledBuffer), &mZeroFilledBuffers);
1747 }
1748
requestScratchBufferImpl(std::vector<angle::ScratchBuffer> * bufferVector)1749 angle::ScratchBuffer Display::requestScratchBufferImpl(
1750 std::vector<angle::ScratchBuffer> *bufferVector)
1751 {
1752 std::lock_guard<std::mutex> lock(mScratchBufferMutex);
1753 if (!bufferVector->empty())
1754 {
1755 angle::ScratchBuffer buffer = std::move(bufferVector->back());
1756 bufferVector->pop_back();
1757 return buffer;
1758 }
1759
1760 return angle::ScratchBuffer(kScratchBufferLifetime);
1761 }
1762
returnScratchBufferImpl(angle::ScratchBuffer scratchBuffer,std::vector<angle::ScratchBuffer> * bufferVector)1763 void Display::returnScratchBufferImpl(angle::ScratchBuffer scratchBuffer,
1764 std::vector<angle::ScratchBuffer> *bufferVector)
1765 {
1766 std::lock_guard<std::mutex> lock(mScratchBufferMutex);
1767 bufferVector->push_back(std::move(scratchBuffer));
1768 }
1769
1770 } // namespace egl
1771