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