// // 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 #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" namespace { template bool SetPtr(T *dst, void *src) { if (src) { *dst = reinterpret_cast(src); return true; } 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), getDisplayPtr(nullptr), getErrorPtr(nullptr), initializePtr(nullptr), makeCurrentPtr(nullptr), queryStringPtr(nullptr), querySurfacePtr(nullptr), swapBuffersPtr(nullptr), terminatePtr(nullptr), bindTexImagePtr(nullptr), releaseTexImagePtr(nullptr), surfaceAttribPtr(nullptr), swapIntervalPtr(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) {} // 1.0 PFNEGLBINDAPIPROC bindAPIPtr; PFNEGLCHOOSECONFIGPROC chooseConfigPtr; PFNEGLCREATECONTEXTPROC createContextPtr; PFNEGLCREATEPBUFFERSURFACEPROC createPbufferSurfacePtr; PFNEGLCREATEWINDOWSURFACEPROC createWindowSurfacePtr; PFNEGLDESTROYCONTEXTPROC destroyContextPtr; PFNEGLDESTROYSURFACEPROC destroySurfacePtr; PFNEGLGETCONFIGATTRIBPROC getConfigAttribPtr; 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; // 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; }; FunctionsEGL::FunctionsEGL() : majorVersion(0), minorVersion(0), mFnPtrs(new EGLDispatchTable()), mEGLDisplay(EGL_NO_DISPLAY) {} FunctionsEGL::~FunctionsEGL() { SafeDelete(mFnPtrs); } egl::Error FunctionsEGL::initialize(EGLNativeDisplayType nativeDisplay) { #define ANGLE_GET_PROC_OR_ERROR(MEMBER, NAME) \ do \ { \ if (!SetPtr(MEMBER, getProcAddress(#NAME))) \ { \ return egl::EglNotInitialized() << "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->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); mEGLDisplay = mFnPtrs->getDisplayPtr(nativeDisplay); if (mEGLDisplay == EGL_NO_DISPLAY) { return egl::EglNotInitialized() << "Failed to get system egl display"; } if (mFnPtrs->initializePtr(mEGLDisplay, &majorVersion, &minorVersion) != EGL_TRUE) { return egl::Error(mFnPtrs->getErrorPtr(), "Failed to initialize system egl"); } if (majorVersion < 1 || (majorVersion == 1 && minorVersion < 4)) { return egl::EglNotInitialized() << "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"); } const char *extensions = queryString(EGL_EXTENSIONS); if (!extensions) { return egl::Error(mFnPtrs->getErrorPtr(), "Faild to query extensions in system egl"); } angle::SplitStringAlongWhitespace(extensions, &mExtensions); 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"); } } #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()); } 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(); } 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::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) const { return mFnPtrs->getConfigAttribPtr(mEGLDisplay, config, attribute, value); } 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); } 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, 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); } } // namespace rx