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 ¤tContext = 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 ¤tContext : 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 ¤tContext = 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