blob: cb52de22fb783d4bf0a68881487ddb5536009a1f [file] [log] [blame]
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// FunctionsEGL.cpp: Implements the FunctionsEGL class.
#include "libANGLE/renderer/gl/egl/FunctionsEGL.h"
#include <algorithm>
#include "common/platform.h"
#include "common/string_utils.h"
#include "libANGLE/renderer/driver_utils.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/egl/functionsegl_typedefs.h"
#if defined(ANGLE_HAS_LIBDRM)
// clang-format off
#include <fcntl.h>
#include <unistd.h>
#include <xf86drm.h>
// clang-format on
#endif // defined(ANGLE_HAS_LIBDRM)
namespace
{
template <typename T>
bool SetPtr(T *dst, void *src)
{
if (src)
{
*dst = reinterpret_cast<T>(src);
return true;
}
return false;
}
bool IsValidPlatformTypeForPlatformDisplayConnection(EGLAttrib platformType)
{
switch (platformType)
{
case EGL_PLATFORM_SURFACELESS_MESA:
return true;
default:
break;
}
return false;
}
} // namespace
namespace rx
{
struct FunctionsEGL::EGLDispatchTable
{
EGLDispatchTable()
: bindAPIPtr(nullptr),
chooseConfigPtr(nullptr),
createContextPtr(nullptr),
createPbufferSurfacePtr(nullptr),
createWindowSurfacePtr(nullptr),
destroyContextPtr(nullptr),
destroySurfacePtr(nullptr),
getConfigAttribPtr(nullptr),
getConfigsPtr(nullptr),
getCurrentSurfacePtr(nullptr),
getDisplayPtr(nullptr),
getErrorPtr(nullptr),
initializePtr(nullptr),
makeCurrentPtr(nullptr),
queryStringPtr(nullptr),
querySurfacePtr(nullptr),
swapBuffersPtr(nullptr),
terminatePtr(nullptr),
bindTexImagePtr(nullptr),
releaseTexImagePtr(nullptr),
surfaceAttribPtr(nullptr),
swapIntervalPtr(nullptr),
getCurrentContextPtr(nullptr),
createImageKHRPtr(nullptr),
destroyImageKHRPtr(nullptr),
createSyncKHRPtr(nullptr),
destroySyncKHRPtr(nullptr),
clientWaitSyncKHRPtr(nullptr),
getSyncAttribKHRPtr(nullptr),
waitSyncKHRPtr(nullptr),
swapBuffersWithDamageKHRPtr(nullptr),
presentationTimeANDROIDPtr(nullptr),
setBlobCacheFuncsANDROIDPtr(nullptr),
getCompositorTimingSupportedANDROIDPtr(nullptr),
getCompositorTimingANDROIDPtr(nullptr),
getNextFrameIdANDROIDPtr(nullptr),
getFrameTimestampSupportedANDROIDPtr(nullptr),
getFrameTimestampsANDROIDPtr(nullptr),
dupNativeFenceFDANDROIDPtr(nullptr),
queryDmaBufFormatsEXTPtr(nullptr),
queryDmaBufModifiersEXTPtr(nullptr),
queryDeviceAttribEXTPtr(nullptr),
queryDeviceStringEXTPtr(nullptr),
queryDisplayAttribEXTPtr(nullptr)
{}
// 1.0
PFNEGLBINDAPIPROC bindAPIPtr;
PFNEGLCHOOSECONFIGPROC chooseConfigPtr;
PFNEGLCREATECONTEXTPROC createContextPtr;
PFNEGLCREATEPBUFFERSURFACEPROC createPbufferSurfacePtr;
PFNEGLCREATEWINDOWSURFACEPROC createWindowSurfacePtr;
PFNEGLDESTROYCONTEXTPROC destroyContextPtr;
PFNEGLDESTROYSURFACEPROC destroySurfacePtr;
PFNEGLGETCONFIGATTRIBPROC getConfigAttribPtr;
PFNEGLGETCONFIGSPROC getConfigsPtr;
PFNEGLGETCURRENTSURFACEPROC getCurrentSurfacePtr;
PFNEGLGETDISPLAYPROC getDisplayPtr;
PFNEGLGETERRORPROC getErrorPtr;
PFNEGLINITIALIZEPROC initializePtr;
PFNEGLMAKECURRENTPROC makeCurrentPtr;
PFNEGLQUERYSTRINGPROC queryStringPtr;
PFNEGLQUERYSURFACEPROC querySurfacePtr;
PFNEGLSWAPBUFFERSPROC swapBuffersPtr;
PFNEGLTERMINATEPROC terminatePtr;
// 1.1
PFNEGLBINDTEXIMAGEPROC bindTexImagePtr;
PFNEGLRELEASETEXIMAGEPROC releaseTexImagePtr;
PFNEGLSURFACEATTRIBPROC surfaceAttribPtr;
PFNEGLSWAPINTERVALPROC swapIntervalPtr;
// 1.4
PFNEGLGETCURRENTCONTEXTPROC getCurrentContextPtr;
// EGL_KHR_image
PFNEGLCREATEIMAGEKHRPROC createImageKHRPtr;
PFNEGLDESTROYIMAGEKHRPROC destroyImageKHRPtr;
// EGL_KHR_fence_sync
PFNEGLCREATESYNCKHRPROC createSyncKHRPtr;
PFNEGLDESTROYSYNCKHRPROC destroySyncKHRPtr;
PFNEGLCLIENTWAITSYNCKHRPROC clientWaitSyncKHRPtr;
PFNEGLGETSYNCATTRIBKHRPROC getSyncAttribKHRPtr;
// EGL_KHR_wait_sync
PFNEGLWAITSYNCKHRPROC waitSyncKHRPtr;
// EGL_KHR_swap_buffers_with_damage
PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC swapBuffersWithDamageKHRPtr;
// EGL_ANDROID_presentation_time
PFNEGLPRESENTATIONTIMEANDROIDPROC presentationTimeANDROIDPtr;
// EGL_ANDROID_blob_cache
PFNEGLSETBLOBCACHEFUNCSANDROIDPROC setBlobCacheFuncsANDROIDPtr;
// EGL_ANDROID_get_frame_timestamps
PFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROIDPROC getCompositorTimingSupportedANDROIDPtr;
PFNEGLGETCOMPOSITORTIMINGANDROIDPROC getCompositorTimingANDROIDPtr;
PFNEGLGETNEXTFRAMEIDANDROIDPROC getNextFrameIdANDROIDPtr;
PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROIDPROC getFrameTimestampSupportedANDROIDPtr;
PFNEGLGETFRAMETIMESTAMPSANDROIDPROC getFrameTimestampsANDROIDPtr;
// EGL_ANDROID_native_fence_sync
PFNEGLDUPNATIVEFENCEFDANDROIDPROC dupNativeFenceFDANDROIDPtr;
// EGL_EXT_image_dma_buf_import_modifiers
PFNEGLQUERYDMABUFFORMATSEXTPROC queryDmaBufFormatsEXTPtr;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC queryDmaBufModifiersEXTPtr;
// EGL_EXT_device_query
PFNEGLQUERYDEVICEATTRIBEXTPROC queryDeviceAttribEXTPtr;
PFNEGLQUERYDEVICESTRINGEXTPROC queryDeviceStringEXTPtr;
PFNEGLQUERYDISPLAYATTRIBEXTPROC queryDisplayAttribEXTPtr;
};
FunctionsEGL::FunctionsEGL()
: majorVersion(0), minorVersion(0), mFnPtrs(new EGLDispatchTable()), mEGLDisplay(EGL_NO_DISPLAY)
{}
FunctionsEGL::~FunctionsEGL()
{
SafeDelete(mFnPtrs);
}
egl::Error FunctionsEGL::initialize(EGLAttrib platformType, EGLNativeDisplayType nativeDisplay)
{
#define ANGLE_GET_PROC_OR_WARNING(MEMBER, NAME) \
do \
{ \
if (!SetPtr(MEMBER, getProcAddress(#NAME))) \
{ \
WARN() << "Could not load EGL entry point " #NAME; \
} \
} while (0)
#define ANGLE_GET_PROC_OR_ERROR(MEMBER, NAME) \
do \
{ \
if (!SetPtr(MEMBER, getProcAddress(#NAME))) \
{ \
return egl::Error(EGL_NOT_INITIALIZED, "Could not load EGL entry point " #NAME); \
} \
} while (0)
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->bindAPIPtr, eglBindAPI);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->chooseConfigPtr, eglChooseConfig);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createContextPtr, eglCreateContext);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createPbufferSurfacePtr, eglCreatePbufferSurface);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createWindowSurfacePtr, eglCreateWindowSurface);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroyContextPtr, eglDestroyContext);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroySurfacePtr, eglDestroySurface);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getConfigAttribPtr, eglGetConfigAttrib);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getConfigsPtr, eglGetConfigs);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getCurrentSurfacePtr, eglGetCurrentSurface);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getDisplayPtr, eglGetDisplay);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getErrorPtr, eglGetError);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->initializePtr, eglInitialize);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->makeCurrentPtr, eglMakeCurrent);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->queryStringPtr, eglQueryString);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->querySurfacePtr, eglQuerySurface);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->swapBuffersPtr, eglSwapBuffers);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->terminatePtr, eglTerminate);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->bindTexImagePtr, eglBindTexImage);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->releaseTexImagePtr, eglReleaseTexImage);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->surfaceAttribPtr, eglSurfaceAttrib);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->swapIntervalPtr, eglSwapInterval);
// Querying EGL_EXTENSIONS string and loading it into the mExtensions
// vector will at this point retrieve the client extensions since mEGLDisplay is still
// EGL_NO_DISPLAY. This is desired, and mExtensions will later be reinitialized with the display
// extensions once the display is created and initialized.
queryExtensions();
#if defined(ANGLE_HAS_LIBDRM)
mEGLDisplay = getPreferredDisplay(&majorVersion, &minorVersion);
#endif // defined(ANGLE_HAS_LIBDRM)
if (mEGLDisplay == EGL_NO_DISPLAY)
{
if (IsValidPlatformTypeForPlatformDisplayConnection(platformType))
{
mEGLDisplay = getPlatformDisplay(platformType, nativeDisplay);
}
else
{
mEGLDisplay = mFnPtrs->getDisplayPtr(nativeDisplay);
}
}
if (mEGLDisplay != EGL_NO_DISPLAY &&
mFnPtrs->initializePtr(mEGLDisplay, &majorVersion, &minorVersion) != EGL_TRUE)
{
mEGLDisplay = EGL_NO_DISPLAY;
}
if (mEGLDisplay == EGL_NO_DISPLAY)
{
// If no display was available, try to fallback to the first available
// native device object's display.
mEGLDisplay = getNativeDisplay(&majorVersion, &minorVersion);
}
if (mEGLDisplay == EGL_NO_DISPLAY)
{
return egl::Error(EGL_NOT_INITIALIZED, "Failed to get system egl display");
}
if (majorVersion < 1 || (majorVersion == 1 && minorVersion < 4))
{
return egl::Error(EGL_NOT_INITIALIZED, "Unsupported EGL version (require at least 1.4).");
}
if (mFnPtrs->bindAPIPtr(EGL_OPENGL_ES_API) != EGL_TRUE)
{
return egl::Error(mFnPtrs->getErrorPtr(), "Failed to bind API in system egl");
}
vendorString = queryString(EGL_VENDOR);
versionString = queryString(EGL_VERSION);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getCurrentContextPtr, eglGetCurrentContext);
if (!queryExtensions())
{
return egl::Error(mFnPtrs->getErrorPtr(), "Failed to query extensions in system egl");
}
if (hasExtension("EGL_KHR_image_base"))
{
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createImageKHRPtr, eglCreateImageKHR);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroyImageKHRPtr, eglDestroyImageKHR);
}
if (hasExtension("EGL_KHR_fence_sync"))
{
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createSyncKHRPtr, eglCreateSyncKHR);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroySyncKHRPtr, eglDestroySyncKHR);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->clientWaitSyncKHRPtr, eglClientWaitSyncKHR);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getSyncAttribKHRPtr, eglGetSyncAttribKHR);
}
if (hasExtension("EGL_KHR_wait_sync"))
{
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->waitSyncKHRPtr, eglWaitSyncKHR);
}
if (hasExtension("EGL_KHR_swap_buffers_with_damage"))
{
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->swapBuffersWithDamageKHRPtr, eglSwapBuffersWithDamageKHR);
}
if (hasExtension("EGL_ANDROID_presentation_time"))
{
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->presentationTimeANDROIDPtr, eglPresentationTimeANDROID);
}
if (hasExtension("EGL_ANDROID_blob_cache"))
{
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->setBlobCacheFuncsANDROIDPtr, eglSetBlobCacheFuncsANDROID);
}
if (hasExtension("EGL_ANDROID_get_frame_timestamps"))
{
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getCompositorTimingSupportedANDROIDPtr,
eglGetCompositorTimingSupportedANDROID);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getCompositorTimingANDROIDPtr,
eglGetCompositorTimingANDROID);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getNextFrameIdANDROIDPtr, eglGetNextFrameIdANDROID);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getFrameTimestampSupportedANDROIDPtr,
eglGetFrameTimestampSupportedANDROID);
ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getFrameTimestampsANDROIDPtr,
eglGetFrameTimestampsANDROID);
}
// The native fence sync extension is a bit complicated. It's reported as present for ChromeOS,
// but Android currently doesn't report this extension even when it's present, and older devices
// may export a useless wrapper function. See crbug.com/775707 for details. In short, if the
// symbol is present and we're on Android N or newer, assume that it's usable even if the
// extension wasn't reported.
if (hasExtension("EGL_ANDROID_native_fence_sync") || GetAndroidSDKVersion() >= 24)
{
// Don't error trying to load this entry point.
if (SetPtr(&mFnPtrs->dupNativeFenceFDANDROIDPtr,
getProcAddress("eglDupNativeFenceFDANDROID")) &&
!hasExtension("EGL_ANDROID_native_fence_sync"))
{
mExtensions.push_back("EGL_ANDROID_native_fence_sync");
}
}
if (hasExtension("EGL_EXT_image_dma_buf_import_modifiers"))
{
// https://anglebug.com/42266130
// Some drivers, notably older versions of ANGLE, announce this extension without
// implementing the following functions. DisplayEGL checks for this case and disables the
// extension.
ANGLE_GET_PROC_OR_WARNING(&mFnPtrs->queryDmaBufFormatsEXTPtr, eglQueryDmaBufFormatsEXT);
ANGLE_GET_PROC_OR_WARNING(&mFnPtrs->queryDmaBufModifiersEXTPtr, eglQueryDmaBufModifiersEXT);
}
// EGL_EXT_device_query is only advertised in extension string in the
// no-display case, see getNativeDisplay().
if (SetPtr(&mFnPtrs->queryDeviceAttribEXTPtr, getProcAddress("eglQueryDeviceAttribEXT")) &&
SetPtr(&mFnPtrs->queryDeviceStringEXTPtr, getProcAddress("eglQueryDeviceStringEXT")) &&
SetPtr(&mFnPtrs->queryDisplayAttribEXTPtr, getProcAddress("eglQueryDisplayAttribEXT")))
{
mExtensions.push_back("EGL_EXT_device_query");
}
#undef ANGLE_GET_PROC_OR_ERROR
return egl::NoError();
}
egl::Error FunctionsEGL::terminate()
{
if (mFnPtrs->terminatePtr == nullptr || mFnPtrs->terminatePtr(mEGLDisplay) == EGL_TRUE)
{
mEGLDisplay = nullptr;
return egl::NoError();
}
return egl::Error(mFnPtrs->getErrorPtr());
}
bool FunctionsEGL::queryExtensions()
{
const char *extensions = queryString(EGL_EXTENSIONS);
if (!extensions)
{
return false;
}
angle::SplitStringAlongWhitespace(extensions, &mExtensions);
return true;
}
EGLDisplay FunctionsEGL::getPlatformDisplay(EGLAttrib platformType,
EGLNativeDisplayType nativeDisplay)
{
PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXTPtr;
if (!hasExtension("EGL_EXT_platform_base") ||
!SetPtr(&getPlatformDisplayEXTPtr, getProcAddress("eglGetPlatformDisplayEXT")))
{
return EGL_NO_DISPLAY;
}
ASSERT(IsValidPlatformTypeForPlatformDisplayConnection(platformType));
switch (platformType)
{
case EGL_PLATFORM_SURFACELESS_MESA:
if (!hasExtension("EGL_MESA_platform_surfaceless"))
return EGL_NO_DISPLAY;
break;
default:
UNREACHABLE();
return EGL_NO_DISPLAY;
}
return getPlatformDisplayEXTPtr(static_cast<EGLenum>(platformType),
reinterpret_cast<void *>(nativeDisplay), nullptr);
}
std::vector<EGLDeviceEXT> FunctionsEGL::queryDevices(int *major, int *minor)
{
// Only called after confirming we have the necessary extension.
PFNEGLQUERYDEVICESEXTPROC queryDevicesEXTPtr;
if (!SetPtr(&queryDevicesEXTPtr, getProcAddress("eglQueryDevicesEXT")))
{
return {};
}
// Get a list of native device objects.
const EGLint kMaxDevices = 32;
EGLint numDevices = 0;
std::vector<EGLDeviceEXT> devices(kMaxDevices, EGL_NO_DEVICE_EXT);
if (!queryDevicesEXTPtr(kMaxDevices, devices.data(), &numDevices))
{
return {};
}
devices.resize(numDevices);
return devices;
}
EGLDisplay FunctionsEGL::getNativeDisplay(int *major, int *minor)
{
// This fallback mechanism makes use of:
// - EGL_EXT_device_enumeration or EGL_EXT_device_base for eglQueryDevicesEXT
// - EGL_EXT_platform_base for eglGetPlatformDisplayEXT
// - EGL_EXT_platform_device for EGL_PLATFORM_DEVICE_EXT
PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXTPtr;
bool hasQueryDevicesEXT =
hasExtension("EGL_EXT_device_enumeration") || hasExtension("EGL_EXT_device_base");
bool hasPlatformBaseEXT = hasExtension("EGL_EXT_platform_base");
bool hasPlatformDeviceEXT = hasExtension("EGL_EXT_platform_device");
if (!hasQueryDevicesEXT || !hasPlatformBaseEXT || !hasPlatformDeviceEXT)
{
return EGL_NO_DISPLAY;
}
if (!SetPtr(&getPlatformDisplayEXTPtr, getProcAddress("eglGetPlatformDisplayEXT")))
{
return EGL_NO_DISPLAY;
}
std::vector<EGLDeviceEXT> devices = queryDevices(major, minor);
if (devices.size() == 0)
{
return EGL_NO_DISPLAY;
}
// Look for the first native device that gives us a valid display.
for (const EGLDeviceEXT device : devices)
{
EGLDisplay display = getPlatformDisplayEXTPtr(EGL_PLATFORM_DEVICE_EXT, device, nullptr);
if (mFnPtrs->getErrorPtr() == EGL_SUCCESS &&
mFnPtrs->initializePtr(display, major, minor) == EGL_TRUE)
{
return display;
}
}
return EGL_NO_DISPLAY;
}
#if defined(ANGLE_HAS_LIBDRM)
EGLDeviceEXT FunctionsEGL::getPreferredEGLDevice(const std::vector<EGLDeviceEXT> &devices)
{
// Only called after confirming we have the necessary extension.
PFNEGLQUERYDEVICESTRINGEXTPROC queryDeviceStringEXTPtr;
if (!SetPtr(&queryDeviceStringEXTPtr, getProcAddress("eglQueryDeviceStringEXT")))
{
return EGL_NO_DEVICE_EXT;
}
std::map<EGLDeviceEXT, std::string> device_drivers;
for (const EGLDeviceEXT device : devices)
{
const char *filename = queryDeviceStringEXTPtr(device, EGL_DRM_DEVICE_FILE_EXT);
if (!filename)
{
continue;
}
int fd = open(filename, O_RDWR);
if (!fd)
{
continue;
}
drmVersionPtr version = drmGetVersion(fd);
if (version)
{
const std::string driver_name(version->name, version->name_len);
device_drivers.insert({device, driver_name});
}
drmFreeVersion(version);
close(fd);
}
const char *preferred_drivers[3] = {"i915", "amdgpu", "virtio_gpu"};
for (const char *preferred_driver : preferred_drivers)
{
for (const EGLDeviceEXT device : devices)
{
const auto driver = device_drivers.find(device);
if (driver != device_drivers.end() && driver->second == preferred_driver)
{
return device;
}
}
}
return EGL_NO_DEVICE_EXT;
}
EGLDisplay FunctionsEGL::getPreferredDisplay(int *major, int *minor)
{
// This mechanism makes use of:
// - EGL_EXT_device_enumeration or EGL_EXT_device_base for eglQueryDevicesEXT
// - EGL_EXT_platform_base for eglGetPlatformDisplayEXT
// - EGL_EXT_platform_device for EGL_PLATFORM_DEVICE_EXT
// - EGL_EXT_device_query for eglQueryDeviceStringEXT
PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXTPtr;
bool hasQueryDevicesEXT =
hasExtension("EGL_EXT_device_enumeration") || hasExtension("EGL_EXT_device_base");
bool hasPlatformBaseEXT = hasExtension("EGL_EXT_platform_base");
bool hasPlatformDeviceEXT = hasExtension("EGL_EXT_platform_device");
bool hasDeviceQueryEXT = hasExtension("EGL_EXT_device_query");
if (!hasQueryDevicesEXT || !hasPlatformBaseEXT || !hasPlatformDeviceEXT || !hasDeviceQueryEXT)
{
return EGL_NO_DISPLAY;
}
if (!SetPtr(&getPlatformDisplayEXTPtr, getProcAddress("eglGetPlatformDisplayEXT")))
{
return EGL_NO_DISPLAY;
}
std::vector<EGLDeviceEXT> devices = queryDevices(major, minor);
if (devices.size() == 0)
{
return EGL_NO_DISPLAY;
}
EGLDeviceEXT device = getPreferredEGLDevice(devices);
if (device == EGL_NO_DEVICE_EXT)
{
return EGL_NO_DISPLAY;
}
EGLDisplay display = getPlatformDisplayEXTPtr(EGL_PLATFORM_DEVICE_EXT, device, nullptr);
if (mFnPtrs->getErrorPtr() == EGL_SUCCESS)
{
return display;
}
return EGL_NO_DISPLAY;
}
#endif // defined(ANGLE_HAS_LIBDRM)
class FunctionsGLEGL : public FunctionsGL
{
public:
FunctionsGLEGL(const FunctionsEGL &egl) : mEGL(egl) {}
~FunctionsGLEGL() override {}
private:
void *loadProcAddress(const std::string &function) const override
{
return mEGL.getProcAddress(function.c_str());
}
const FunctionsEGL &mEGL;
};
FunctionsGL *FunctionsEGL::makeFunctionsGL(void) const
{
return new FunctionsGLEGL(*this);
}
bool FunctionsEGL::hasExtension(const char *extension) const
{
return std::find(mExtensions.begin(), mExtensions.end(), extension) != mExtensions.end();
}
bool FunctionsEGL::hasDmaBufImportModifierFunctions() const
{
return mFnPtrs->queryDmaBufFormatsEXTPtr != nullptr &&
mFnPtrs->queryDmaBufModifiersEXTPtr != nullptr;
}
EGLDisplay FunctionsEGL::getDisplay() const
{
return mEGLDisplay;
}
EGLint FunctionsEGL::getError() const
{
return mFnPtrs->getErrorPtr();
}
EGLBoolean FunctionsEGL::chooseConfig(EGLint const *attribList,
EGLConfig *configs,
EGLint configSize,
EGLint *numConfig) const
{
return mFnPtrs->chooseConfigPtr(mEGLDisplay, attribList, configs, configSize, numConfig);
}
EGLBoolean FunctionsEGL::getConfigs(EGLConfig *configs,
EGLint config_size,
EGLint *num_config) const
{
return mFnPtrs->getConfigsPtr(mEGLDisplay, configs, config_size, num_config);
}
EGLBoolean FunctionsEGL::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) const
{
return mFnPtrs->getConfigAttribPtr(mEGLDisplay, config, attribute, value);
}
EGLSurface FunctionsEGL::getCurrentSurface(EGLint readdraw) const
{
return mFnPtrs->getCurrentSurfacePtr(readdraw);
}
EGLContext FunctionsEGL::createContext(EGLConfig config,
EGLContext share_context,
EGLint const *attrib_list) const
{
return mFnPtrs->createContextPtr(mEGLDisplay, config, share_context, attrib_list);
}
EGLSurface FunctionsEGL::createPbufferSurface(EGLConfig config, const EGLint *attrib_list) const
{
return mFnPtrs->createPbufferSurfacePtr(mEGLDisplay, config, attrib_list);
}
EGLSurface FunctionsEGL::createWindowSurface(EGLConfig config,
EGLNativeWindowType win,
const EGLint *attrib_list) const
{
return mFnPtrs->createWindowSurfacePtr(mEGLDisplay, config, win, attrib_list);
}
EGLBoolean FunctionsEGL::destroyContext(EGLContext context) const
{
return mFnPtrs->destroyContextPtr(mEGLDisplay, context);
}
EGLBoolean FunctionsEGL::destroySurface(EGLSurface surface) const
{
return mFnPtrs->destroySurfacePtr(mEGLDisplay, surface);
}
EGLBoolean FunctionsEGL::makeCurrent(EGLSurface surface, EGLContext context) const
{
return mFnPtrs->makeCurrentPtr(mEGLDisplay, surface, surface, context);
}
char const *FunctionsEGL::queryString(EGLint name) const
{
return mFnPtrs->queryStringPtr(mEGLDisplay, name);
}
EGLBoolean FunctionsEGL::querySurface(EGLSurface surface, EGLint attribute, EGLint *value) const
{
return mFnPtrs->querySurfacePtr(mEGLDisplay, surface, attribute, value);
}
EGLBoolean FunctionsEGL::swapBuffers(EGLSurface surface) const
{
return mFnPtrs->swapBuffersPtr(mEGLDisplay, surface);
}
EGLBoolean FunctionsEGL::bindTexImage(EGLSurface surface, EGLint buffer) const
{
return mFnPtrs->bindTexImagePtr(mEGLDisplay, surface, buffer);
}
EGLBoolean FunctionsEGL::releaseTexImage(EGLSurface surface, EGLint buffer) const
{
return mFnPtrs->releaseTexImagePtr(mEGLDisplay, surface, buffer);
}
EGLBoolean FunctionsEGL::surfaceAttrib(EGLSurface surface, EGLint attribute, EGLint value) const
{
return mFnPtrs->surfaceAttribPtr(mEGLDisplay, surface, attribute, value);
}
EGLBoolean FunctionsEGL::swapInterval(EGLint interval) const
{
return mFnPtrs->swapIntervalPtr(mEGLDisplay, interval);
}
EGLContext FunctionsEGL::getCurrentContext() const
{
return mFnPtrs->getCurrentContextPtr();
}
EGLImageKHR FunctionsEGL::createImageKHR(EGLContext context,
EGLenum target,
EGLClientBuffer buffer,
const EGLint *attrib_list) const
{
return mFnPtrs->createImageKHRPtr(mEGLDisplay, context, target, buffer, attrib_list);
}
EGLBoolean FunctionsEGL::destroyImageKHR(EGLImageKHR image) const
{
return mFnPtrs->destroyImageKHRPtr(mEGLDisplay, image);
}
EGLSyncKHR FunctionsEGL::createSyncKHR(EGLenum type, const EGLint *attrib_list) const
{
return mFnPtrs->createSyncKHRPtr(mEGLDisplay, type, attrib_list);
}
EGLBoolean FunctionsEGL::destroySyncKHR(EGLSyncKHR sync) const
{
return mFnPtrs->destroySyncKHRPtr(mEGLDisplay, sync);
}
EGLint FunctionsEGL::clientWaitSyncKHR(EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) const
{
return mFnPtrs->clientWaitSyncKHRPtr(mEGLDisplay, sync, flags, timeout);
}
EGLBoolean FunctionsEGL::getSyncAttribKHR(EGLSyncKHR sync, EGLint attribute, EGLint *value) const
{
return mFnPtrs->getSyncAttribKHRPtr(mEGLDisplay, sync, attribute, value);
}
EGLint FunctionsEGL::waitSyncKHR(EGLSyncKHR sync, EGLint flags) const
{
return mFnPtrs->waitSyncKHRPtr(mEGLDisplay, sync, flags);
}
EGLBoolean FunctionsEGL::swapBuffersWithDamageKHR(EGLSurface surface,
const EGLint *rects,
EGLint n_rects) const
{
return mFnPtrs->swapBuffersWithDamageKHRPtr(mEGLDisplay, surface, rects, n_rects);
}
EGLBoolean FunctionsEGL::presentationTimeANDROID(EGLSurface surface, EGLnsecsANDROID time) const
{
return mFnPtrs->presentationTimeANDROIDPtr(mEGLDisplay, surface, time);
}
void FunctionsEGL::setBlobCacheFuncsANDROID(EGLSetBlobFuncANDROID set,
EGLGetBlobFuncANDROID get) const
{
return mFnPtrs->setBlobCacheFuncsANDROIDPtr(mEGLDisplay, set, get);
}
EGLBoolean FunctionsEGL::getCompositorTimingSupportedANDROID(EGLSurface surface, EGLint name) const
{
return mFnPtrs->getCompositorTimingSupportedANDROIDPtr(mEGLDisplay, surface, name);
}
EGLBoolean FunctionsEGL::getCompositorTimingANDROID(EGLSurface surface,
EGLint numTimestamps,
const EGLint *names,
EGLnsecsANDROID *values) const
{
return mFnPtrs->getCompositorTimingANDROIDPtr(mEGLDisplay, surface, numTimestamps, names,
values);
}
EGLBoolean FunctionsEGL::getNextFrameIdANDROID(EGLSurface surface, EGLuint64KHR *frameId) const
{
return mFnPtrs->getNextFrameIdANDROIDPtr(mEGLDisplay, surface, frameId);
}
EGLBoolean FunctionsEGL::getFrameTimestampSupportedANDROID(EGLSurface surface,
EGLint timestamp) const
{
return mFnPtrs->getFrameTimestampSupportedANDROIDPtr(mEGLDisplay, surface, timestamp);
}
EGLBoolean FunctionsEGL::getFrameTimestampsANDROID(EGLSurface surface,
EGLuint64KHR frameId,
EGLint numTimestamps,
const EGLint *timestamps,
EGLnsecsANDROID *values) const
{
return mFnPtrs->getFrameTimestampsANDROIDPtr(mEGLDisplay, surface, frameId, numTimestamps,
timestamps, values);
}
EGLint FunctionsEGL::dupNativeFenceFDANDROID(EGLSync sync) const
{
return mFnPtrs->dupNativeFenceFDANDROIDPtr(mEGLDisplay, sync);
}
EGLint FunctionsEGL::queryDmaBufFormatsEXT(EGLint maxFormats,
EGLint *formats,
EGLint *numFormats) const
{
return mFnPtrs->queryDmaBufFormatsEXTPtr(mEGLDisplay, maxFormats, formats, numFormats);
}
EGLint FunctionsEGL::queryDmaBufModifiersEXT(EGLint format,
EGLint maxModifiers,
EGLuint64KHR *modifiers,
EGLBoolean *externalOnly,
EGLint *numModifiers) const
{
return mFnPtrs->queryDmaBufModifiersEXTPtr(mEGLDisplay, format, maxModifiers, modifiers,
externalOnly, numModifiers);
}
EGLBoolean FunctionsEGL::queryDeviceAttribEXT(EGLDeviceEXT device,
EGLint attribute,
EGLAttrib *value) const
{
return mFnPtrs->queryDeviceAttribEXTPtr(device, attribute, value);
}
const char *FunctionsEGL::queryDeviceStringEXT(EGLDeviceEXT device, EGLint name) const
{
return mFnPtrs->queryDeviceStringEXTPtr(device, name);
}
EGLBoolean FunctionsEGL::queryDisplayAttribEXT(EGLint attribute, EGLAttrib *value) const
{
return mFnPtrs->queryDisplayAttribEXTPtr(mEGLDisplay, attribute, value);
}
} // namespace rx