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