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