// // Copyright (c) 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 "libANGLE/renderer/gl/FunctionsGL.h" #include "libANGLE/renderer/gl/egl/functionsegl_typedefs.h" #include "common/string_utils.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), swapIntervalPtr(nullptr), createImageKHRPtr(nullptr), destroyImageKHRPtr(nullptr), clientWaitSyncKHRPtr(nullptr), createSyncKHRPtr(nullptr), destroySyncKHRPtr(nullptr), getSyncAttribKHRPtr(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; PFNEGLSWAPINTERVALPROC swapIntervalPtr; // EGL_KHR_image PFNEGLCREATEIMAGEKHRPROC createImageKHRPtr; PFNEGLDESTROYIMAGEKHRPROC destroyImageKHRPtr; // EGL_KHR_fence_sync PFNEGLCLIENTWAITSYNCKHRPROC clientWaitSyncKHRPtr; PFNEGLCREATESYNCKHRPROC createSyncKHRPtr; PFNEGLDESTROYSYNCKHRPROC destroySyncKHRPtr; PFNEGLGETSYNCATTRIBKHRPROC getSyncAttribKHRPtr; }; 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) \ if (!SetPtr(MEMBER, getProcAddress(#NAME))) \ { \ return egl::Error(EGL_NOT_INITIALIZED, "Could not load EGL entry point " #NAME); \ } 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->swapIntervalPtr, eglSwapInterval); mEGLDisplay = mFnPtrs->getDisplayPtr(nativeDisplay); if (mEGLDisplay == EGL_NO_DISPLAY) { return egl::Error(EGL_NOT_INITIALIZED, "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::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"); } 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->clientWaitSyncKHRPtr, eglClientWaitSyncKHR); ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->createSyncKHRPtr, eglCreateSyncKHR); ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->destroySyncKHRPtr, eglDestroySyncKHR); ANGLE_GET_PROC_OR_ERROR(&mFnPtrs->getSyncAttribKHRPtr, eglGetSyncAttribKHR); } #undef ANGLE_GET_PROC_OR_ERROR return egl::Error(EGL_SUCCESS); } egl::Error FunctionsEGL::terminate() { if (mFnPtrs->terminatePtr(mEGLDisplay) == EGL_TRUE) { mEGLDisplay = nullptr; return egl::Error(EGL_SUCCESS); } 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) 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::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) { return mFnPtrs->createSyncKHRPtr(mEGLDisplay, type, attrib_list); } EGLBoolean FunctionsEGL::destroySyncKHR(EGLSyncKHR sync) { return mFnPtrs->destroySyncKHRPtr(mEGLDisplay, sync); } EGLint FunctionsEGL::clientWaitSyncKHR(EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) { return mFnPtrs->clientWaitSyncKHRPtr(mEGLDisplay, sync, flags, timeout); } EGLBoolean FunctionsEGL::getSyncAttribKHR(EGLSyncKHR sync, EGLint attribute, EGLint *value) { return mFnPtrs->getSyncAttribKHRPtr(mEGLDisplay, sync, attribute, value); } } // namespace rx