• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 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 // DisplayEGL.cpp: Common across EGL parts of platform specific egl::Display implementations
8 
9 #include "libANGLE/renderer/gl/egl/DisplayEGL.h"
10 
11 #include "common/debug.h"
12 #include "libANGLE/Context.h"
13 #include "libANGLE/Display.h"
14 #include "libANGLE/Surface.h"
15 #include "libANGLE/renderer/gl/ContextGL.h"
16 #include "libANGLE/renderer/gl/RendererGL.h"
17 #include "libANGLE/renderer/gl/egl/ContextEGL.h"
18 #include "libANGLE/renderer/gl/egl/DmaBufImageSiblingEGL.h"
19 #include "libANGLE/renderer/gl/egl/FunctionsEGLDL.h"
20 #include "libANGLE/renderer/gl/egl/ImageEGL.h"
21 #include "libANGLE/renderer/gl/egl/PbufferSurfaceEGL.h"
22 #include "libANGLE/renderer/gl/egl/RendererEGL.h"
23 #include "libANGLE/renderer/gl/egl/SyncEGL.h"
24 #include "libANGLE/renderer/gl/egl/WindowSurfaceEGL.h"
25 #include "libANGLE/renderer/gl/renderergl_utils.h"
26 
27 namespace
28 {
29 
GetRobustnessVideoMemoryPurge(const egl::AttributeMap & attribs)30 rx::RobustnessVideoMemoryPurgeStatus GetRobustnessVideoMemoryPurge(const egl::AttributeMap &attribs)
31 {
32     return static_cast<rx::RobustnessVideoMemoryPurgeStatus>(
33         attribs.get(EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, GL_FALSE));
34 }
35 
RenderableTypesFromPlatformAttrib(const rx::FunctionsEGL * egl,const EGLAttrib platformAttrib)36 std::vector<EGLint> RenderableTypesFromPlatformAttrib(const rx::FunctionsEGL *egl,
37                                                       const EGLAttrib platformAttrib)
38 {
39     std::vector<EGLint> renderableTypes;
40     switch (platformAttrib)
41     {
42         case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
43             renderableTypes.push_back(EGL_OPENGL_BIT);
44             break;
45 
46         case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
47         {
48             static_assert(EGL_OPENGL_ES3_BIT == EGL_OPENGL_ES3_BIT_KHR,
49                           "Extension define must match core");
50 
51             gl::Version eglVersion(egl->majorVersion, egl->minorVersion);
52             if (eglVersion >= gl::Version(1, 5) || egl->hasExtension("EGL_KHR_create_context"))
53             {
54                 renderableTypes.push_back(EGL_OPENGL_ES3_BIT);
55             }
56             renderableTypes.push_back(EGL_OPENGL_ES2_BIT);
57         }
58         break;
59 
60         default:
61             break;
62     }
63     return renderableTypes;
64 }
65 
66 class WorkerContextEGL final : public rx::WorkerContext
67 {
68   public:
69     WorkerContextEGL(EGLContext context, rx::FunctionsEGL *functions, EGLSurface pbuffer);
70     ~WorkerContextEGL() override;
71 
72     bool makeCurrent() override;
73     void unmakeCurrent() override;
74 
75   private:
76     EGLContext mContext;
77     rx::FunctionsEGL *mFunctions;
78     EGLSurface mPbuffer;
79 };
80 
WorkerContextEGL(EGLContext context,rx::FunctionsEGL * functions,EGLSurface pbuffer)81 WorkerContextEGL::WorkerContextEGL(EGLContext context,
82                                    rx::FunctionsEGL *functions,
83                                    EGLSurface pbuffer)
84     : mContext(context), mFunctions(functions), mPbuffer(pbuffer)
85 {}
86 
~WorkerContextEGL()87 WorkerContextEGL::~WorkerContextEGL()
88 {
89     mFunctions->destroyContext(mContext);
90 }
91 
makeCurrent()92 bool WorkerContextEGL::makeCurrent()
93 {
94     if (mFunctions->makeCurrent(mPbuffer, mContext) == EGL_FALSE)
95     {
96         ERR() << "Unable to make the EGL context current.";
97         return false;
98     }
99     return true;
100 }
101 
unmakeCurrent()102 void WorkerContextEGL::unmakeCurrent()
103 {
104     mFunctions->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
105 }
106 
107 }  // namespace
108 
109 namespace rx
110 {
111 
DisplayEGL(const egl::DisplayState & state)112 DisplayEGL::DisplayEGL(const egl::DisplayState &state) : DisplayGL(state) {}
113 
~DisplayEGL()114 DisplayEGL::~DisplayEGL() {}
115 
createImage(const egl::ImageState & state,const gl::Context * context,EGLenum target,const egl::AttributeMap & attribs)116 ImageImpl *DisplayEGL::createImage(const egl::ImageState &state,
117                                    const gl::Context *context,
118                                    EGLenum target,
119                                    const egl::AttributeMap &attribs)
120 {
121     return new ImageEGL(state, context, target, attribs, mEGL);
122 }
123 
createSync(const egl::AttributeMap & attribs)124 EGLSyncImpl *DisplayEGL::createSync(const egl::AttributeMap &attribs)
125 {
126     return new SyncEGL(attribs, mEGL);
127 }
128 
getEGLPath() const129 const char *DisplayEGL::getEGLPath() const
130 {
131 #if defined(ANGLE_PLATFORM_ANDROID)
132 #    if defined(__LP64__)
133     return "/system/lib64/libEGL.so";
134 #    else
135     return "/system/lib/libEGL.so";
136 #    endif
137 #else
138     return "libEGL.so.1";
139 #endif
140 }
141 
initializeContext(EGLContext shareContext,const egl::AttributeMap & eglAttributes,EGLContext * outContext,native_egl::AttributeVector * outAttribs) const142 egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
143                                          const egl::AttributeMap &eglAttributes,
144                                          EGLContext *outContext,
145                                          native_egl::AttributeVector *outAttribs) const
146 {
147     gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion);
148 
149     EGLint requestedMajor =
150         eglAttributes.getAsInt(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE);
151     EGLint requestedMinor =
152         eglAttributes.getAsInt(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE);
153     bool initializeRequested = requestedMajor != EGL_DONT_CARE && requestedMinor != EGL_DONT_CARE;
154 
155     static_assert(EGL_CONTEXT_MAJOR_VERSION == EGL_CONTEXT_MAJOR_VERSION_KHR,
156                   "Major Version define should match");
157     static_assert(EGL_CONTEXT_MINOR_VERSION == EGL_CONTEXT_MINOR_VERSION_KHR,
158                   "Minor Version define should match");
159 
160     std::vector<egl::AttributeMap> contextAttribLists;
161     if (eglVersion >= gl::Version(1, 5) || mEGL->hasExtension("EGL_KHR_create_context"))
162     {
163         if (initializeRequested)
164         {
165             egl::AttributeMap requestedVersionAttribs;
166             requestedVersionAttribs.insert(EGL_CONTEXT_MAJOR_VERSION, requestedMajor);
167             requestedVersionAttribs.insert(EGL_CONTEXT_MINOR_VERSION, requestedMinor);
168 
169             contextAttribLists.push_back(std::move(requestedVersionAttribs));
170         }
171         else
172         {
173             // clang-format off
174             const gl::Version esVersionsFrom2_0[] = {
175                 gl::Version(3, 2),
176                 gl::Version(3, 1),
177                 gl::Version(3, 0),
178                 gl::Version(2, 0),
179             };
180             // clang-format on
181 
182             for (const auto &version : esVersionsFrom2_0)
183             {
184                 egl::AttributeMap versionAttribs;
185                 versionAttribs.insert(EGL_CONTEXT_MAJOR_VERSION,
186                                       static_cast<EGLint>(version.major));
187                 versionAttribs.insert(EGL_CONTEXT_MINOR_VERSION,
188                                       static_cast<EGLint>(version.minor));
189 
190                 contextAttribLists.push_back(std::move(versionAttribs));
191             }
192         }
193     }
194     else
195     {
196         if (initializeRequested && (requestedMajor != 2 || requestedMinor != 0))
197         {
198             return egl::EglBadAttribute() << "Unsupported requested context version";
199         }
200 
201         egl::AttributeMap fallbackAttribs;
202         fallbackAttribs.insert(EGL_CONTEXT_CLIENT_VERSION, 2);
203 
204         contextAttribLists.push_back(std::move(fallbackAttribs));
205     }
206 
207     for (const egl::AttributeMap &attribs : contextAttribLists)
208     {
209         // If robustness is supported, try to create a context with robustness enabled. If it fails,
210         // fall back to creating a context without the robustness parameters. We've seen devices
211         // that expose the robustness extensions but fail to create robust contexts.
212         if (mHasEXTCreateContextRobustness)
213         {
214             egl::AttributeMap attribsWithRobustness(attribs);
215 
216             attribsWithRobustness.insert(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY,
217                                          EGL_LOSE_CONTEXT_ON_RESET);
218             if (mHasNVRobustnessVideoMemoryPurge)
219             {
220                 attribsWithRobustness.insert(EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, GL_TRUE);
221             }
222 
223             native_egl::AttributeVector attribVector = attribsWithRobustness.toIntVector();
224             EGLContext context = mEGL->createContext(mConfig, shareContext, attribVector.data());
225             if (context != EGL_NO_CONTEXT)
226             {
227                 *outContext = context;
228                 *outAttribs = std::move(attribVector);
229                 return egl::NoError();
230             }
231 
232             INFO() << "EGL_EXT_create_context_robustness available but robust context creation "
233                       "failed.";
234         }
235 
236         native_egl::AttributeVector attribVector = attribs.toIntVector();
237         EGLContext context = mEGL->createContext(mConfig, shareContext, attribVector.data());
238         if (context != EGL_NO_CONTEXT)
239         {
240             *outContext = context;
241             *outAttribs = std::move(attribVector);
242             return egl::NoError();
243         }
244     }
245 
246     return egl::Error(mEGL->getError(), "eglCreateContext failed");
247 }
248 
initialize(egl::Display * display)249 egl::Error DisplayEGL::initialize(egl::Display *display)
250 {
251     mDisplayAttributes = display->getAttributeMap();
252     mEGL               = new FunctionsEGLDL();
253 
254     void *eglHandle =
255         reinterpret_cast<void *>(mDisplayAttributes.get(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE, 0));
256     ANGLE_TRY(mEGL->initialize(display->getNativeDisplayId(), getEGLPath(), eglHandle));
257 
258     gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion);
259     if (eglVersion < gl::Version(1, 4))
260     {
261         return egl::EglNotInitialized() << "EGL >= 1.4 is required";
262     }
263 
264     mHasEXTCreateContextRobustness   = mEGL->hasExtension("EGL_EXT_create_context_robustness");
265     mHasNVRobustnessVideoMemoryPurge = mEGL->hasExtension("EGL_NV_robustness_video_memory_purge");
266     mSupportsNoConfigContexts        = mEGL->hasExtension("EGL_KHR_no_config_context") ||
267                                 mEGL->hasExtension("EGL_KHR_no_config_context");
268     mSupportsSurfaceless = mEGL->hasExtension("EGL_KHR_surfaceless_context");
269 
270     if (!mSupportsNoConfigContexts)
271     {
272         const EGLAttrib platformAttrib = mDisplayAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, 0);
273         std::vector<EGLint> renderableTypes =
274             RenderableTypesFromPlatformAttrib(mEGL, platformAttrib);
275         if (renderableTypes.empty())
276         {
277             return egl::EglNotInitialized() << "No available renderable types.";
278         }
279 
280         const EGLint surfaceTypes[] = {EGL_WINDOW_BIT | EGL_PBUFFER_BIT, EGL_DONT_CARE};
281 
282         egl::AttributeMap configAttribs;
283         // Choose RGBA8888
284         configAttribs.insert(EGL_RED_SIZE, 8);
285         configAttribs.insert(EGL_GREEN_SIZE, 8);
286         configAttribs.insert(EGL_BLUE_SIZE, 8);
287         configAttribs.insert(EGL_ALPHA_SIZE, 8);
288 
289         // Choose D24S8
290         // EGL1.5 spec Section 2.2 says that depth, multisample and stencil buffer depths
291         // must match for contexts to be compatible.
292         configAttribs.insert(EGL_DEPTH_SIZE, 24);
293         configAttribs.insert(EGL_STENCIL_SIZE, 8);
294 
295         for (EGLint surfaceType : surfaceTypes)
296         {
297             configAttribs.insert(EGL_SURFACE_TYPE, surfaceType);
298 
299             for (EGLint renderableType : renderableTypes)
300             {
301                 configAttribs.insert(EGL_RENDERABLE_TYPE, renderableType);
302 
303                 std::vector<EGLint> attribVector = configAttribs.toIntVector();
304 
305                 EGLint numConfig = 0;
306                 if (mEGL->chooseConfig(attribVector.data(), &mConfig, 1, &numConfig) == EGL_TRUE)
307                 {
308                     break;
309                 }
310             }
311         }
312 
313         if (mConfig == EGL_NO_CONFIG_KHR)
314         {
315             return egl::EglNotInitialized()
316                    << "eglChooseConfig failed with " << egl::Error(mEGL->getError());
317         }
318 
319         mConfigAttribList = configAttribs.toIntVector();
320     }
321 
322     // A mock pbuffer is only needed if surfaceless contexts are not supported.
323     mSupportsSurfaceless = mEGL->hasExtension("EGL_KHR_surfaceless_context");
324     if (!mSupportsSurfaceless)
325     {
326         // clang-format off
327         constexpr const EGLint pbufferConfigAttribs[] =
328         {
329             // We want RGBA8 and DEPTH24_STENCIL8
330             EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
331             EGL_RED_SIZE, 8,
332             EGL_GREEN_SIZE, 8,
333             EGL_BLUE_SIZE, 8,
334             EGL_ALPHA_SIZE, 8,
335             EGL_DEPTH_SIZE, 24,
336             EGL_STENCIL_SIZE, 8,
337             EGL_NONE,
338         };
339 
340         constexpr const int mockPbufferAttribs[] = {
341             EGL_WIDTH, 1,
342             EGL_HEIGHT, 1,
343             EGL_NONE,
344         };
345         // clang-format on
346 
347         EGLint numConfig;
348         EGLConfig pbufferConfig;
349         if (!mEGL->chooseConfig(pbufferConfigAttribs, &pbufferConfig, 1, &numConfig) ||
350             numConfig < 1)
351         {
352             return egl::EglNotInitialized() << "Failed to find a config for the mock pbuffer.";
353         }
354 
355         mMockPbuffer = mEGL->createPbufferSurface(pbufferConfig, mockPbufferAttribs);
356         if (mMockPbuffer == EGL_NO_SURFACE)
357         {
358             return egl::EglNotInitialized()
359                    << "eglCreatePbufferSurface failed with " << egl::Error(mEGL->getError());
360         }
361     }
362 
363     ANGLE_TRY(createRenderer(EGL_NO_CONTEXT, true, false, &mRenderer));
364 
365     const gl::Version &maxVersion = mRenderer->getMaxSupportedESVersion();
366     if (maxVersion < gl::Version(2, 0))
367     {
368         return egl::EglNotInitialized() << "OpenGL ES 2.0 is not supportable.";
369     }
370 
371     ANGLE_TRY(DisplayGL::initialize(display));
372 
373     INFO() << "ANGLE DisplayEGL initialized: " << getRendererDescription();
374 
375     return egl::NoError();
376 }
377 
terminate()378 void DisplayEGL::terminate()
379 {
380     DisplayGL::terminate();
381 
382     EGLBoolean success = mEGL->makeCurrent(EGL_NO_SURFACE, EGL_NO_CONTEXT);
383     if (success == EGL_FALSE)
384     {
385         ERR() << "eglMakeCurrent error " << egl::Error(mEGL->getError());
386     }
387 
388     if (mMockPbuffer != EGL_NO_SURFACE)
389     {
390         success      = mEGL->destroySurface(mMockPbuffer);
391         mMockPbuffer = EGL_NO_SURFACE;
392         if (success == EGL_FALSE)
393         {
394             ERR() << "eglDestroySurface error " << egl::Error(mEGL->getError());
395         }
396     }
397 
398     mRenderer.reset();
399     mVirtualizationGroups.clear();
400 
401     mCurrentNativeContexts.clear();
402 
403     egl::Error result = mEGL->terminate();
404     if (result.isError())
405     {
406         ERR() << "eglTerminate error " << result;
407     }
408 
409     SafeDelete(mEGL);
410 }
411 
createWindowSurface(const egl::SurfaceState & state,EGLNativeWindowType window,const egl::AttributeMap & attribs)412 SurfaceImpl *DisplayEGL::createWindowSurface(const egl::SurfaceState &state,
413                                              EGLNativeWindowType window,
414                                              const egl::AttributeMap &attribs)
415 {
416     EGLConfig config;
417     EGLint numConfig;
418     EGLBoolean success;
419 
420     const EGLint configAttribList[] = {EGL_CONFIG_ID, mConfigIds[state.config->configID], EGL_NONE};
421     success                         = mEGL->chooseConfig(configAttribList, &config, 1, &numConfig);
422     ASSERT(success && numConfig == 1);
423 
424     return new WindowSurfaceEGL(state, mEGL, config, window);
425 }
426 
createPbufferSurface(const egl::SurfaceState & state,const egl::AttributeMap & attribs)427 SurfaceImpl *DisplayEGL::createPbufferSurface(const egl::SurfaceState &state,
428                                               const egl::AttributeMap &attribs)
429 {
430     EGLConfig config;
431     EGLint numConfig;
432     EGLBoolean success;
433 
434     const EGLint configAttribList[] = {EGL_CONFIG_ID, mConfigIds[state.config->configID], EGL_NONE};
435     success                         = mEGL->chooseConfig(configAttribList, &config, 1, &numConfig);
436     ASSERT(success && numConfig == 1);
437 
438     return new PbufferSurfaceEGL(state, mEGL, config);
439 }
440 
441 class ExternalSurfaceEGL : public SurfaceEGL
442 {
443   public:
ExternalSurfaceEGL(const egl::SurfaceState & state,const FunctionsEGL * egl,EGLConfig config,EGLint width,EGLint height)444     ExternalSurfaceEGL(const egl::SurfaceState &state,
445                        const FunctionsEGL *egl,
446                        EGLConfig config,
447                        EGLint width,
448                        EGLint height)
449         : SurfaceEGL(state, egl, config), mWidth(width), mHeight(height)
450     {}
451     ~ExternalSurfaceEGL() override = default;
452 
initialize(const egl::Display * display)453     egl::Error initialize(const egl::Display *display) override { return egl::NoError(); }
getSwapBehavior() const454     EGLint getSwapBehavior() const override { return EGL_BUFFER_DESTROYED; }
getWidth() const455     EGLint getWidth() const override { return mWidth; }
getHeight() const456     EGLint getHeight() const override { return mHeight; }
isExternal() const457     bool isExternal() const override { return true; }
458 
459   private:
460     const EGLint mWidth;
461     const EGLint mHeight;
462 };
463 
createPbufferFromClientBuffer(const egl::SurfaceState & state,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs)464 SurfaceImpl *DisplayEGL::createPbufferFromClientBuffer(const egl::SurfaceState &state,
465                                                        EGLenum buftype,
466                                                        EGLClientBuffer clientBuffer,
467                                                        const egl::AttributeMap &attribs)
468 {
469     switch (buftype)
470     {
471         case EGL_EXTERNAL_SURFACE_ANGLE:
472             return new ExternalSurfaceEGL(state, mEGL, EGL_NO_CONFIG_KHR,
473                                           attribs.getAsInt(EGL_WIDTH, 0),
474                                           attribs.getAsInt(EGL_HEIGHT, 0));
475 
476         default:
477             return DisplayGL::createPbufferFromClientBuffer(state, buftype, clientBuffer, attribs);
478     }
479 }
480 
createPixmapSurface(const egl::SurfaceState & state,NativePixmapType nativePixmap,const egl::AttributeMap & attribs)481 SurfaceImpl *DisplayEGL::createPixmapSurface(const egl::SurfaceState &state,
482                                              NativePixmapType nativePixmap,
483                                              const egl::AttributeMap &attribs)
484 {
485     UNIMPLEMENTED();
486     return nullptr;
487 }
488 
createContext(const gl::State & state,gl::ErrorSet * errorSet,const egl::Config * configuration,const gl::Context * shareContext,const egl::AttributeMap & attribs)489 ContextImpl *DisplayEGL::createContext(const gl::State &state,
490                                        gl::ErrorSet *errorSet,
491                                        const egl::Config *configuration,
492                                        const gl::Context *shareContext,
493                                        const egl::AttributeMap &attribs)
494 {
495     bool usingExternalContext = attribs.get(EGL_EXTERNAL_CONTEXT_ANGLE, EGL_FALSE) == EGL_TRUE;
496     EGLAttrib virtualizationGroup =
497         attribs.get(EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE, EGL_DONT_CARE);
498     bool globalTextureShareGroup =
499         attribs.get(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE;
500 
501     std::shared_ptr<RendererEGL> renderer = mRenderer;
502     if (usingExternalContext)
503     {
504         ASSERT(!shareContext);
505         egl::Error error = createRenderer(EGL_NO_CONTEXT, false, true, &renderer);
506         if (error.isError())
507         {
508             ERR() << "Failed to create a shared renderer: " << error.getMessage();
509             return nullptr;
510         }
511     }
512     else if (virtualizationGroup != EGL_DONT_CARE)
513     {
514         renderer = mVirtualizationGroups[virtualizationGroup].lock();
515         if (!renderer)
516         {
517             // If the user requested a dispaly-level texture share group, all contexts must be in
518             // the same share group. Otherwise honor the user's share group request.
519             EGLContext nativeShareContext = EGL_NO_CONTEXT;
520             if (globalTextureShareGroup)
521             {
522                 nativeShareContext = mRenderer->getContext();
523             }
524             else if (shareContext)
525             {
526                 ContextEGL *shareContextEGL = GetImplAs<ContextEGL>(shareContext);
527                 nativeShareContext          = shareContextEGL->getContext();
528             }
529 
530             // Create a new renderer for this context.
531             egl::Error error = createRenderer(nativeShareContext, false, false, &renderer);
532             if (error.isError())
533             {
534                 ERR() << "Failed to create a shared renderer: " << error.getMessage();
535                 return nullptr;
536             }
537 
538             mVirtualizationGroups[virtualizationGroup] = renderer;
539         }
540     }
541     ASSERT(renderer);
542 
543     RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus =
544         GetRobustnessVideoMemoryPurge(attribs);
545     return new ContextEGL(state, errorSet, renderer, robustnessVideoMemoryPurgeStatus);
546 }
547 
548 template <typename T>
getConfigAttrib(EGLConfig config,EGLint attribute,T * value) const549 void DisplayEGL::getConfigAttrib(EGLConfig config, EGLint attribute, T *value) const
550 {
551     EGLint tmp;
552     EGLBoolean success = mEGL->getConfigAttrib(config, attribute, &tmp);
553     ASSERT(success == EGL_TRUE);
554     *value = tmp;
555 }
556 
557 template <typename T, typename U>
getConfigAttribIfExtension(EGLConfig config,EGLint attribute,T * value,const char * extension,const U & defaultValue) const558 void DisplayEGL::getConfigAttribIfExtension(EGLConfig config,
559                                             EGLint attribute,
560                                             T *value,
561                                             const char *extension,
562                                             const U &defaultValue) const
563 {
564     if (mEGL->hasExtension(extension))
565     {
566         getConfigAttrib(config, attribute, value);
567     }
568     else
569     {
570         *value = static_cast<T>(defaultValue);
571     }
572 }
573 
generateConfigs()574 egl::ConfigSet DisplayEGL::generateConfigs()
575 {
576     egl::ConfigSet configSet;
577     mConfigIds.clear();
578 
579     std::vector<EGLConfig> configs;
580     if (mSupportsNoConfigContexts)
581     {
582         // Gather all configs
583         EGLint numConfigs;
584         EGLBoolean success = mEGL->getConfigs(nullptr, 0, &numConfigs);
585         ASSERT(success == EGL_TRUE && numConfigs > 0);
586 
587         configs.resize(numConfigs);
588         EGLint numConfigs2;
589         success = mEGL->getConfigs(configs.data(), numConfigs, &numConfigs2);
590         ASSERT(success == EGL_TRUE && numConfigs2 == numConfigs);
591     }
592     else
593     {
594         // Choose configs that match the attribute list of the config used for the context
595         EGLint numConfigs;
596         EGLBoolean success = mEGL->chooseConfig(mConfigAttribList.data(), nullptr, 0, &numConfigs);
597         ASSERT(success == EGL_TRUE && numConfigs > 0);
598 
599         configs.resize(numConfigs);
600         EGLint numConfigs2;
601         success =
602             mEGL->chooseConfig(mConfigAttribList.data(), configs.data(), numConfigs, &numConfigs2);
603         ASSERT(success == EGL_TRUE && numConfigs2 == numConfigs);
604     }
605 
606     for (size_t i = 0; i < configs.size(); i++)
607     {
608         egl::Config config;
609 
610         getConfigAttrib(configs[i], EGL_BUFFER_SIZE, &config.bufferSize);
611         getConfigAttrib(configs[i], EGL_RED_SIZE, &config.redSize);
612         getConfigAttrib(configs[i], EGL_GREEN_SIZE, &config.greenSize);
613         getConfigAttrib(configs[i], EGL_BLUE_SIZE, &config.blueSize);
614         getConfigAttrib(configs[i], EGL_LUMINANCE_SIZE, &config.luminanceSize);
615         getConfigAttrib(configs[i], EGL_ALPHA_SIZE, &config.alphaSize);
616         getConfigAttrib(configs[i], EGL_ALPHA_MASK_SIZE, &config.alphaMaskSize);
617         getConfigAttrib(configs[i], EGL_BIND_TO_TEXTURE_RGB, &config.bindToTextureRGB);
618         getConfigAttrib(configs[i], EGL_BIND_TO_TEXTURE_RGBA, &config.bindToTextureRGBA);
619         getConfigAttrib(configs[i], EGL_COLOR_BUFFER_TYPE, &config.colorBufferType);
620         getConfigAttrib(configs[i], EGL_CONFIG_CAVEAT, &config.configCaveat);
621         getConfigAttrib(configs[i], EGL_CONFIG_ID, &config.configID);
622         getConfigAttrib(configs[i], EGL_CONFORMANT, &config.conformant);
623         getConfigAttrib(configs[i], EGL_DEPTH_SIZE, &config.depthSize);
624         getConfigAttrib(configs[i], EGL_LEVEL, &config.level);
625         getConfigAttrib(configs[i], EGL_MAX_PBUFFER_WIDTH, &config.maxPBufferWidth);
626         getConfigAttrib(configs[i], EGL_MAX_PBUFFER_HEIGHT, &config.maxPBufferHeight);
627         getConfigAttrib(configs[i], EGL_MAX_PBUFFER_PIXELS, &config.maxPBufferPixels);
628         getConfigAttrib(configs[i], EGL_MAX_SWAP_INTERVAL, &config.maxSwapInterval);
629         getConfigAttrib(configs[i], EGL_MIN_SWAP_INTERVAL, &config.minSwapInterval);
630         getConfigAttrib(configs[i], EGL_NATIVE_RENDERABLE, &config.nativeRenderable);
631         getConfigAttrib(configs[i], EGL_NATIVE_VISUAL_ID, &config.nativeVisualID);
632         getConfigAttrib(configs[i], EGL_NATIVE_VISUAL_TYPE, &config.nativeVisualType);
633         getConfigAttrib(configs[i], EGL_RENDERABLE_TYPE, &config.renderableType);
634         getConfigAttrib(configs[i], EGL_SAMPLE_BUFFERS, &config.sampleBuffers);
635         getConfigAttrib(configs[i], EGL_SAMPLES, &config.samples);
636         getConfigAttrib(configs[i], EGL_STENCIL_SIZE, &config.stencilSize);
637         getConfigAttrib(configs[i], EGL_SURFACE_TYPE, &config.surfaceType);
638         getConfigAttrib(configs[i], EGL_TRANSPARENT_TYPE, &config.transparentType);
639         getConfigAttrib(configs[i], EGL_TRANSPARENT_RED_VALUE, &config.transparentRedValue);
640         getConfigAttrib(configs[i], EGL_TRANSPARENT_GREEN_VALUE, &config.transparentGreenValue);
641         getConfigAttrib(configs[i], EGL_TRANSPARENT_BLUE_VALUE, &config.transparentBlueValue);
642         getConfigAttribIfExtension(configs[i], EGL_COLOR_COMPONENT_TYPE_EXT,
643                                    &config.colorComponentType, "EGL_EXT_pixel_format_float",
644                                    EGL_COLOR_COMPONENT_TYPE_FIXED_EXT);
645 
646         config.surfaceType = fixSurfaceType(config.surfaceType);
647 
648         if (config.colorBufferType == EGL_RGB_BUFFER)
649         {
650             config.renderTargetFormat = gl::GetConfigColorBufferFormat(&config);
651             if (config.renderTargetFormat == GL_NONE)
652             {
653                 ERR() << "RGBA(" << config.redSize << "," << config.greenSize << ","
654                       << config.blueSize << "," << config.alphaSize << ") not handled";
655                 continue;
656             }
657         }
658         else
659         {
660             continue;
661         }
662         config.depthStencilFormat = gl::GetConfigDepthStencilBufferFormat(&config);
663 
664         config.matchNativePixmap  = EGL_NONE;
665         config.optimalOrientation = 0;
666 
667         int internalId         = configSet.add(config);
668         mConfigIds[internalId] = config.configID;
669     }
670 
671     return configSet;
672 }
673 
testDeviceLost()674 bool DisplayEGL::testDeviceLost()
675 {
676     return false;
677 }
678 
restoreLostDevice(const egl::Display * display)679 egl::Error DisplayEGL::restoreLostDevice(const egl::Display *display)
680 {
681     UNIMPLEMENTED();
682     return egl::NoError();
683 }
684 
isValidNativeWindow(EGLNativeWindowType window) const685 bool DisplayEGL::isValidNativeWindow(EGLNativeWindowType window) const
686 {
687     return true;
688 }
689 
validateClientBuffer(const egl::Config * configuration,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const690 egl::Error DisplayEGL::validateClientBuffer(const egl::Config *configuration,
691                                             EGLenum buftype,
692                                             EGLClientBuffer clientBuffer,
693                                             const egl::AttributeMap &attribs) const
694 {
695     switch (buftype)
696     {
697         case EGL_EXTERNAL_SURFACE_ANGLE:
698             ASSERT(clientBuffer == nullptr);
699             return egl::NoError();
700 
701         default:
702             return DisplayGL::validateClientBuffer(configuration, buftype, clientBuffer, attribs);
703     }
704 }
705 
waitClient(const gl::Context * context)706 egl::Error DisplayEGL::waitClient(const gl::Context *context)
707 {
708     UNIMPLEMENTED();
709     return egl::NoError();
710 }
711 
waitNative(const gl::Context * context,EGLint engine)712 egl::Error DisplayEGL::waitNative(const gl::Context *context, EGLint engine)
713 {
714     UNIMPLEMENTED();
715     return egl::NoError();
716 }
717 
makeCurrent(egl::Display * display,egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)718 egl::Error DisplayEGL::makeCurrent(egl::Display *display,
719                                    egl::Surface *drawSurface,
720                                    egl::Surface *readSurface,
721                                    gl::Context *context)
722 {
723     CurrentNativeContext &currentContext = mCurrentNativeContexts[std::this_thread::get_id()];
724 
725     EGLSurface newSurface = EGL_NO_SURFACE;
726     if (drawSurface)
727     {
728         SurfaceEGL *drawSurfaceEGL = GetImplAs<SurfaceEGL>(drawSurface);
729         newSurface                 = drawSurfaceEGL->getSurface();
730     }
731 
732     EGLContext newContext = EGL_NO_CONTEXT;
733     if (context)
734     {
735         ContextEGL *contextEGL = GetImplAs<ContextEGL>(context);
736         newContext             = contextEGL->getContext();
737     }
738 
739     if (currentContext.isExternalContext || (context && context->isExternal()))
740     {
741         ASSERT(currentContext.surface == EGL_NO_SURFACE);
742         if (!currentContext.isExternalContext)
743         {
744             // Switch to an ANGLE external context.
745             ASSERT(context);
746             ASSERT(currentContext.context == EGL_NO_CONTEXT);
747             currentContext.context           = newContext;
748             currentContext.isExternalContext = true;
749 
750             // We only support using external surface with external context.
751             ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->isExternal());
752             ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->getSurface() == EGL_NO_SURFACE);
753         }
754         else if (context)
755         {
756             // Switch surface but not context.
757             ASSERT(currentContext.context == newContext);
758             ASSERT(newSurface == EGL_NO_SURFACE);
759             ASSERT(newContext != EGL_NO_CONTEXT);
760             // We only support using external surface with external context.
761             ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->isExternal());
762             ASSERT(GetImplAs<SurfaceEGL>(drawSurface)->getSurface() == EGL_NO_SURFACE);
763         }
764         else
765         {
766             // Release the ANGLE external context.
767             ASSERT(newSurface == EGL_NO_SURFACE);
768             ASSERT(newContext == EGL_NO_CONTEXT);
769             ASSERT(currentContext.context != EGL_NO_CONTEXT);
770             currentContext.context           = EGL_NO_CONTEXT;
771             currentContext.isExternalContext = false;
772         }
773 
774         // Do not need to call eglMakeCurrent(), since we don't support switching EGLSurface for
775         // external context.
776         return DisplayGL::makeCurrent(display, drawSurface, readSurface, context);
777     }
778 
779     if (newSurface != currentContext.surface || newContext != currentContext.context)
780     {
781         if (mEGL->makeCurrent(newSurface, newContext) == EGL_FALSE)
782         {
783             return egl::Error(mEGL->getError(), "eglMakeCurrent failed");
784         }
785         currentContext.surface = newSurface;
786         currentContext.context = newContext;
787     }
788 
789     return DisplayGL::makeCurrent(display, drawSurface, readSurface, context);
790 }
791 
getMaxSupportedESVersion() const792 gl::Version DisplayEGL::getMaxSupportedESVersion() const
793 {
794     return mRenderer->getMaxSupportedESVersion();
795 }
796 
destroyNativeContext(EGLContext context)797 void DisplayEGL::destroyNativeContext(EGLContext context)
798 {
799     // If this context is current, remove it from the tracking of current contexts to make sure we
800     // don't try to make it current again.
801     for (auto &currentContext : mCurrentNativeContexts)
802     {
803         if (currentContext.second.context == context)
804         {
805             currentContext.second.surface = EGL_NO_SURFACE;
806             currentContext.second.context = EGL_NO_CONTEXT;
807         }
808     }
809 
810     mEGL->destroyContext(context);
811 }
812 
generateExtensions(egl::DisplayExtensions * outExtensions) const813 void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
814 {
815     gl::Version eglVersion(mEGL->majorVersion, mEGL->minorVersion);
816 
817     outExtensions->createContextRobustness =
818         mEGL->hasExtension("EGL_EXT_create_context_robustness");
819 
820     outExtensions->postSubBuffer    = false;  // Since SurfaceEGL::postSubBuffer is not implemented
821     outExtensions->presentationTime = mEGL->hasExtension("EGL_ANDROID_presentation_time");
822 
823     // Contexts are virtualized so textures and semaphores can be shared globally
824     outExtensions->displayTextureShareGroup   = true;
825     outExtensions->displaySemaphoreShareGroup = true;
826 
827     // We will fallback to regular swap if swapBuffersWithDamage isn't
828     // supported, so indicate support here to keep validation happy.
829     outExtensions->swapBuffersWithDamage = true;
830 
831     outExtensions->image     = mEGL->hasExtension("EGL_KHR_image");
832     outExtensions->imageBase = mEGL->hasExtension("EGL_KHR_image_base");
833     // Pixmaps are not supported in ANGLE's EGL implementation.
834     // outExtensions->imagePixmap = mEGL->hasExtension("EGL_KHR_image_pixmap");
835     outExtensions->glTexture2DImage      = mEGL->hasExtension("EGL_KHR_gl_texture_2D_image");
836     outExtensions->glTextureCubemapImage = mEGL->hasExtension("EGL_KHR_gl_texture_cubemap_image");
837     outExtensions->glTexture3DImage      = mEGL->hasExtension("EGL_KHR_gl_texture_3D_image");
838     outExtensions->glRenderbufferImage   = mEGL->hasExtension("EGL_KHR_gl_renderbuffer_image");
839     outExtensions->pixelFormatFloat      = mEGL->hasExtension("EGL_EXT_pixel_format_float");
840 
841     outExtensions->glColorspace = mEGL->hasExtension("EGL_KHR_gl_colorspace");
842     if (outExtensions->glColorspace)
843     {
844         outExtensions->glColorspaceDisplayP3Linear =
845             mEGL->hasExtension("EGL_EXT_gl_colorspace_display_p3_linear");
846         outExtensions->glColorspaceDisplayP3 =
847             mEGL->hasExtension("EGL_EXT_gl_colorspace_display_p3");
848         outExtensions->glColorspaceScrgb = mEGL->hasExtension("EGL_EXT_gl_colorspace_scrgb");
849         outExtensions->glColorspaceScrgbLinear =
850             mEGL->hasExtension("EGL_EXT_gl_colorspace_scrgb_linear");
851         outExtensions->glColorspaceDisplayP3Passthrough =
852             mEGL->hasExtension("EGL_EXT_gl_colorspace_display_p3_passthrough");
853         outExtensions->imageGlColorspace = mEGL->hasExtension("EGL_EXT_image_gl_colorspace");
854     }
855 
856     outExtensions->imageNativeBuffer = mEGL->hasExtension("EGL_ANDROID_image_native_buffer");
857 
858     outExtensions->getFrameTimestamps = mEGL->hasExtension("EGL_ANDROID_get_frame_timestamps");
859 
860     outExtensions->fenceSync =
861         eglVersion >= gl::Version(1, 5) || mEGL->hasExtension("EGL_KHR_fence_sync");
862     outExtensions->waitSync =
863         eglVersion >= gl::Version(1, 5) || mEGL->hasExtension("EGL_KHR_wait_sync");
864 
865     outExtensions->getNativeClientBufferANDROID =
866         mEGL->hasExtension("EGL_ANDROID_get_native_client_buffer");
867 
868     outExtensions->createNativeClientBufferANDROID =
869         mEGL->hasExtension("EGL_ANDROID_create_native_client_buffer");
870 
871     outExtensions->nativeFenceSyncANDROID = mEGL->hasExtension("EGL_ANDROID_native_fence_sync");
872 
873     outExtensions->noConfigContext = mSupportsNoConfigContexts;
874 
875     outExtensions->surfacelessContext = mEGL->hasExtension("EGL_KHR_surfaceless_context");
876 
877     outExtensions->framebufferTargetANDROID = mEGL->hasExtension("EGL_ANDROID_framebuffer_target");
878 
879     outExtensions->imageDmaBufImportEXT = mEGL->hasExtension("EGL_EXT_image_dma_buf_import");
880 
881     outExtensions->imageDmaBufImportModifiersEXT =
882         mEGL->hasExtension("EGL_EXT_image_dma_buf_import_modifiers");
883 
884     outExtensions->robustnessVideoMemoryPurgeNV = mHasNVRobustnessVideoMemoryPurge;
885 
886     outExtensions->bufferAgeEXT = mEGL->hasExtension("EGL_EXT_buffer_age");
887 
888     // Surfaceless can be support if the native driver supports it or we know that we are running on
889     // a single thread (mVirtualizedContexts == true)
890     outExtensions->surfacelessContext = mSupportsSurfaceless;
891 
892     outExtensions->externalContextAndSurface = true;
893 
894     outExtensions->contextVirtualizationANGLE = true;
895 
896     DisplayGL::generateExtensions(outExtensions);
897 }
898 
generateCaps(egl::Caps * outCaps) const899 void DisplayEGL::generateCaps(egl::Caps *outCaps) const
900 {
901     outCaps->textureNPOT = true;  // Since we request GLES >= 2
902 }
903 
setBlobCacheFuncs(EGLSetBlobFuncANDROID set,EGLGetBlobFuncANDROID get)904 void DisplayEGL::setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get)
905 {
906     if (mEGL->hasExtension("EGL_ANDROID_blob_cache"))
907     {
908         mEGL->setBlobCacheFuncsANDROID(set, get);
909     }
910 }
911 
makeCurrentSurfaceless(gl::Context * context)912 egl::Error DisplayEGL::makeCurrentSurfaceless(gl::Context *context)
913 {
914     // Nothing to do because EGL always uses the same context and the previous surface can be left
915     // current.
916     return egl::NoError();
917 }
918 
createRenderer(EGLContext shareContext,bool makeNewContextCurrent,bool isExternalContext,std::shared_ptr<RendererEGL> * outRenderer)919 egl::Error DisplayEGL::createRenderer(EGLContext shareContext,
920                                       bool makeNewContextCurrent,
921                                       bool isExternalContext,
922                                       std::shared_ptr<RendererEGL> *outRenderer)
923 {
924     EGLContext context = EGL_NO_CONTEXT;
925     native_egl::AttributeVector attribs;
926 
927     // If isExternalContext is true, the external context is current, so we don't need to make the
928     // mMockPbuffer current.
929     if (isExternalContext)
930     {
931         ASSERT(shareContext == EGL_NO_CONTEXT);
932         ASSERT(!makeNewContextCurrent);
933         // TODO(penghuang): Should we consider creating a share context to avoid querying and
934         // restoring GL context state? http://anglebug.com/5509
935         context = mEGL->getCurrentContext();
936         ASSERT(context != EGL_NO_CONTEXT);
937         // TODO(penghuang): get the version from the current context. http://anglebug.com/5509
938         attribs = {EGL_CONTEXT_MAJOR_VERSION, 2, EGL_CONTEXT_MINOR_VERSION, 0, EGL_NONE};
939     }
940     else
941     {
942         ANGLE_TRY(initializeContext(shareContext, mDisplayAttributes, &context, &attribs));
943         if (mEGL->makeCurrent(mMockPbuffer, context) == EGL_FALSE)
944         {
945             return egl::EglNotInitialized()
946                    << "eglMakeCurrent failed with " << egl::Error(mEGL->getError());
947         }
948     }
949 
950     std::unique_ptr<FunctionsGL> functionsGL(mEGL->makeFunctionsGL());
951     functionsGL->initialize(mDisplayAttributes);
952 
953     outRenderer->reset(new RendererEGL(std::move(functionsGL), mDisplayAttributes, this, context,
954                                        attribs, isExternalContext));
955 
956     CurrentNativeContext &currentContext = mCurrentNativeContexts[std::this_thread::get_id()];
957     if (makeNewContextCurrent)
958     {
959         currentContext.surface = mMockPbuffer;
960         currentContext.context = context;
961     }
962     else if (!isExternalContext)
963     {
964         // Reset the current context back to the previous state
965         if (mEGL->makeCurrent(currentContext.surface, currentContext.context) == EGL_FALSE)
966         {
967             return egl::EglNotInitialized()
968                    << "eglMakeCurrent failed with " << egl::Error(mEGL->getError());
969         }
970     }
971 
972     return egl::NoError();
973 }
974 
createWorkerContext(std::string * infoLog,EGLContext sharedContext,const native_egl::AttributeVector workerAttribs)975 WorkerContext *DisplayEGL::createWorkerContext(std::string *infoLog,
976                                                EGLContext sharedContext,
977                                                const native_egl::AttributeVector workerAttribs)
978 {
979     EGLContext context = mEGL->createContext(mConfig, sharedContext, workerAttribs.data());
980     if (context == EGL_NO_CONTEXT)
981     {
982         *infoLog += "Unable to create the EGL context.";
983         return nullptr;
984     }
985     return new WorkerContextEGL(context, mEGL, EGL_NO_SURFACE);
986 }
987 
initializeFrontendFeatures(angle::FrontendFeatures * features) const988 void DisplayEGL::initializeFrontendFeatures(angle::FrontendFeatures *features) const
989 {
990     mRenderer->initializeFrontendFeatures(features);
991 }
992 
populateFeatureList(angle::FeatureList * features)993 void DisplayEGL::populateFeatureList(angle::FeatureList *features)
994 {
995     mRenderer->getFeatures().populateFeatureList(features);
996 }
997 
getRenderer() const998 RendererGL *DisplayEGL::getRenderer() const
999 {
1000     return mRenderer.get();
1001 }
1002 
validateImageClientBuffer(const gl::Context * context,EGLenum target,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const1003 egl::Error DisplayEGL::validateImageClientBuffer(const gl::Context *context,
1004                                                  EGLenum target,
1005                                                  EGLClientBuffer clientBuffer,
1006                                                  const egl::AttributeMap &attribs) const
1007 {
1008     switch (target)
1009     {
1010         case EGL_LINUX_DMA_BUF_EXT:
1011             return egl::NoError();
1012 
1013         default:
1014             return DisplayGL::validateImageClientBuffer(context, target, clientBuffer, attribs);
1015     }
1016 }
1017 
createExternalImageSibling(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const egl::AttributeMap & attribs)1018 ExternalImageSiblingImpl *DisplayEGL::createExternalImageSibling(const gl::Context *context,
1019                                                                  EGLenum target,
1020                                                                  EGLClientBuffer buffer,
1021                                                                  const egl::AttributeMap &attribs)
1022 {
1023     switch (target)
1024     {
1025         case EGL_LINUX_DMA_BUF_EXT:
1026             ASSERT(context == nullptr);
1027             ASSERT(buffer == nullptr);
1028             return new DmaBufImageSiblingEGL(attribs);
1029 
1030         default:
1031             return DisplayGL::createExternalImageSibling(context, target, buffer, attribs);
1032     }
1033 }
1034 
fixSurfaceType(EGLint surfaceType) const1035 EGLint DisplayEGL::fixSurfaceType(EGLint surfaceType) const
1036 {
1037     // Pixmaps are not supported on EGL, make sure the config doesn't expose them.
1038     return surfaceType & ~EGL_PIXMAP_BIT;
1039 }
1040 
getFunctionsEGL() const1041 const FunctionsEGL *DisplayEGL::getFunctionsEGL() const
1042 {
1043     return mEGL;
1044 }
1045 
1046 }  // namespace rx
1047