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 // FunctionsEGL.cpp: Implements the FunctionsEGL class.
8
9 #include "libANGLE/renderer/gl/egl/FunctionsEGL.h"
10
11 #include <algorithm>
12
13 #include "common/platform.h"
14 #include "common/string_utils.h"
15 #include "libANGLE/renderer/driver_utils.h"
16 #include "libANGLE/renderer/gl/FunctionsGL.h"
17 #include "libANGLE/renderer/gl/egl/functionsegl_typedefs.h"
18
19 #if defined(ANGLE_HAS_LIBDRM)
20 // clang-format off
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <xf86drm.h>
24 // clang-format on
25 #endif // defined(ANGLE_HAS_LIBDRM)
26
27 namespace
28 {
29
30 template <typename T>
SetPtr(T * dst,void * src)31 bool SetPtr(T *dst, void *src)
32 {
33 if (src)
34 {
35 *dst = reinterpret_cast<T>(src);
36 return true;
37 }
38 return false;
39 }
40
IsValidPlatformTypeForPlatformDisplayConnection(EGLAttrib platformType)41 bool IsValidPlatformTypeForPlatformDisplayConnection(EGLAttrib platformType)
42 {
43 switch (platformType)
44 {
45 case EGL_PLATFORM_SURFACELESS_MESA:
46 return true;
47 default:
48 break;
49 }
50 return false;
51 }
52
53 } // namespace
54
55 namespace rx
56 {
57
58 struct FunctionsEGL::EGLDispatchTable
59 {
EGLDispatchTablerx::FunctionsEGL::EGLDispatchTable60 EGLDispatchTable()
61 : bindAPIPtr(nullptr),
62 chooseConfigPtr(nullptr),
63 createContextPtr(nullptr),
64 createPbufferSurfacePtr(nullptr),
65 createWindowSurfacePtr(nullptr),
66 destroyContextPtr(nullptr),
67 destroySurfacePtr(nullptr),
68 getConfigAttribPtr(nullptr),
69 getConfigsPtr(nullptr),
70 getCurrentSurfacePtr(nullptr),
71 getDisplayPtr(nullptr),
72 getErrorPtr(nullptr),
73 initializePtr(nullptr),
74 makeCurrentPtr(nullptr),
75 queryStringPtr(nullptr),
76 querySurfacePtr(nullptr),
77 swapBuffersPtr(nullptr),
78 terminatePtr(nullptr),
79
80 bindTexImagePtr(nullptr),
81 releaseTexImagePtr(nullptr),
82 surfaceAttribPtr(nullptr),
83 swapIntervalPtr(nullptr),
84
85 getCurrentContextPtr(nullptr),
86
87 createImageKHRPtr(nullptr),
88 destroyImageKHRPtr(nullptr),
89
90 createSyncKHRPtr(nullptr),
91 destroySyncKHRPtr(nullptr),
92 clientWaitSyncKHRPtr(nullptr),
93 getSyncAttribKHRPtr(nullptr),
94
95 waitSyncKHRPtr(nullptr),
96
97 swapBuffersWithDamageKHRPtr(nullptr),
98
99 presentationTimeANDROIDPtr(nullptr),
100
101 setBlobCacheFuncsANDROIDPtr(nullptr),
102
103 getCompositorTimingSupportedANDROIDPtr(nullptr),
104 getCompositorTimingANDROIDPtr(nullptr),
105 getNextFrameIdANDROIDPtr(nullptr),
106 getFrameTimestampSupportedANDROIDPtr(nullptr),
107 getFrameTimestampsANDROIDPtr(nullptr),
108
109 dupNativeFenceFDANDROIDPtr(nullptr),
110
111 queryDmaBufFormatsEXTPtr(nullptr),
112 queryDmaBufModifiersEXTPtr(nullptr),
113
114 queryDeviceAttribEXTPtr(nullptr),
115 queryDeviceStringEXTPtr(nullptr),
116 queryDisplayAttribEXTPtr(nullptr)
117 {}
118
119 // 1.0
120 PFNEGLBINDAPIPROC bindAPIPtr;
121 PFNEGLCHOOSECONFIGPROC chooseConfigPtr;
122 PFNEGLCREATECONTEXTPROC createContextPtr;
123 PFNEGLCREATEPBUFFERSURFACEPROC createPbufferSurfacePtr;
124 PFNEGLCREATEWINDOWSURFACEPROC createWindowSurfacePtr;
125 PFNEGLDESTROYCONTEXTPROC destroyContextPtr;
126 PFNEGLDESTROYSURFACEPROC destroySurfacePtr;
127 PFNEGLGETCONFIGATTRIBPROC getConfigAttribPtr;
128 PFNEGLGETCONFIGSPROC getConfigsPtr;
129 PFNEGLGETCURRENTSURFACEPROC getCurrentSurfacePtr;
130 PFNEGLGETDISPLAYPROC getDisplayPtr;
131 PFNEGLGETERRORPROC getErrorPtr;
132 PFNEGLINITIALIZEPROC initializePtr;
133 PFNEGLMAKECURRENTPROC makeCurrentPtr;
134 PFNEGLQUERYSTRINGPROC queryStringPtr;
135 PFNEGLQUERYSURFACEPROC querySurfacePtr;
136 PFNEGLSWAPBUFFERSPROC swapBuffersPtr;
137 PFNEGLTERMINATEPROC terminatePtr;
138
139 // 1.1
140 PFNEGLBINDTEXIMAGEPROC bindTexImagePtr;
141 PFNEGLRELEASETEXIMAGEPROC releaseTexImagePtr;
142 PFNEGLSURFACEATTRIBPROC surfaceAttribPtr;
143 PFNEGLSWAPINTERVALPROC swapIntervalPtr;
144
145 // 1.4
146 PFNEGLGETCURRENTCONTEXTPROC getCurrentContextPtr;
147
148 // EGL_KHR_image
149 PFNEGLCREATEIMAGEKHRPROC createImageKHRPtr;
150 PFNEGLDESTROYIMAGEKHRPROC destroyImageKHRPtr;
151
152 // EGL_KHR_fence_sync
153 PFNEGLCREATESYNCKHRPROC createSyncKHRPtr;
154 PFNEGLDESTROYSYNCKHRPROC destroySyncKHRPtr;
155 PFNEGLCLIENTWAITSYNCKHRPROC clientWaitSyncKHRPtr;
156 PFNEGLGETSYNCATTRIBKHRPROC getSyncAttribKHRPtr;
157
158 // EGL_KHR_wait_sync
159 PFNEGLWAITSYNCKHRPROC waitSyncKHRPtr;
160
161 // EGL_KHR_swap_buffers_with_damage
162 PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC swapBuffersWithDamageKHRPtr;
163
164 // EGL_ANDROID_presentation_time
165 PFNEGLPRESENTATIONTIMEANDROIDPROC presentationTimeANDROIDPtr;
166
167 // EGL_ANDROID_blob_cache
168 PFNEGLSETBLOBCACHEFUNCSANDROIDPROC setBlobCacheFuncsANDROIDPtr;
169
170 // EGL_ANDROID_get_frame_timestamps
171 PFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROIDPROC getCompositorTimingSupportedANDROIDPtr;
172 PFNEGLGETCOMPOSITORTIMINGANDROIDPROC getCompositorTimingANDROIDPtr;
173 PFNEGLGETNEXTFRAMEIDANDROIDPROC getNextFrameIdANDROIDPtr;
174 PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROIDPROC getFrameTimestampSupportedANDROIDPtr;
175 PFNEGLGETFRAMETIMESTAMPSANDROIDPROC getFrameTimestampsANDROIDPtr;
176
177 // EGL_ANDROID_native_fence_sync
178 PFNEGLDUPNATIVEFENCEFDANDROIDPROC dupNativeFenceFDANDROIDPtr;
179
180 // EGL_EXT_image_dma_buf_import_modifiers
181 PFNEGLQUERYDMABUFFORMATSEXTPROC queryDmaBufFormatsEXTPtr;
182 PFNEGLQUERYDMABUFMODIFIERSEXTPROC queryDmaBufModifiersEXTPtr;
183
184 // EGL_EXT_device_query
185 PFNEGLQUERYDEVICEATTRIBEXTPROC queryDeviceAttribEXTPtr;
186 PFNEGLQUERYDEVICESTRINGEXTPROC queryDeviceStringEXTPtr;
187 PFNEGLQUERYDISPLAYATTRIBEXTPROC queryDisplayAttribEXTPtr;
188 };
189
FunctionsEGL()190 FunctionsEGL::FunctionsEGL()
191 : majorVersion(0), minorVersion(0), mFnPtrs(new EGLDispatchTable()), mEGLDisplay(EGL_NO_DISPLAY)
192 {}
193
~FunctionsEGL()194 FunctionsEGL::~FunctionsEGL()
195 {
196 SafeDelete(mFnPtrs);
197 }
198
initialize(EGLAttrib platformType,EGLNativeDisplayType nativeDisplay)199 egl::Error FunctionsEGL::initialize(EGLAttrib platformType, EGLNativeDisplayType nativeDisplay)
200 {
201 #define ANGLE_GET_PROC_OR_WARNING(MEMBER, NAME) \
202 do \
203 { \
204 if (!SetPtr(MEMBER, getProcAddress(#NAME))) \
205 { \
206 WARN() << "Could not load EGL entry point " #NAME; \
207 } \
208 } while (0)
209 #define ANGLE_GET_PROC_OR_ERROR(MEMBER, NAME) \
210 do \
211 { \
212 if (!SetPtr(MEMBER, getProcAddress(#NAME))) \
213 { \
214 return egl::EglNotInitialized() << "Could not load EGL entry point " #NAME; \
215 } \
216 } while (0)
217
218 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->bindAPIPtr, eglBindAPI);
219 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->chooseConfigPtr, eglChooseConfig);
220 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createContextPtr, eglCreateContext);
221 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createPbufferSurfacePtr, eglCreatePbufferSurface);
222 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createWindowSurfacePtr, eglCreateWindowSurface);
223 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroyContextPtr, eglDestroyContext);
224 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroySurfacePtr, eglDestroySurface);
225 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getConfigAttribPtr, eglGetConfigAttrib);
226 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getConfigsPtr, eglGetConfigs);
227 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getCurrentSurfacePtr, eglGetCurrentSurface);
228 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getDisplayPtr, eglGetDisplay);
229 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getErrorPtr, eglGetError);
230 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->initializePtr, eglInitialize);
231 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->makeCurrentPtr, eglMakeCurrent);
232 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->queryStringPtr, eglQueryString);
233 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->querySurfacePtr, eglQuerySurface);
234 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->swapBuffersPtr, eglSwapBuffers);
235 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->terminatePtr, eglTerminate);
236
237 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->bindTexImagePtr, eglBindTexImage);
238 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->releaseTexImagePtr, eglReleaseTexImage);
239 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->surfaceAttribPtr, eglSurfaceAttrib);
240 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalPtr, eglSwapInterval);
241
242 // Querying EGL_EXTENSIONS string and loading it into the mExtensions
243 // vector will at this point retrieve the client extensions since mEGLDisplay is still
244 // EGL_NO_DISPLAY. This is desired, and mExtensions will later be reinitialized with the display
245 // extensions once the display is created and initialized.
246 queryExtensions();
247
248 #if defined(ANGLE_HAS_LIBDRM)
249 mEGLDisplay = getPreferredDisplay(&majorVersion, &minorVersion);
250 #endif // defined(ANGLE_HAS_LIBDRM)
251
252 if (mEGLDisplay == EGL_NO_DISPLAY)
253 {
254 if (IsValidPlatformTypeForPlatformDisplayConnection(platformType))
255 {
256 mEGLDisplay = getPlatformDisplay(platformType, nativeDisplay);
257 }
258 else
259 {
260 mEGLDisplay = mFnPtrs->getDisplayPtr(nativeDisplay);
261 }
262 }
263
264 if (mEGLDisplay != EGL_NO_DISPLAY &&
265 mFnPtrs->initializePtr(mEGLDisplay, &majorVersion, &minorVersion) != EGL_TRUE)
266 {
267 mEGLDisplay = EGL_NO_DISPLAY;
268 }
269 if (mEGLDisplay == EGL_NO_DISPLAY)
270 {
271 // If no display was available, try to fallback to the first available
272 // native device object's display.
273 mEGLDisplay = getNativeDisplay(&majorVersion, &minorVersion);
274 }
275 if (mEGLDisplay == EGL_NO_DISPLAY)
276 {
277 return egl::EglNotInitialized() << "Failed to get system egl display";
278 }
279 if (majorVersion < 1 || (majorVersion == 1 && minorVersion < 4))
280 {
281 return egl::EglNotInitialized() << "Unsupported EGL version (require at least 1.4).";
282 }
283 if (mFnPtrs->bindAPIPtr(EGL_OPENGL_ES_API) != EGL_TRUE)
284 {
285 return egl::Error(mFnPtrs->getErrorPtr(), "Failed to bind API in system egl");
286 }
287
288 vendorString = queryString(EGL_VENDOR);
289 versionString = queryString(EGL_VERSION);
290
291 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getCurrentContextPtr, eglGetCurrentContext);
292
293 if (!queryExtensions())
294 {
295 return egl::Error(mFnPtrs->getErrorPtr(), "Failed to query extensions in system egl");
296 }
297
298 if (hasExtension("EGL_KHR_image_base"))
299 {
300 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createImageKHRPtr, eglCreateImageKHR);
301 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroyImageKHRPtr, eglDestroyImageKHR);
302 }
303 if (hasExtension("EGL_KHR_fence_sync"))
304 {
305 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createSyncKHRPtr, eglCreateSyncKHR);
306 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroySyncKHRPtr, eglDestroySyncKHR);
307 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->clientWaitSyncKHRPtr, eglClientWaitSyncKHR);
308 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getSyncAttribKHRPtr, eglGetSyncAttribKHR);
309 }
310 if (hasExtension("EGL_KHR_wait_sync"))
311 {
312 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->waitSyncKHRPtr, eglWaitSyncKHR);
313 }
314
315 if (hasExtension("EGL_KHR_swap_buffers_with_damage"))
316 {
317 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->swapBuffersWithDamageKHRPtr, eglSwapBuffersWithDamageKHR);
318 }
319
320 if (hasExtension("EGL_ANDROID_presentation_time"))
321 {
322 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->presentationTimeANDROIDPtr, eglPresentationTimeANDROID);
323 }
324
325 if (hasExtension("EGL_ANDROID_blob_cache"))
326 {
327 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->setBlobCacheFuncsANDROIDPtr, eglSetBlobCacheFuncsANDROID);
328 }
329
330 if (hasExtension("EGL_ANDROID_get_frame_timestamps"))
331 {
332 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getCompositorTimingSupportedANDROIDPtr,
333 eglGetCompositorTimingSupportedANDROID);
334 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getCompositorTimingANDROIDPtr,
335 eglGetCompositorTimingANDROID);
336 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getNextFrameIdANDROIDPtr, eglGetNextFrameIdANDROID);
337 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getFrameTimestampSupportedANDROIDPtr,
338 eglGetFrameTimestampSupportedANDROID);
339 ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getFrameTimestampsANDROIDPtr,
340 eglGetFrameTimestampsANDROID);
341 }
342
343 // The native fence sync extension is a bit complicated. It's reported as present for ChromeOS,
344 // but Android currently doesn't report this extension even when it's present, and older devices
345 // may export a useless wrapper function. See crbug.com/775707 for details. In short, if the
346 // symbol is present and we're on Android N or newer, assume that it's usable even if the
347 // extension wasn't reported.
348 if (hasExtension("EGL_ANDROID_native_fence_sync") || GetAndroidSDKVersion() >= 24)
349 {
350 // Don't error trying to load this entry point.
351 if (SetPtr(&mFnPtrs->dupNativeFenceFDANDROIDPtr,
352 getProcAddress("eglDupNativeFenceFDANDROID")) &&
353 !hasExtension("EGL_ANDROID_native_fence_sync"))
354 {
355 mExtensions.push_back("EGL_ANDROID_native_fence_sync");
356 }
357 }
358
359 if (hasExtension("EGL_EXT_image_dma_buf_import_modifiers"))
360 {
361 // https://anglebug.com/42266130
362 // Some drivers, notably older versions of ANGLE, announce this extension without
363 // implementing the following functions. DisplayEGL checks for this case and disables the
364 // extension.
365 ANGLE_GET_PROC_OR_WARNING(&mFnPtrs->queryDmaBufFormatsEXTPtr, eglQueryDmaBufFormatsEXT);
366 ANGLE_GET_PROC_OR_WARNING(&mFnPtrs->queryDmaBufModifiersEXTPtr, eglQueryDmaBufModifiersEXT);
367 }
368
369 // EGL_EXT_device_query is only advertised in extension string in the
370 // no-display case, see getNativeDisplay().
371 if (SetPtr(&mFnPtrs->queryDeviceAttribEXTPtr, getProcAddress("eglQueryDeviceAttribEXT")) &&
372 SetPtr(&mFnPtrs->queryDeviceStringEXTPtr, getProcAddress("eglQueryDeviceStringEXT")) &&
373 SetPtr(&mFnPtrs->queryDisplayAttribEXTPtr, getProcAddress("eglQueryDisplayAttribEXT")))
374 {
375 mExtensions.push_back("EGL_EXT_device_query");
376 }
377
378 #undef ANGLE_GET_PROC_OR_ERROR
379
380 return egl::NoError();
381 }
382
terminate()383 egl::Error FunctionsEGL::terminate()
384 {
385 if (mFnPtrs->terminatePtr == nullptr || mFnPtrs->terminatePtr(mEGLDisplay) == EGL_TRUE)
386 {
387 mEGLDisplay = nullptr;
388 return egl::NoError();
389 }
390 return egl::Error(mFnPtrs->getErrorPtr());
391 }
392
queryExtensions()393 bool FunctionsEGL::queryExtensions()
394 {
395 const char *extensions = queryString(EGL_EXTENSIONS);
396 if (!extensions)
397 {
398 return false;
399 }
400
401 angle::SplitStringAlongWhitespace(extensions, &mExtensions);
402
403 return true;
404 }
405
getPlatformDisplay(EGLAttrib platformType,EGLNativeDisplayType nativeDisplay)406 EGLDisplay FunctionsEGL::getPlatformDisplay(EGLAttrib platformType,
407 EGLNativeDisplayType nativeDisplay)
408 {
409 PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXTPtr;
410 if (!hasExtension("EGL_EXT_platform_base") ||
411 !SetPtr(&getPlatformDisplayEXTPtr, getProcAddress("eglGetPlatformDisplayEXT")))
412 {
413 return EGL_NO_DISPLAY;
414 }
415
416 ASSERT(IsValidPlatformTypeForPlatformDisplayConnection(platformType));
417 switch (platformType)
418 {
419 case EGL_PLATFORM_SURFACELESS_MESA:
420 if (!hasExtension("EGL_MESA_platform_surfaceless"))
421 return EGL_NO_DISPLAY;
422 break;
423 default:
424 UNREACHABLE();
425 return EGL_NO_DISPLAY;
426 }
427
428 return getPlatformDisplayEXTPtr(static_cast<EGLenum>(platformType),
429 reinterpret_cast<void *>(nativeDisplay), nullptr);
430 }
431
queryDevices(int * major,int * minor)432 std::vector<EGLDeviceEXT> FunctionsEGL::queryDevices(int *major, int *minor)
433 {
434 // Only called after confirming we have the necessary extension.
435 PFNEGLQUERYDEVICESEXTPROC queryDevicesEXTPtr;
436 if (!SetPtr(&queryDevicesEXTPtr, getProcAddress("eglQueryDevicesEXT")))
437 {
438 return {};
439 }
440
441 // Get a list of native device objects.
442 const EGLint kMaxDevices = 32;
443 EGLint numDevices = 0;
444 std::vector<EGLDeviceEXT> devices(kMaxDevices, EGL_NO_DEVICE_EXT);
445 if (!queryDevicesEXTPtr(kMaxDevices, devices.data(), &numDevices))
446 {
447 return {};
448 }
449
450 devices.resize(numDevices);
451 return devices;
452 }
453
getNativeDisplay(int * major,int * minor)454 EGLDisplay FunctionsEGL::getNativeDisplay(int *major, int *minor)
455 {
456 // This fallback mechanism makes use of:
457 // - EGL_EXT_device_enumeration or EGL_EXT_device_base for eglQueryDevicesEXT
458 // - EGL_EXT_platform_base for eglGetPlatformDisplayEXT
459 // - EGL_EXT_platform_device for EGL_PLATFORM_DEVICE_EXT
460 PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXTPtr;
461 bool hasQueryDevicesEXT =
462 hasExtension("EGL_EXT_device_enumeration") || hasExtension("EGL_EXT_device_base");
463 bool hasPlatformBaseEXT = hasExtension("EGL_EXT_platform_base");
464 bool hasPlatformDeviceEXT = hasExtension("EGL_EXT_platform_device");
465 if (!hasQueryDevicesEXT || !hasPlatformBaseEXT || !hasPlatformDeviceEXT)
466 {
467 return EGL_NO_DISPLAY;
468 }
469
470 if (!SetPtr(&getPlatformDisplayEXTPtr, getProcAddress("eglGetPlatformDisplayEXT")))
471 {
472 return EGL_NO_DISPLAY;
473 }
474
475 std::vector<EGLDeviceEXT> devices = queryDevices(major, minor);
476 if (devices.size() == 0)
477 {
478 return EGL_NO_DISPLAY;
479 }
480
481 // Look for the first native device that gives us a valid display.
482 for (const EGLDeviceEXT device : devices)
483 {
484 EGLDisplay display = getPlatformDisplayEXTPtr(EGL_PLATFORM_DEVICE_EXT, device, nullptr);
485 if (mFnPtrs->getErrorPtr() == EGL_SUCCESS &&
486 mFnPtrs->initializePtr(display, major, minor) == EGL_TRUE)
487 {
488 return display;
489 }
490 }
491
492 return EGL_NO_DISPLAY;
493 }
494
495 #if defined(ANGLE_HAS_LIBDRM)
getPreferredEGLDevice(const std::vector<EGLDeviceEXT> & devices)496 EGLDeviceEXT FunctionsEGL::getPreferredEGLDevice(const std::vector<EGLDeviceEXT> &devices)
497 {
498 // Only called after confirming we have the necessary extension.
499 PFNEGLQUERYDEVICESTRINGEXTPROC queryDeviceStringEXTPtr;
500 if (!SetPtr(&queryDeviceStringEXTPtr, getProcAddress("eglQueryDeviceStringEXT")))
501 {
502 return EGL_NO_DEVICE_EXT;
503 }
504
505 std::map<EGLDeviceEXT, std::string> device_drivers;
506 for (const EGLDeviceEXT device : devices)
507 {
508 const char *filename = queryDeviceStringEXTPtr(device, EGL_DRM_DEVICE_FILE_EXT);
509 if (!filename)
510 {
511 continue;
512 }
513
514 int fd = open(filename, O_RDWR);
515 if (!fd)
516 {
517 continue;
518 }
519
520 drmVersionPtr version = drmGetVersion(fd);
521 if (version)
522 {
523 const std::string driver_name(version->name, version->name_len);
524 device_drivers.insert({device, driver_name});
525 }
526
527 drmFreeVersion(version);
528 close(fd);
529 }
530
531 const char *preferred_drivers[3] = {"i915", "amdgpu", "virtio_gpu"};
532 for (const char *preferred_driver : preferred_drivers)
533 {
534 for (const EGLDeviceEXT device : devices)
535 {
536 const auto driver = device_drivers.find(device);
537 if (driver != device_drivers.end() && driver->second == preferred_driver)
538 {
539 return device;
540 }
541 }
542 }
543
544 return EGL_NO_DEVICE_EXT;
545 }
546
getPreferredDisplay(int * major,int * minor)547 EGLDisplay FunctionsEGL::getPreferredDisplay(int *major, int *minor)
548 {
549 // This mechanism makes use of:
550 // - EGL_EXT_device_enumeration or EGL_EXT_device_base for eglQueryDevicesEXT
551 // - EGL_EXT_platform_base for eglGetPlatformDisplayEXT
552 // - EGL_EXT_platform_device for EGL_PLATFORM_DEVICE_EXT
553 // - EGL_EXT_device_query for eglQueryDeviceStringEXT
554 PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXTPtr;
555 bool hasQueryDevicesEXT =
556 hasExtension("EGL_EXT_device_enumeration") || hasExtension("EGL_EXT_device_base");
557 bool hasPlatformBaseEXT = hasExtension("EGL_EXT_platform_base");
558 bool hasPlatformDeviceEXT = hasExtension("EGL_EXT_platform_device");
559 bool hasDeviceQueryEXT = hasExtension("EGL_EXT_device_query");
560 if (!hasQueryDevicesEXT || !hasPlatformBaseEXT || !hasPlatformDeviceEXT || !hasDeviceQueryEXT)
561 {
562 return EGL_NO_DISPLAY;
563 }
564
565 if (!SetPtr(&getPlatformDisplayEXTPtr, getProcAddress("eglGetPlatformDisplayEXT")))
566 {
567 return EGL_NO_DISPLAY;
568 }
569
570 std::vector<EGLDeviceEXT> devices = queryDevices(major, minor);
571 if (devices.size() == 0)
572 {
573 return EGL_NO_DISPLAY;
574 }
575
576 EGLDeviceEXT device = getPreferredEGLDevice(devices);
577 if (device == EGL_NO_DEVICE_EXT)
578 {
579 return EGL_NO_DISPLAY;
580 }
581
582 EGLDisplay display = getPlatformDisplayEXTPtr(EGL_PLATFORM_DEVICE_EXT, device, nullptr);
583 if (mFnPtrs->getErrorPtr() == EGL_SUCCESS)
584 {
585 return display;
586 }
587
588 return EGL_NO_DISPLAY;
589 }
590 #endif // defined(ANGLE_HAS_LIBDRM)
591
592 class FunctionsGLEGL : public FunctionsGL
593 {
594 public:
FunctionsGLEGL(const FunctionsEGL & egl)595 FunctionsGLEGL(const FunctionsEGL &egl) : mEGL(egl) {}
596
~FunctionsGLEGL()597 ~FunctionsGLEGL() override {}
598
599 private:
loadProcAddress(const std::string & function) const600 void *loadProcAddress(const std::string &function) const override
601 {
602 return mEGL.getProcAddress(function.c_str());
603 }
604
605 const FunctionsEGL &mEGL;
606 };
607
makeFunctionsGL(void) const608 FunctionsGL *FunctionsEGL::makeFunctionsGL(void) const
609 {
610 return new FunctionsGLEGL(*this);
611 }
612
hasExtension(const char * extension) const613 bool FunctionsEGL::hasExtension(const char *extension) const
614 {
615 return std::find(mExtensions.begin(), mExtensions.end(), extension) != mExtensions.end();
616 }
617
hasDmaBufImportModifierFunctions() const618 bool FunctionsEGL::hasDmaBufImportModifierFunctions() const
619 {
620 return mFnPtrs->queryDmaBufFormatsEXTPtr != nullptr &&
621 mFnPtrs->queryDmaBufModifiersEXTPtr != nullptr;
622 }
623
getDisplay() const624 EGLDisplay FunctionsEGL::getDisplay() const
625 {
626 return mEGLDisplay;
627 }
628
getError() const629 EGLint FunctionsEGL::getError() const
630 {
631 return mFnPtrs->getErrorPtr();
632 }
633
chooseConfig(EGLint const * attribList,EGLConfig * configs,EGLint configSize,EGLint * numConfig) const634 EGLBoolean FunctionsEGL::chooseConfig(EGLint const *attribList,
635 EGLConfig *configs,
636 EGLint configSize,
637 EGLint *numConfig) const
638 {
639 return mFnPtrs->chooseConfigPtr(mEGLDisplay, attribList, configs, configSize, numConfig);
640 }
641
getConfigs(EGLConfig * configs,EGLint config_size,EGLint * num_config) const642 EGLBoolean FunctionsEGL::getConfigs(EGLConfig *configs,
643 EGLint config_size,
644 EGLint *num_config) const
645 {
646 return mFnPtrs->getConfigsPtr(mEGLDisplay, configs, config_size, num_config);
647 }
648
getConfigAttrib(EGLConfig config,EGLint attribute,EGLint * value) const649 EGLBoolean FunctionsEGL::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) const
650 {
651 return mFnPtrs->getConfigAttribPtr(mEGLDisplay, config, attribute, value);
652 }
653
getCurrentSurface(EGLint readdraw) const654 EGLSurface FunctionsEGL::getCurrentSurface(EGLint readdraw) const
655 {
656 return mFnPtrs->getCurrentSurfacePtr(readdraw);
657 }
658
createContext(EGLConfig config,EGLContext share_context,EGLint const * attrib_list) const659 EGLContext FunctionsEGL::createContext(EGLConfig config,
660 EGLContext share_context,
661 EGLint const *attrib_list) const
662 {
663 return mFnPtrs->createContextPtr(mEGLDisplay, config, share_context, attrib_list);
664 }
665
createPbufferSurface(EGLConfig config,const EGLint * attrib_list) const666 EGLSurface FunctionsEGL::createPbufferSurface(EGLConfig config, const EGLint *attrib_list) const
667 {
668 return mFnPtrs->createPbufferSurfacePtr(mEGLDisplay, config, attrib_list);
669 }
670
createWindowSurface(EGLConfig config,EGLNativeWindowType win,const EGLint * attrib_list) const671 EGLSurface FunctionsEGL::createWindowSurface(EGLConfig config,
672 EGLNativeWindowType win,
673 const EGLint *attrib_list) const
674 {
675 return mFnPtrs->createWindowSurfacePtr(mEGLDisplay, config, win, attrib_list);
676 }
677
destroyContext(EGLContext context) const678 EGLBoolean FunctionsEGL::destroyContext(EGLContext context) const
679 {
680 return mFnPtrs->destroyContextPtr(mEGLDisplay, context);
681 }
682
destroySurface(EGLSurface surface) const683 EGLBoolean FunctionsEGL::destroySurface(EGLSurface surface) const
684 {
685 return mFnPtrs->destroySurfacePtr(mEGLDisplay, surface);
686 }
687
makeCurrent(EGLSurface surface,EGLContext context) const688 EGLBoolean FunctionsEGL::makeCurrent(EGLSurface surface, EGLContext context) const
689 {
690 return mFnPtrs->makeCurrentPtr(mEGLDisplay, surface, surface, context);
691 }
692
queryString(EGLint name) const693 char const *FunctionsEGL::queryString(EGLint name) const
694 {
695 return mFnPtrs->queryStringPtr(mEGLDisplay, name);
696 }
697
querySurface(EGLSurface surface,EGLint attribute,EGLint * value) const698 EGLBoolean FunctionsEGL::querySurface(EGLSurface surface, EGLint attribute, EGLint *value) const
699 {
700 return mFnPtrs->querySurfacePtr(mEGLDisplay, surface, attribute, value);
701 }
702
swapBuffers(EGLSurface surface) const703 EGLBoolean FunctionsEGL::swapBuffers(EGLSurface surface) const
704 {
705 return mFnPtrs->swapBuffersPtr(mEGLDisplay, surface);
706 }
707
bindTexImage(EGLSurface surface,EGLint buffer) const708 EGLBoolean FunctionsEGL::bindTexImage(EGLSurface surface, EGLint buffer) const
709 {
710 return mFnPtrs->bindTexImagePtr(mEGLDisplay, surface, buffer);
711 }
712
releaseTexImage(EGLSurface surface,EGLint buffer) const713 EGLBoolean FunctionsEGL::releaseTexImage(EGLSurface surface, EGLint buffer) const
714 {
715 return mFnPtrs->releaseTexImagePtr(mEGLDisplay, surface, buffer);
716 }
717
surfaceAttrib(EGLSurface surface,EGLint attribute,EGLint value) const718 EGLBoolean FunctionsEGL::surfaceAttrib(EGLSurface surface, EGLint attribute, EGLint value) const
719 {
720 return mFnPtrs->surfaceAttribPtr(mEGLDisplay, surface, attribute, value);
721 }
722
swapInterval(EGLint interval) const723 EGLBoolean FunctionsEGL::swapInterval(EGLint interval) const
724 {
725 return mFnPtrs->swapIntervalPtr(mEGLDisplay, interval);
726 }
727
getCurrentContext() const728 EGLContext FunctionsEGL::getCurrentContext() const
729 {
730 return mFnPtrs->getCurrentContextPtr();
731 }
732
createImageKHR(EGLContext context,EGLenum target,EGLClientBuffer buffer,const EGLint * attrib_list) const733 EGLImageKHR FunctionsEGL::createImageKHR(EGLContext context,
734 EGLenum target,
735 EGLClientBuffer buffer,
736 const EGLint *attrib_list) const
737 {
738 return mFnPtrs->createImageKHRPtr(mEGLDisplay, context, target, buffer, attrib_list);
739 }
740
destroyImageKHR(EGLImageKHR image) const741 EGLBoolean FunctionsEGL::destroyImageKHR(EGLImageKHR image) const
742 {
743 return mFnPtrs->destroyImageKHRPtr(mEGLDisplay, image);
744 }
745
createSyncKHR(EGLenum type,const EGLint * attrib_list) const746 EGLSyncKHR FunctionsEGL::createSyncKHR(EGLenum type, const EGLint *attrib_list) const
747 {
748 return mFnPtrs->createSyncKHRPtr(mEGLDisplay, type, attrib_list);
749 }
750
destroySyncKHR(EGLSyncKHR sync) const751 EGLBoolean FunctionsEGL::destroySyncKHR(EGLSyncKHR sync) const
752 {
753 return mFnPtrs->destroySyncKHRPtr(mEGLDisplay, sync);
754 }
755
clientWaitSyncKHR(EGLSyncKHR sync,EGLint flags,EGLTimeKHR timeout) const756 EGLint FunctionsEGL::clientWaitSyncKHR(EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) const
757 {
758 return mFnPtrs->clientWaitSyncKHRPtr(mEGLDisplay, sync, flags, timeout);
759 }
760
getSyncAttribKHR(EGLSyncKHR sync,EGLint attribute,EGLint * value) const761 EGLBoolean FunctionsEGL::getSyncAttribKHR(EGLSyncKHR sync, EGLint attribute, EGLint *value) const
762 {
763 return mFnPtrs->getSyncAttribKHRPtr(mEGLDisplay, sync, attribute, value);
764 }
765
waitSyncKHR(EGLSyncKHR sync,EGLint flags) const766 EGLint FunctionsEGL::waitSyncKHR(EGLSyncKHR sync, EGLint flags) const
767 {
768 return mFnPtrs->waitSyncKHRPtr(mEGLDisplay, sync, flags);
769 }
770
swapBuffersWithDamageKHR(EGLSurface surface,const EGLint * rects,EGLint n_rects) const771 EGLBoolean FunctionsEGL::swapBuffersWithDamageKHR(EGLSurface surface,
772 const EGLint *rects,
773 EGLint n_rects) const
774 {
775 return mFnPtrs->swapBuffersWithDamageKHRPtr(mEGLDisplay, surface, rects, n_rects);
776 }
777
presentationTimeANDROID(EGLSurface surface,EGLnsecsANDROID time) const778 EGLBoolean FunctionsEGL::presentationTimeANDROID(EGLSurface surface, EGLnsecsANDROID time) const
779 {
780 return mFnPtrs->presentationTimeANDROIDPtr(mEGLDisplay, surface, time);
781 }
782
setBlobCacheFuncsANDROID(EGLSetBlobFuncANDROID set,EGLGetBlobFuncANDROID get) const783 void FunctionsEGL::setBlobCacheFuncsANDROID(EGLSetBlobFuncANDROID set,
784 EGLGetBlobFuncANDROID get) const
785 {
786 return mFnPtrs->setBlobCacheFuncsANDROIDPtr(mEGLDisplay, set, get);
787 }
788
getCompositorTimingSupportedANDROID(EGLSurface surface,EGLint name) const789 EGLBoolean FunctionsEGL::getCompositorTimingSupportedANDROID(EGLSurface surface, EGLint name) const
790 {
791 return mFnPtrs->getCompositorTimingSupportedANDROIDPtr(mEGLDisplay, surface, name);
792 }
793
getCompositorTimingANDROID(EGLSurface surface,EGLint numTimestamps,const EGLint * names,EGLnsecsANDROID * values) const794 EGLBoolean FunctionsEGL::getCompositorTimingANDROID(EGLSurface surface,
795 EGLint numTimestamps,
796 const EGLint *names,
797 EGLnsecsANDROID *values) const
798 {
799 return mFnPtrs->getCompositorTimingANDROIDPtr(mEGLDisplay, surface, numTimestamps, names,
800 values);
801 }
802
getNextFrameIdANDROID(EGLSurface surface,EGLuint64KHR * frameId) const803 EGLBoolean FunctionsEGL::getNextFrameIdANDROID(EGLSurface surface, EGLuint64KHR *frameId) const
804 {
805 return mFnPtrs->getNextFrameIdANDROIDPtr(mEGLDisplay, surface, frameId);
806 }
807
getFrameTimestampSupportedANDROID(EGLSurface surface,EGLint timestamp) const808 EGLBoolean FunctionsEGL::getFrameTimestampSupportedANDROID(EGLSurface surface,
809 EGLint timestamp) const
810 {
811 return mFnPtrs->getFrameTimestampSupportedANDROIDPtr(mEGLDisplay, surface, timestamp);
812 }
813
getFrameTimestampsANDROID(EGLSurface surface,EGLuint64KHR frameId,EGLint numTimestamps,const EGLint * timestamps,EGLnsecsANDROID * values) const814 EGLBoolean FunctionsEGL::getFrameTimestampsANDROID(EGLSurface surface,
815 EGLuint64KHR frameId,
816 EGLint numTimestamps,
817 const EGLint *timestamps,
818 EGLnsecsANDROID *values) const
819 {
820 return mFnPtrs->getFrameTimestampsANDROIDPtr(mEGLDisplay, surface, frameId, numTimestamps,
821 timestamps, values);
822 }
823
dupNativeFenceFDANDROID(EGLSync sync) const824 EGLint FunctionsEGL::dupNativeFenceFDANDROID(EGLSync sync) const
825 {
826 return mFnPtrs->dupNativeFenceFDANDROIDPtr(mEGLDisplay, sync);
827 }
828
queryDmaBufFormatsEXT(EGLint maxFormats,EGLint * formats,EGLint * numFormats) const829 EGLint FunctionsEGL::queryDmaBufFormatsEXT(EGLint maxFormats,
830 EGLint *formats,
831 EGLint *numFormats) const
832 {
833 return mFnPtrs->queryDmaBufFormatsEXTPtr(mEGLDisplay, maxFormats, formats, numFormats);
834 }
835
queryDmaBufModifiersEXT(EGLint format,EGLint maxModifiers,EGLuint64KHR * modifiers,EGLBoolean * externalOnly,EGLint * numModifiers) const836 EGLint FunctionsEGL::queryDmaBufModifiersEXT(EGLint format,
837 EGLint maxModifiers,
838 EGLuint64KHR *modifiers,
839 EGLBoolean *externalOnly,
840 EGLint *numModifiers) const
841 {
842 return mFnPtrs->queryDmaBufModifiersEXTPtr(mEGLDisplay, format, maxModifiers, modifiers,
843 externalOnly, numModifiers);
844 }
845
queryDeviceAttribEXT(EGLDeviceEXT device,EGLint attribute,EGLAttrib * value) const846 EGLBoolean FunctionsEGL::queryDeviceAttribEXT(EGLDeviceEXT device,
847 EGLint attribute,
848 EGLAttrib *value) const
849 {
850 return mFnPtrs->queryDeviceAttribEXTPtr(device, attribute, value);
851 }
852
queryDeviceStringEXT(EGLDeviceEXT device,EGLint name) const853 const char *FunctionsEGL::queryDeviceStringEXT(EGLDeviceEXT device, EGLint name) const
854 {
855 return mFnPtrs->queryDeviceStringEXTPtr(device, name);
856 }
857
queryDisplayAttribEXT(EGLint attribute,EGLAttrib * value) const858 EGLBoolean FunctionsEGL::queryDisplayAttribEXT(EGLint attribute, EGLAttrib *value) const
859 {
860 return mFnPtrs->queryDisplayAttribEXTPtr(mEGLDisplay, attribute, value);
861 }
862
863 } // namespace rx
864