xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/gl/egl/FunctionsEGL.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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