1 //
2 // Copyright (c) 2002-2014 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 <platform/Platform.h>
20 #include <EGL/eglext.h>
21
22 #include "common/debug.h"
23 #include "common/mathutil.h"
24 #include "common/platform.h"
25 #include "common/utilities.h"
26 #include "libANGLE/Context.h"
27 #include "libANGLE/Device.h"
28 #include "libANGLE/histogram_macros.h"
29 #include "libANGLE/Image.h"
30 #include "libANGLE/Surface.h"
31 #include "libANGLE/Stream.h"
32 #include "libANGLE/ResourceManager.h"
33 #include "libANGLE/renderer/DisplayImpl.h"
34 #include "libANGLE/renderer/ImageImpl.h"
35 #include "third_party/trace_event/trace_event.h"
36
37 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
38 # include "libANGLE/renderer/d3d/DisplayD3D.h"
39 #endif
40
41 #if defined(ANGLE_ENABLE_OPENGL)
42 # if defined(ANGLE_PLATFORM_WINDOWS)
43 # include "libANGLE/renderer/gl/wgl/DisplayWGL.h"
44 # elif defined(ANGLE_USE_X11)
45 # include "libANGLE/renderer/gl/glx/DisplayGLX.h"
46 # elif defined(ANGLE_PLATFORM_APPLE)
47 # include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
48 # elif defined(ANGLE_USE_OZONE)
49 # include "libANGLE/renderer/gl/egl/ozone/DisplayOzone.h"
50 # elif defined(ANGLE_PLATFORM_ANDROID)
51 # include "libANGLE/renderer/gl/egl/android/DisplayAndroid.h"
52 # else
53 # error Unsupported OpenGL platform.
54 # endif
55 #endif
56
57 #if defined(ANGLE_ENABLE_NULL)
58 #include "libANGLE/renderer/null/DisplayNULL.h"
59 #endif // defined(ANGLE_ENABLE_NULL)
60
61 #if defined(ANGLE_ENABLE_VULKAN)
62 #if defined(ANGLE_PLATFORM_WINDOWS)
63 #include "libANGLE/renderer/vulkan/win32/DisplayVkWin32.h"
64 #elif defined(ANGLE_PLATFORM_LINUX)
65 #include "libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h"
66 #else
67 #error Unsupported Vulkan platform.
68 #endif
69 #endif // defined(ANGLE_ENABLE_VULKAN)
70
71 namespace egl
72 {
73
74 namespace
75 {
76
77 typedef std::map<EGLNativeWindowType, Surface*> WindowSurfaceMap;
78 // Get a map of all EGL window surfaces to validate that no window has more than one EGL surface
79 // associated with it.
GetWindowSurfaces()80 static WindowSurfaceMap *GetWindowSurfaces()
81 {
82 static WindowSurfaceMap windowSurfaces;
83 return &windowSurfaces;
84 }
85
86 typedef std::map<EGLNativeDisplayType, Display *> ANGLEPlatformDisplayMap;
GetANGLEPlatformDisplayMap()87 static ANGLEPlatformDisplayMap *GetANGLEPlatformDisplayMap()
88 {
89 static ANGLEPlatformDisplayMap displays;
90 return &displays;
91 }
92
93 typedef std::map<Device *, Display *> DevicePlatformDisplayMap;
GetDevicePlatformDisplayMap()94 static DevicePlatformDisplayMap *GetDevicePlatformDisplayMap()
95 {
96 static DevicePlatformDisplayMap displays;
97 return &displays;
98 }
99
CreateDisplayFromDevice(Device * eglDevice,const DisplayState & state)100 rx::DisplayImpl *CreateDisplayFromDevice(Device *eglDevice, const DisplayState &state)
101 {
102 rx::DisplayImpl *impl = nullptr;
103
104 switch (eglDevice->getType())
105 {
106 #if defined(ANGLE_ENABLE_D3D11)
107 case EGL_D3D11_DEVICE_ANGLE:
108 impl = new rx::DisplayD3D(state);
109 break;
110 #endif
111 #if defined(ANGLE_ENABLE_D3D9)
112 case EGL_D3D9_DEVICE_ANGLE:
113 // Currently the only way to get EGLDeviceEXT representing a D3D9 device
114 // is to retrieve one from an already-existing EGLDisplay.
115 // When eglGetPlatformDisplayEXT is called with a D3D9 EGLDeviceEXT,
116 // the already-existing display should be returned.
117 // Therefore this codepath to create a new display from the device
118 // should never be hit.
119 UNREACHABLE();
120 break;
121 #endif
122 default:
123 UNREACHABLE();
124 break;
125 }
126
127 ASSERT(impl != nullptr);
128 return impl;
129 }
130
CreateDisplayFromAttribs(const AttributeMap & attribMap,const DisplayState & state)131 rx::DisplayImpl *CreateDisplayFromAttribs(const AttributeMap &attribMap, const DisplayState &state)
132 {
133 rx::DisplayImpl *impl = nullptr;
134 EGLAttrib displayType =
135 attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
136 switch (displayType)
137 {
138 case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
139 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
140 // Default to D3D displays
141 impl = new rx::DisplayD3D(state);
142 #elif defined(ANGLE_USE_X11)
143 impl = new rx::DisplayGLX(state);
144 #elif defined(ANGLE_PLATFORM_APPLE)
145 impl = new rx::DisplayCGL(state);
146 #elif defined(ANGLE_USE_OZONE)
147 impl = new rx::DisplayOzone(state);
148 #elif defined(ANGLE_PLATFORM_ANDROID)
149 impl = new rx::DisplayAndroid(state);
150 #else
151 // No display available
152 UNREACHABLE();
153 #endif
154 break;
155
156 case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
157 case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
158 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
159 impl = new rx::DisplayD3D(state);
160 #else
161 // A D3D display was requested on a platform that doesn't support it
162 UNREACHABLE();
163 #endif
164 break;
165
166 case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
167 #if defined(ANGLE_ENABLE_OPENGL)
168 #if defined(ANGLE_PLATFORM_WINDOWS)
169 impl = new rx::DisplayWGL(state);
170 #elif defined(ANGLE_USE_X11)
171 impl = new rx::DisplayGLX(state);
172 #elif defined(ANGLE_PLATFORM_APPLE)
173 impl = new rx::DisplayCGL(state);
174 #elif defined(ANGLE_USE_OZONE)
175 // This might work but has never been tried, so disallow for now.
176 impl = nullptr;
177 #elif defined(ANGLE_PLATFORM_ANDROID)
178 // No GL support on this platform, fail display creation.
179 impl = nullptr;
180 #else
181 #error Unsupported OpenGL platform.
182 #endif
183 #else
184 // No display available
185 UNREACHABLE();
186 #endif // defined(ANGLE_ENABLE_OPENGL)
187 break;
188
189 case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
190 #if defined(ANGLE_ENABLE_OPENGL)
191 #if defined(ANGLE_PLATFORM_WINDOWS)
192 impl = new rx::DisplayWGL(state);
193 #elif defined(ANGLE_USE_X11)
194 impl = new rx::DisplayGLX(state);
195 #elif defined(ANGLE_USE_OZONE)
196 impl = new rx::DisplayOzone(state);
197 #elif defined(ANGLE_PLATFORM_ANDROID)
198 impl = new rx::DisplayAndroid(state);
199 #else
200 // No GLES support on this platform, fail display creation.
201 impl = nullptr;
202 #endif
203 #endif // defined(ANGLE_ENABLE_OPENGL)
204 break;
205
206 case EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE:
207 #if defined(ANGLE_ENABLE_VULKAN)
208 #if defined(ANGLE_PLATFORM_WINDOWS)
209 impl = new rx::DisplayVkWin32(state);
210 #elif defined(ANGLE_PLATFORM_LINUX)
211 impl = new rx::DisplayVkXcb(state);
212 #else
213 #error Unsupported Vulkan platform.
214 #endif
215 #else
216 // No display available
217 UNREACHABLE();
218 #endif // defined(ANGLE_ENABLE_VULKAN)
219 break;
220
221 case EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE:
222 #if defined(ANGLE_ENABLE_NULL)
223 impl = new rx::DisplayNULL(state);
224 #else
225 // No display available
226 UNREACHABLE();
227 #endif // defined(ANGLE_ENABLE_NULL)
228 break;
229
230 default:
231 UNREACHABLE();
232 break;
233 }
234
235 return impl;
236 }
237
Display_logError(angle::PlatformMethods * platform,const char * errorMessage)238 void Display_logError(angle::PlatformMethods *platform, const char *errorMessage)
239 {
240 gl::Trace(gl::LOG_ERR, errorMessage);
241 }
242
Display_logWarning(angle::PlatformMethods * platform,const char * warningMessage)243 void Display_logWarning(angle::PlatformMethods *platform, const char *warningMessage)
244 {
245 gl::Trace(gl::LOG_WARN, warningMessage);
246 }
247
Display_logInfo(angle::PlatformMethods * platform,const char * infoMessage)248 void Display_logInfo(angle::PlatformMethods *platform, const char *infoMessage)
249 {
250 // Uncomment to get info spam
251 // gl::Trace(gl::LOG_WARN, infoMessage);
252 }
253
ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display)254 void ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display)
255 {
256 angle::PlatformMethods *platformMethods = ANGLEPlatformCurrent();
257 if (platformMethods->logError != angle::DefaultLogError)
258 {
259 // Don't reset pre-set Platform to Default
260 return;
261 }
262
263 ANGLEResetDisplayPlatform(display);
264 platformMethods->logError = Display_logError;
265 platformMethods->logWarning = Display_logWarning;
266 platformMethods->logInfo = Display_logInfo;
267 }
268
269 } // anonymous namespace
270
DisplayState()271 DisplayState::DisplayState()
272 {
273 }
274
~DisplayState()275 DisplayState::~DisplayState()
276 {
277 }
278
279 // static
GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay,const AttributeMap & attribMap)280 Display *Display::GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay,
281 const AttributeMap &attribMap)
282 {
283 Display *display = nullptr;
284
285 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
286 const auto &iter = displays->find(nativeDisplay);
287 if (iter != displays->end())
288 {
289 display = iter->second;
290 }
291
292 if (display == nullptr)
293 {
294 // Validate the native display
295 if (!Display::isValidNativeDisplay(nativeDisplay))
296 {
297 return nullptr;
298 }
299
300 display = new Display(EGL_PLATFORM_ANGLE_ANGLE, nativeDisplay, nullptr);
301 displays->insert(std::make_pair(nativeDisplay, display));
302 }
303
304 // Apply new attributes if the display is not initialized yet.
305 if (!display->isInitialized())
306 {
307 rx::DisplayImpl *impl = CreateDisplayFromAttribs(attribMap, display->getState());
308 if (impl == nullptr)
309 {
310 // No valid display implementation for these attributes
311 return nullptr;
312 }
313
314 display->setAttributes(impl, attribMap);
315 }
316
317 return display;
318 }
319
320 // static
GetDisplayFromDevice(Device * device,const AttributeMap & attribMap)321 Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attribMap)
322 {
323 Display *display = nullptr;
324
325 ASSERT(Device::IsValidDevice(device));
326
327 ANGLEPlatformDisplayMap *anglePlatformDisplays = GetANGLEPlatformDisplayMap();
328 DevicePlatformDisplayMap *devicePlatformDisplays = GetDevicePlatformDisplayMap();
329
330 // First see if this eglDevice is in use by a Display created using ANGLE platform
331 for (auto &displayMapEntry : *anglePlatformDisplays)
332 {
333 egl::Display *iterDisplay = displayMapEntry.second;
334 if (iterDisplay->getDevice() == device)
335 {
336 display = iterDisplay;
337 }
338 }
339
340 if (display == nullptr)
341 {
342 // See if the eglDevice is in use by a Display created using the DEVICE platform
343 const auto &iter = devicePlatformDisplays->find(device);
344 if (iter != devicePlatformDisplays->end())
345 {
346 display = iter->second;
347 }
348 }
349
350 if (display == nullptr)
351 {
352 // Otherwise create a new Display
353 display = new Display(EGL_PLATFORM_DEVICE_EXT, 0, device);
354 devicePlatformDisplays->insert(std::make_pair(device, display));
355 }
356
357 // Apply new attributes if the display is not initialized yet.
358 if (!display->isInitialized())
359 {
360 rx::DisplayImpl *impl = CreateDisplayFromDevice(device, display->getState());
361 display->setAttributes(impl, attribMap);
362 }
363
364 return display;
365 }
366
367 //static
CleanupDisplays()368 void Display::CleanupDisplays()
369 {
370 // ~Display takes care of removing the entry from the according map
371 {
372 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
373 while (!displays->empty())
374 delete displays->begin()->second;
375 }
376
377 {
378 DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap();
379 while (!displays->empty())
380 delete displays->begin()->second;
381 }
382 }
383
Display(EGLenum platform,EGLNativeDisplayType displayId,Device * eglDevice)384 Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice)
385 : mImplementation(nullptr),
386 mDisplayId(displayId),
387 mAttributeMap(),
388 mConfigSet(),
389 mContextSet(),
390 mStreamSet(),
391 mInitialized(false),
392 mDeviceLost(false),
393 mCaps(),
394 mDisplayExtensions(),
395 mDisplayExtensionString(),
396 mVendorString(),
397 mDevice(eglDevice),
398 mPlatform(platform),
399 mTextureManager(nullptr),
400 mMemoryProgramCache(gl::kDefaultMaxProgramCacheMemoryBytes),
401 mGlobalTextureShareGroupUsers(0),
402 mProxyContext(this)
403 {
404 }
405
~Display()406 Display::~Display()
407 {
408 // TODO(jmadill): When is this called?
409 // terminate();
410
411 if (mPlatform == EGL_PLATFORM_ANGLE_ANGLE)
412 {
413 ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
414 ANGLEPlatformDisplayMap::iterator iter = displays->find(mDisplayId);
415 if (iter != displays->end())
416 {
417 displays->erase(iter);
418 }
419 }
420 else if (mPlatform == EGL_PLATFORM_DEVICE_EXT)
421 {
422 DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap();
423 DevicePlatformDisplayMap::iterator iter = displays->find(mDevice);
424 if (iter != displays->end())
425 {
426 displays->erase(iter);
427 }
428 }
429 else
430 {
431 UNREACHABLE();
432 }
433
434 mProxyContext.reset(nullptr);
435
436 SafeDelete(mDevice);
437 SafeDelete(mImplementation);
438 }
439
setAttributes(rx::DisplayImpl * impl,const AttributeMap & attribMap)440 void Display::setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap)
441 {
442 ASSERT(!mInitialized);
443
444 ASSERT(impl != nullptr);
445 SafeDelete(mImplementation);
446 mImplementation = impl;
447
448 mAttributeMap = attribMap;
449 }
450
initialize()451 Error Display::initialize()
452 {
453 // TODO(jmadill): Store Platform in Display and init here.
454 const angle::PlatformMethods *platformMethods =
455 reinterpret_cast<const angle::PlatformMethods *>(
456 mAttributeMap.get(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX, 0));
457 if (platformMethods != nullptr)
458 {
459 *ANGLEPlatformCurrent() = *platformMethods;
460 }
461 else
462 {
463 ANGLESetDefaultDisplayPlatform(this);
464 }
465
466 gl::InitializeDebugAnnotations(&mAnnotator);
467
468 SCOPED_ANGLE_HISTOGRAM_TIMER("GPU.ANGLE.DisplayInitializeMS");
469 TRACE_EVENT0("gpu.angle", "egl::Display::initialize");
470
471 ASSERT(mImplementation != nullptr);
472
473 if (isInitialized())
474 {
475 return NoError();
476 }
477
478 Error error = mImplementation->initialize(this);
479 if (error.isError())
480 {
481 // Log extended error message here
482 ERR() << "ANGLE Display::initialize error " << error.getID() << ": " << error.getMessage();
483 return error;
484 }
485
486 mCaps = mImplementation->getCaps();
487
488 mConfigSet = mImplementation->generateConfigs();
489 if (mConfigSet.size() == 0)
490 {
491 mImplementation->terminate();
492 return EglNotInitialized();
493 }
494
495 initDisplayExtensions();
496 initVendorString();
497
498 // Populate the Display's EGLDeviceEXT if the Display wasn't created using one
499 if (mPlatform != EGL_PLATFORM_DEVICE_EXT)
500 {
501 if (mDisplayExtensions.deviceQuery)
502 {
503 rx::DeviceImpl *impl = nullptr;
504 ANGLE_TRY(mImplementation->getDevice(&impl));
505 ANGLE_TRY(Device::CreateDevice(this, impl, &mDevice));
506 }
507 else
508 {
509 mDevice = nullptr;
510 }
511 }
512 else
513 {
514 // For EGL_PLATFORM_DEVICE_EXT, mDevice should always be populated using
515 // an external device
516 ASSERT(mDevice != nullptr);
517 }
518
519 mProxyContext.reset(nullptr);
520 gl::Context *proxyContext = new gl::Context(mImplementation, nullptr, nullptr, nullptr, nullptr,
521 egl::AttributeMap(), mDisplayExtensions);
522 mProxyContext.reset(proxyContext);
523
524 mInitialized = true;
525
526 return NoError();
527 }
528
terminate()529 Error Display::terminate()
530 {
531 ANGLE_TRY(makeCurrent(nullptr, nullptr, nullptr));
532
533 mMemoryProgramCache.clear();
534
535 mProxyContext.reset(nullptr);
536
537 while (!mContextSet.empty())
538 {
539 ANGLE_TRY(destroyContext(*mContextSet.begin()));
540 }
541
542 // The global texture manager should be deleted with the last context that uses it.
543 ASSERT(mGlobalTextureShareGroupUsers == 0 && mTextureManager == nullptr);
544
545 while (!mImageSet.empty())
546 {
547 destroyImage(*mImageSet.begin());
548 }
549
550 while (!mStreamSet.empty())
551 {
552 destroyStream(*mStreamSet.begin());
553 }
554
555 while (!mState.surfaceSet.empty())
556 {
557 ANGLE_TRY(destroySurface(*mState.surfaceSet.begin()));
558 }
559
560 mConfigSet.clear();
561
562 if (mDevice != nullptr && mDevice->getOwningDisplay() != nullptr)
563 {
564 // Don't delete the device if it was created externally using eglCreateDeviceANGLE
565 // We also shouldn't set it to null in case eglInitialize() is called again later
566 SafeDelete(mDevice);
567 }
568
569 mImplementation->terminate();
570
571 mDeviceLost = false;
572
573 mInitialized = false;
574
575 gl::UninitializeDebugAnnotations();
576
577 // TODO(jmadill): Store Platform in Display and deinit here.
578 ANGLEResetDisplayPlatform(this);
579
580 return NoError();
581 }
582
getConfigs(const egl::AttributeMap & attribs) const583 std::vector<const Config*> Display::getConfigs(const egl::AttributeMap &attribs) const
584 {
585 return mConfigSet.filter(attribs);
586 }
587
createWindowSurface(const Config * configuration,EGLNativeWindowType window,const AttributeMap & attribs,Surface ** outSurface)588 Error Display::createWindowSurface(const Config *configuration,
589 EGLNativeWindowType window,
590 const AttributeMap &attribs,
591 Surface **outSurface)
592 {
593 if (mImplementation->testDeviceLost())
594 {
595 ANGLE_TRY(restoreLostDevice());
596 }
597
598 SurfacePointer surface(new WindowSurface(mImplementation, configuration, window, attribs),
599 this);
600 ANGLE_TRY(surface->initialize(this));
601
602 ASSERT(outSurface != nullptr);
603 *outSurface = surface.release();
604 mState.surfaceSet.insert(*outSurface);
605
606 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
607 ASSERT(windowSurfaces && windowSurfaces->find(window) == windowSurfaces->end());
608 windowSurfaces->insert(std::make_pair(window, *outSurface));
609
610 return NoError();
611 }
612
createPbufferSurface(const Config * configuration,const AttributeMap & attribs,Surface ** outSurface)613 Error Display::createPbufferSurface(const Config *configuration,
614 const AttributeMap &attribs,
615 Surface **outSurface)
616 {
617 ASSERT(isInitialized());
618
619 if (mImplementation->testDeviceLost())
620 {
621 ANGLE_TRY(restoreLostDevice());
622 }
623
624 SurfacePointer surface(new PbufferSurface(mImplementation, configuration, attribs), this);
625 ANGLE_TRY(surface->initialize(this));
626
627 ASSERT(outSurface != nullptr);
628 *outSurface = surface.release();
629 mState.surfaceSet.insert(*outSurface);
630
631 return NoError();
632 }
633
createPbufferFromClientBuffer(const Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const AttributeMap & attribs,Surface ** outSurface)634 Error Display::createPbufferFromClientBuffer(const Config *configuration,
635 EGLenum buftype,
636 EGLClientBuffer clientBuffer,
637 const AttributeMap &attribs,
638 Surface **outSurface)
639 {
640 ASSERT(isInitialized());
641
642 if (mImplementation->testDeviceLost())
643 {
644 ANGLE_TRY(restoreLostDevice());
645 }
646
647 SurfacePointer surface(
648 new PbufferSurface(mImplementation, configuration, buftype, clientBuffer, attribs), this);
649 ANGLE_TRY(surface->initialize(this));
650
651 ASSERT(outSurface != nullptr);
652 *outSurface = surface.release();
653 mState.surfaceSet.insert(*outSurface);
654
655 return NoError();
656 }
657
createPixmapSurface(const Config * configuration,NativePixmapType nativePixmap,const AttributeMap & attribs,Surface ** outSurface)658 Error Display::createPixmapSurface(const Config *configuration,
659 NativePixmapType nativePixmap,
660 const AttributeMap &attribs,
661 Surface **outSurface)
662 {
663 ASSERT(isInitialized());
664
665 if (mImplementation->testDeviceLost())
666 {
667 ANGLE_TRY(restoreLostDevice());
668 }
669
670 SurfacePointer surface(new PixmapSurface(mImplementation, configuration, nativePixmap, attribs),
671 this);
672 ANGLE_TRY(surface->initialize(this));
673
674 ASSERT(outSurface != nullptr);
675 *outSurface = surface.release();
676 mState.surfaceSet.insert(*outSurface);
677
678 return NoError();
679 }
680
createImage(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const AttributeMap & attribs,Image ** outImage)681 Error Display::createImage(const gl::Context *context,
682 EGLenum target,
683 EGLClientBuffer buffer,
684 const AttributeMap &attribs,
685 Image **outImage)
686 {
687 ASSERT(isInitialized());
688
689 if (mImplementation->testDeviceLost())
690 {
691 ANGLE_TRY(restoreLostDevice());
692 }
693
694 egl::ImageSibling *sibling = nullptr;
695 if (IsTextureTarget(target))
696 {
697 sibling = context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
698 }
699 else if (IsRenderbufferTarget(target))
700 {
701 sibling = context->getRenderbuffer(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
702 }
703 else
704 {
705 UNREACHABLE();
706 }
707 ASSERT(sibling != nullptr);
708
709 angle::UniqueObjectPointer<Image, gl::Context> imagePtr(
710 new Image(mImplementation, target, sibling, attribs), context);
711 ANGLE_TRY(imagePtr->initialize());
712
713 Image *image = imagePtr.release();
714
715 ASSERT(outImage != nullptr);
716 *outImage = image;
717
718 // Add this image to the list of all images and hold a ref to it.
719 image->addRef();
720 mImageSet.insert(image);
721
722 return NoError();
723 }
724
createStream(const AttributeMap & attribs,Stream ** outStream)725 Error Display::createStream(const AttributeMap &attribs, Stream **outStream)
726 {
727 ASSERT(isInitialized());
728
729 Stream *stream = new Stream(this, attribs);
730
731 ASSERT(stream != nullptr);
732 mStreamSet.insert(stream);
733
734 ASSERT(outStream != nullptr);
735 *outStream = stream;
736
737 return NoError();
738 }
739
createContext(const Config * configuration,gl::Context * shareContext,const AttributeMap & attribs,gl::Context ** outContext)740 Error Display::createContext(const Config *configuration,
741 gl::Context *shareContext,
742 const AttributeMap &attribs,
743 gl::Context **outContext)
744 {
745 ASSERT(isInitialized());
746
747 if (mImplementation->testDeviceLost())
748 {
749 ANGLE_TRY(restoreLostDevice());
750 }
751
752 // This display texture sharing will allow the first context to create the texture share group.
753 bool usingDisplayTextureShareGroup =
754 attribs.get(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE;
755 gl::TextureManager *shareTextures = nullptr;
756
757 if (usingDisplayTextureShareGroup)
758 {
759 ASSERT((mTextureManager == nullptr) == (mGlobalTextureShareGroupUsers == 0));
760 if (mTextureManager == nullptr)
761 {
762 mTextureManager = new gl::TextureManager();
763 }
764
765 mGlobalTextureShareGroupUsers++;
766 shareTextures = mTextureManager;
767 }
768
769 gl::MemoryProgramCache *cachePointer = &mMemoryProgramCache;
770
771 // Check context creation attributes to see if we should enable the cache.
772 if (mAttributeMap.get(EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE, EGL_TRUE) == EGL_FALSE)
773 {
774 cachePointer = nullptr;
775 }
776
777 // A program cache size of zero indicates it should be disabled.
778 if (mMemoryProgramCache.maxSize() == 0)
779 {
780 cachePointer = nullptr;
781 }
782
783 gl::Context *context =
784 new gl::Context(mImplementation, configuration, shareContext, shareTextures, cachePointer,
785 attribs, mDisplayExtensions);
786
787 ASSERT(context != nullptr);
788 mContextSet.insert(context);
789
790 ASSERT(outContext != nullptr);
791 *outContext = context;
792 return NoError();
793 }
794
makeCurrent(egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)795 Error Display::makeCurrent(egl::Surface *drawSurface,
796 egl::Surface *readSurface,
797 gl::Context *context)
798 {
799 ANGLE_TRY(mImplementation->makeCurrent(drawSurface, readSurface, context));
800
801 if (context != nullptr)
802 {
803 ASSERT(readSurface == drawSurface);
804 ANGLE_TRY(context->makeCurrent(this, drawSurface));
805 }
806
807 return NoError();
808 }
809
restoreLostDevice()810 Error Display::restoreLostDevice()
811 {
812 for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
813 {
814 if ((*ctx)->isResetNotificationEnabled())
815 {
816 // If reset notifications have been requested, application must delete all contexts first
817 return EglContextLost();
818 }
819 }
820
821 return mImplementation->restoreLostDevice(this);
822 }
823
destroySurface(Surface * surface)824 Error Display::destroySurface(Surface *surface)
825 {
826 if (surface->getType() == EGL_WINDOW_BIT)
827 {
828 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
829 ASSERT(windowSurfaces);
830
831 bool surfaceRemoved = false;
832 for (WindowSurfaceMap::iterator iter = windowSurfaces->begin(); iter != windowSurfaces->end(); iter++)
833 {
834 if (iter->second == surface)
835 {
836 windowSurfaces->erase(iter);
837 surfaceRemoved = true;
838 break;
839 }
840 }
841
842 ASSERT(surfaceRemoved);
843 }
844
845 mState.surfaceSet.erase(surface);
846 ANGLE_TRY(surface->onDestroy(this));
847 return NoError();
848 }
849
destroyImage(egl::Image * image)850 void Display::destroyImage(egl::Image *image)
851 {
852 auto iter = mImageSet.find(image);
853 ASSERT(iter != mImageSet.end());
854 (*iter)->release(mProxyContext.get());
855 mImageSet.erase(iter);
856 }
857
destroyStream(egl::Stream * stream)858 void Display::destroyStream(egl::Stream *stream)
859 {
860 mStreamSet.erase(stream);
861 SafeDelete(stream);
862 }
863
destroyContext(gl::Context * context)864 Error Display::destroyContext(gl::Context *context)
865 {
866 if (context->usingDisplayTextureShareGroup())
867 {
868 ASSERT(mGlobalTextureShareGroupUsers >= 1 && mTextureManager != nullptr);
869 if (mGlobalTextureShareGroupUsers == 1)
870 {
871 // If this is the last context using the global share group, destroy the global texture
872 // manager so that the textures can be destroyed while a context still exists
873 mTextureManager->release(context);
874 mTextureManager = nullptr;
875 }
876 mGlobalTextureShareGroupUsers--;
877 }
878
879 ANGLE_TRY(context->onDestroy(this));
880 mContextSet.erase(context);
881 SafeDelete(context);
882 return NoError();
883 }
884
isDeviceLost() const885 bool Display::isDeviceLost() const
886 {
887 ASSERT(isInitialized());
888 return mDeviceLost;
889 }
890
testDeviceLost()891 bool Display::testDeviceLost()
892 {
893 ASSERT(isInitialized());
894
895 if (!mDeviceLost && mImplementation->testDeviceLost())
896 {
897 notifyDeviceLost();
898 }
899
900 return mDeviceLost;
901 }
902
notifyDeviceLost()903 void Display::notifyDeviceLost()
904 {
905 if (mDeviceLost)
906 {
907 return;
908 }
909
910 for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++)
911 {
912 (*context)->markContextLost();
913 }
914
915 mDeviceLost = true;
916 }
917
waitClient(const gl::Context * context) const918 Error Display::waitClient(const gl::Context *context) const
919 {
920 return mImplementation->waitClient(context);
921 }
922
waitNative(const gl::Context * context,EGLint engine) const923 Error Display::waitNative(const gl::Context *context, EGLint engine) const
924 {
925 return mImplementation->waitNative(context, engine);
926 }
927
getCaps() const928 const Caps &Display::getCaps() const
929 {
930 return mCaps;
931 }
932
isInitialized() const933 bool Display::isInitialized() const
934 {
935 return mInitialized;
936 }
937
isValidConfig(const Config * config) const938 bool Display::isValidConfig(const Config *config) const
939 {
940 return mConfigSet.contains(config);
941 }
942
isValidContext(const gl::Context * context) const943 bool Display::isValidContext(const gl::Context *context) const
944 {
945 return mContextSet.find(const_cast<gl::Context *>(context)) != mContextSet.end();
946 }
947
isValidSurface(const Surface * surface) const948 bool Display::isValidSurface(const Surface *surface) const
949 {
950 return mState.surfaceSet.find(const_cast<Surface *>(surface)) != mState.surfaceSet.end();
951 }
952
isValidImage(const Image * image) const953 bool Display::isValidImage(const Image *image) const
954 {
955 return mImageSet.find(const_cast<Image *>(image)) != mImageSet.end();
956 }
957
isValidStream(const Stream * stream) const958 bool Display::isValidStream(const Stream *stream) const
959 {
960 return mStreamSet.find(const_cast<Stream *>(stream)) != mStreamSet.end();
961 }
962
hasExistingWindowSurface(EGLNativeWindowType window)963 bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
964 {
965 WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
966 ASSERT(windowSurfaces);
967
968 return windowSurfaces->find(window) != windowSurfaces->end();
969 }
970
GenerateClientExtensions()971 static ClientExtensions GenerateClientExtensions()
972 {
973 ClientExtensions extensions;
974
975 extensions.clientExtensions = true;
976 extensions.platformBase = true;
977 extensions.platformANGLE = true;
978
979 #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
980 extensions.platformANGLED3D = true;
981 extensions.platformDevice = true;
982 #endif
983
984 #if defined(ANGLE_ENABLE_OPENGL)
985 extensions.platformANGLEOpenGL = true;
986 #endif
987
988 #if defined(ANGLE_ENABLE_NULL)
989 extensions.platformANGLENULL = true;
990 #endif
991
992 #if defined(ANGLE_ENABLE_D3D11)
993 extensions.deviceCreation = true;
994 extensions.deviceCreationD3D11 = true;
995 extensions.experimentalPresentPath = true;
996 #endif
997
998 #if defined(ANGLE_ENABLE_VULKAN)
999 extensions.platformANGLEVulkan = true;
1000 #endif
1001
1002 #if defined(ANGLE_USE_X11)
1003 extensions.x11Visual = true;
1004 #endif
1005
1006 extensions.clientGetAllProcAddresses = true;
1007
1008 return extensions;
1009 }
1010
1011 template <typename T>
GenerateExtensionsString(const T & extensions)1012 static std::string GenerateExtensionsString(const T &extensions)
1013 {
1014 std::vector<std::string> extensionsVector = extensions.getStrings();
1015
1016 std::ostringstream stream;
1017 std::copy(extensionsVector.begin(), extensionsVector.end(), std::ostream_iterator<std::string>(stream, " "));
1018 return stream.str();
1019 }
1020
1021 // static
GetClientExtensions()1022 const ClientExtensions &Display::GetClientExtensions()
1023 {
1024 static const ClientExtensions clientExtensions = GenerateClientExtensions();
1025 return clientExtensions;
1026 }
1027
1028 // static
GetClientExtensionString()1029 const std::string &Display::GetClientExtensionString()
1030 {
1031 static const std::string clientExtensionsString =
1032 GenerateExtensionsString(GetClientExtensions());
1033 return clientExtensionsString;
1034 }
1035
initDisplayExtensions()1036 void Display::initDisplayExtensions()
1037 {
1038 mDisplayExtensions = mImplementation->getExtensions();
1039
1040 // Some extensions are always available because they are implemented in the EGL layer.
1041 mDisplayExtensions.createContext = true;
1042 mDisplayExtensions.createContextNoError = true;
1043 mDisplayExtensions.createContextWebGLCompatibility = true;
1044 mDisplayExtensions.createContextBindGeneratesResource = true;
1045 mDisplayExtensions.createContextClientArrays = true;
1046 mDisplayExtensions.pixelFormatFloat = true;
1047
1048 // Force EGL_KHR_get_all_proc_addresses on.
1049 mDisplayExtensions.getAllProcAddresses = true;
1050
1051 // Enable program cache control since it is not back-end dependent.
1052 mDisplayExtensions.programCacheControl = true;
1053
1054 mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions);
1055 }
1056
isValidNativeWindow(EGLNativeWindowType window) const1057 bool Display::isValidNativeWindow(EGLNativeWindowType window) const
1058 {
1059 return mImplementation->isValidNativeWindow(window);
1060 }
1061
validateClientBuffer(const Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const AttributeMap & attribs)1062 Error Display::validateClientBuffer(const Config *configuration,
1063 EGLenum buftype,
1064 EGLClientBuffer clientBuffer,
1065 const AttributeMap &attribs)
1066 {
1067 return mImplementation->validateClientBuffer(configuration, buftype, clientBuffer, attribs);
1068 }
1069
isValidDisplay(const egl::Display * display)1070 bool Display::isValidDisplay(const egl::Display *display)
1071 {
1072 const ANGLEPlatformDisplayMap *anglePlatformDisplayMap = GetANGLEPlatformDisplayMap();
1073 for (const auto &displayPair : *anglePlatformDisplayMap)
1074 {
1075 if (displayPair.second == display)
1076 {
1077 return true;
1078 }
1079 }
1080
1081 const DevicePlatformDisplayMap *devicePlatformDisplayMap = GetDevicePlatformDisplayMap();
1082 for (const auto &displayPair : *devicePlatformDisplayMap)
1083 {
1084 if (displayPair.second == display)
1085 {
1086 return true;
1087 }
1088 }
1089
1090 return false;
1091 }
1092
isValidNativeDisplay(EGLNativeDisplayType display)1093 bool Display::isValidNativeDisplay(EGLNativeDisplayType display)
1094 {
1095 // TODO(jmadill): handle this properly
1096 if (display == EGL_DEFAULT_DISPLAY)
1097 {
1098 return true;
1099 }
1100
1101 #if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_ENABLE_WINDOWS_STORE)
1102 if (display == EGL_SOFTWARE_DISPLAY_ANGLE ||
1103 display == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
1104 display == EGL_D3D11_ONLY_DISPLAY_ANGLE)
1105 {
1106 return true;
1107 }
1108 return (WindowFromDC(display) != nullptr);
1109 #else
1110 return true;
1111 #endif
1112 }
1113
initVendorString()1114 void Display::initVendorString()
1115 {
1116 mVendorString = mImplementation->getVendorString();
1117 }
1118
getExtensions() const1119 const DisplayExtensions &Display::getExtensions() const
1120 {
1121 return mDisplayExtensions;
1122 }
1123
getExtensionString() const1124 const std::string &Display::getExtensionString() const
1125 {
1126 return mDisplayExtensionString;
1127 }
1128
getVendorString() const1129 const std::string &Display::getVendorString() const
1130 {
1131 return mVendorString;
1132 }
1133
getDevice() const1134 Device *Display::getDevice() const
1135 {
1136 return mDevice;
1137 }
1138
getMaxSupportedESVersion() const1139 gl::Version Display::getMaxSupportedESVersion() const
1140 {
1141 return mImplementation->getMaxSupportedESVersion();
1142 }
1143
programCacheGetAttrib(EGLenum attrib) const1144 EGLint Display::programCacheGetAttrib(EGLenum attrib) const
1145 {
1146 switch (attrib)
1147 {
1148 case EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE:
1149 return static_cast<EGLint>(gl::kProgramHashLength);
1150
1151 case EGL_PROGRAM_CACHE_SIZE_ANGLE:
1152 return static_cast<EGLint>(mMemoryProgramCache.entryCount());
1153
1154 default:
1155 UNREACHABLE();
1156 return 0;
1157 }
1158 }
1159
programCacheQuery(EGLint index,void * key,EGLint * keysize,void * binary,EGLint * binarysize)1160 Error Display::programCacheQuery(EGLint index,
1161 void *key,
1162 EGLint *keysize,
1163 void *binary,
1164 EGLint *binarysize)
1165 {
1166 ASSERT(index >= 0 && index < static_cast<EGLint>(mMemoryProgramCache.entryCount()));
1167
1168 const angle::MemoryBuffer *programBinary = nullptr;
1169 gl::ProgramHash programHash;
1170 // TODO(jmadill): Make this thread-safe.
1171 bool result =
1172 mMemoryProgramCache.getAt(static_cast<size_t>(index), &programHash, &programBinary);
1173 if (!result)
1174 {
1175 return EglBadAccess() << "Program binary not accessible.";
1176 }
1177
1178 ASSERT(keysize && binarysize);
1179
1180 if (key)
1181 {
1182 ASSERT(*keysize == static_cast<EGLint>(gl::kProgramHashLength));
1183 memcpy(key, programHash.data(), gl::kProgramHashLength);
1184 }
1185
1186 if (binary)
1187 {
1188 // Note: we check the size here instead of in the validation code, since we need to
1189 // access the cache as atomically as possible. It's possible that the cache contents
1190 // could change between the validation size check and the retrieval.
1191 if (programBinary->size() > static_cast<size_t>(*binarysize))
1192 {
1193 return EglBadAccess() << "Program binary too large or changed during access.";
1194 }
1195
1196 memcpy(binary, programBinary->data(), programBinary->size());
1197 }
1198
1199 *binarysize = static_cast<EGLint>(programBinary->size());
1200 *keysize = static_cast<EGLint>(gl::kProgramHashLength);
1201
1202 return NoError();
1203 }
1204
programCachePopulate(const void * key,EGLint keysize,const void * binary,EGLint binarysize)1205 Error Display::programCachePopulate(const void *key,
1206 EGLint keysize,
1207 const void *binary,
1208 EGLint binarysize)
1209 {
1210 ASSERT(keysize == static_cast<EGLint>(gl::kProgramHashLength));
1211
1212 gl::ProgramHash programHash;
1213 memcpy(programHash.data(), key, gl::kProgramHashLength);
1214
1215 mMemoryProgramCache.putBinary(programHash, reinterpret_cast<const uint8_t *>(binary),
1216 static_cast<size_t>(binarysize));
1217 return NoError();
1218 }
1219
programCacheResize(EGLint limit,EGLenum mode)1220 EGLint Display::programCacheResize(EGLint limit, EGLenum mode)
1221 {
1222 switch (mode)
1223 {
1224 case EGL_PROGRAM_CACHE_RESIZE_ANGLE:
1225 {
1226 size_t initialSize = mMemoryProgramCache.size();
1227 mMemoryProgramCache.resize(static_cast<size_t>(limit));
1228 return static_cast<EGLint>(initialSize);
1229 }
1230
1231 case EGL_PROGRAM_CACHE_TRIM_ANGLE:
1232 return static_cast<EGLint>(mMemoryProgramCache.trim(static_cast<size_t>(limit)));
1233
1234 default:
1235 UNREACHABLE();
1236 return 0;
1237 }
1238 }
1239
1240 } // namespace egl
1241