/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef GLLIBRARYEGL_H_ #define GLLIBRARYEGL_H_ #if defined(MOZ_X11) #include "mozilla/X11Util.h" #endif #include "GLLibraryLoader.h" #include "mozilla/ThreadLocal.h" #include "nsIFile.h" #include "GeckoProfiler.h" #include #if defined(XP_WIN) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif #include typedef HDC EGLNativeDisplayType; typedef HBITMAP EGLNativePixmapType; typedef HWND EGLNativeWindowType; #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW)) #else typedef void *EGLNativeDisplayType; typedef void *EGLNativePixmapType; typedef void *EGLNativeWindowType; #ifdef ANDROID // We only need to explicitly dlopen egltrace // on android as we can use LD_PRELOAD or other tricks // on other platforms. We look for it in /data/local // as that's writeable by all users // // This should really go in GLLibraryEGL.cpp but we currently reference // APITRACE_LIB in GLContextProviderEGL.cpp. Further refactoring // will come in subsequent patches on Bug 732865 #define APITRACE_LIB "/data/local/tmp/egltrace.so" #ifdef MOZ_WIDGET_ANDROID #endif // MOZ_WIDGET_ANDROID #endif // ANDROID #endif #if defined(MOZ_X11) #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)mozilla::DefaultXDisplay()) #else #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) #endif namespace mozilla { namespace gl { #undef BEFORE_GL_CALL #undef AFTER_GL_CALL #ifdef DEBUG #ifndef MOZ_FUNCTION_NAME # ifdef __GNUC__ # define MOZ_FUNCTION_NAME __PRETTY_FUNCTION__ # elif defined(_MSC_VER) # define MOZ_FUNCTION_NAME __FUNCTION__ # else # define MOZ_FUNCTION_NAME __func__ // defined in C99, supported in various C++ compilers. Just raw function name. # endif #endif #ifdef MOZ_WIDGET_ANDROID // Record the name of the GL call for better hang stacks on Android. #define BEFORE_GL_CALL \ PROFILER_LABEL_FUNC( \ js::ProfileEntry::Category::GRAPHICS);\ BeforeGLCall(MOZ_FUNCTION_NAME) #else #define BEFORE_GL_CALL do { \ BeforeGLCall(MOZ_FUNCTION_NAME); \ } while (0) #endif #define AFTER_GL_CALL do { \ AfterGLCall(MOZ_FUNCTION_NAME); \ } while (0) #else #ifdef MOZ_WIDGET_ANDROID // Record the name of the GL call for better hang stacks on Android. #define BEFORE_GL_CALL PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS) #else #define BEFORE_GL_CALL #endif #define AFTER_GL_CALL #endif class GLLibraryEGL { public: GLLibraryEGL() : mInitialized(false), mEGLLibrary(nullptr), mIsANGLE(false) { } void InitExtensions(); /** * Known GL extensions that can be queried by * IsExtensionSupported. The results of this are cached, and as * such it's safe to use this even in performance critical code. * If you add to this array, remember to add to the string names * in GLContext.cpp. */ enum EGLExtensions { KHR_image_base, KHR_image_pixmap, KHR_gl_texture_2D_image, KHR_lock_surface, ANGLE_surface_d3d_texture_2d_share_handle, EXT_create_context_robustness, KHR_image, KHR_fence_sync, ANDROID_native_fence_sync, Extensions_Max }; bool IsExtensionSupported(EGLExtensions aKnownExtension) const { return mAvailableExtensions[aKnownExtension]; } void MarkExtensionUnsupported(EGLExtensions aKnownExtension) { mAvailableExtensions[aKnownExtension] = false; } protected: std::bitset mAvailableExtensions; public: EGLDisplay fGetDisplay(void* display_id) { BEFORE_GL_CALL; EGLDisplay disp = mSymbols.fGetDisplay(display_id); AFTER_GL_CALL; return disp; } EGLBoolean fTerminate(EGLDisplay display) { BEFORE_GL_CALL; EGLBoolean ret = mSymbols.fTerminate(display); AFTER_GL_CALL; return ret; } EGLSurface fGetCurrentSurface(EGLint id) { BEFORE_GL_CALL; EGLSurface surf = mSymbols.fGetCurrentSurface(id); AFTER_GL_CALL; return surf; } EGLContext fGetCurrentContext() { BEFORE_GL_CALL; EGLContext context = mSymbols.fGetCurrentContext(); AFTER_GL_CALL; return context; } EGLBoolean fMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fMakeCurrent(dpy, draw, read, ctx); AFTER_GL_CALL; return b; } EGLBoolean fDestroyContext(EGLDisplay dpy, EGLContext ctx) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fDestroyContext(dpy, ctx); AFTER_GL_CALL; return b; } EGLContext fCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) { BEFORE_GL_CALL; EGLContext ctx = mSymbols.fCreateContext(dpy, config, share_context, attrib_list); AFTER_GL_CALL; return ctx; } EGLBoolean fDestroySurface(EGLDisplay dpy, EGLSurface surface) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fDestroySurface(dpy, surface); AFTER_GL_CALL; return b; } EGLSurface fCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) { BEFORE_GL_CALL; EGLSurface surf = mSymbols.fCreateWindowSurface(dpy, config, win, attrib_list); AFTER_GL_CALL; return surf; } EGLSurface fCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) { BEFORE_GL_CALL; EGLSurface surf = mSymbols.fCreatePbufferSurface(dpy, config, attrib_list); AFTER_GL_CALL; return surf; } EGLSurface fCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) { BEFORE_GL_CALL; EGLSurface surf = mSymbols.fCreatePixmapSurface(dpy, config, pixmap, attrib_list); AFTER_GL_CALL; return surf; } EGLBoolean fBindAPI(EGLenum api) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fBindAPI(api); AFTER_GL_CALL; return b; } EGLBoolean fInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fInitialize(dpy, major, minor); AFTER_GL_CALL; return b; } EGLBoolean fChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fChooseConfig(dpy, attrib_list, configs, config_size, num_config); AFTER_GL_CALL; return b; } EGLint fGetError() { BEFORE_GL_CALL; EGLint i = mSymbols.fGetError(); AFTER_GL_CALL; return i; } EGLBoolean fGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fGetConfigAttrib(dpy, config, attribute, value); AFTER_GL_CALL; return b; } EGLBoolean fGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fGetConfigs(dpy, configs, config_size, num_config); AFTER_GL_CALL; return b; } EGLBoolean fWaitNative(EGLint engine) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fWaitNative(engine); AFTER_GL_CALL; return b; } EGLCastToRelevantPtr fGetProcAddress(const char *procname) { BEFORE_GL_CALL; EGLCastToRelevantPtr p = mSymbols.fGetProcAddress(procname); AFTER_GL_CALL; return p; } EGLBoolean fSwapBuffers(EGLDisplay dpy, EGLSurface surface) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fSwapBuffers(dpy, surface); AFTER_GL_CALL; return b; } EGLBoolean fCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fCopyBuffers(dpy, surface, target); AFTER_GL_CALL; return b; } const GLubyte* fQueryString(EGLDisplay dpy, EGLint name) { BEFORE_GL_CALL; const GLubyte* b; if (mSymbols.fQueryStringImplementationANDROID) { b = mSymbols.fQueryStringImplementationANDROID(dpy, name); } else { b = mSymbols.fQueryString(dpy, name); } AFTER_GL_CALL; return b; } EGLBoolean fQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fQueryContext(dpy, ctx, attribute, value); AFTER_GL_CALL; return b; } EGLBoolean fBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fBindTexImage(dpy, surface, buffer); AFTER_GL_CALL; return b; } EGLBoolean fReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fReleaseTexImage(dpy, surface, buffer); AFTER_GL_CALL; return b; } EGLImage fCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) { BEFORE_GL_CALL; EGLImage i = mSymbols.fCreateImage(dpy, ctx, target, buffer, attrib_list); AFTER_GL_CALL; return i; } EGLBoolean fDestroyImage(EGLDisplay dpy, EGLImage image) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fDestroyImage(dpy, image); AFTER_GL_CALL; return b; } // New extension which allow us to lock texture and get raw image pointer EGLBoolean fLockSurface(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fLockSurface(dpy, surface, attrib_list); AFTER_GL_CALL; return b; } EGLBoolean fUnlockSurface(EGLDisplay dpy, EGLSurface surface) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fUnlockSurface(dpy, surface); AFTER_GL_CALL; return b; } EGLBoolean fQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fQuerySurface(dpy, surface, attribute, value); AFTER_GL_CALL; return b; } EGLBoolean fQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fQuerySurfacePointerANGLE(dpy, surface, attribute, value); AFTER_GL_CALL; return b; } EGLSync fCreateSync(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) { BEFORE_GL_CALL; EGLSync ret = mSymbols.fCreateSync(dpy, type, attrib_list); AFTER_GL_CALL; return ret; } EGLBoolean fDestroySync(EGLDisplay dpy, EGLSync sync) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fDestroySync(dpy, sync); AFTER_GL_CALL; return b; } EGLint fClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) { BEFORE_GL_CALL; EGLint ret = mSymbols.fClientWaitSync(dpy, sync, flags, timeout); AFTER_GL_CALL; return ret; } EGLBoolean fGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLint *value) { BEFORE_GL_CALL; EGLBoolean b = mSymbols.fGetSyncAttrib(dpy, sync, attribute, value); AFTER_GL_CALL; return b; } EGLint fDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSync sync) { MOZ_ASSERT(mSymbols.fDupNativeFenceFDANDROID); BEFORE_GL_CALL; EGLint ret = mSymbols.fDupNativeFenceFDANDROID(dpy, sync); AFTER_GL_CALL; return ret; } EGLDisplay Display() { return mEGLDisplay; } bool IsANGLE() const { return mIsANGLE; } bool HasKHRImageBase() { return IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_base); } bool HasKHRImagePixmap() { return IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_pixmap); } bool HasKHRImageTexture2D() { return IsExtensionSupported(KHR_gl_texture_2D_image); } bool HasANGLESurfaceD3DTexture2DShareHandle() { return IsExtensionSupported(ANGLE_surface_d3d_texture_2d_share_handle); } bool HasRobustness() const { return IsExtensionSupported(EXT_create_context_robustness); } bool EnsureInitialized(); void DumpEGLConfig(EGLConfig cfg); void DumpEGLConfigs(); struct { typedef EGLDisplay (GLAPIENTRY * pfnGetDisplay)(void *display_id); pfnGetDisplay fGetDisplay; typedef EGLBoolean (GLAPIENTRY * pfnTerminate)(EGLDisplay dpy); pfnTerminate fTerminate; typedef EGLSurface (GLAPIENTRY * pfnGetCurrentSurface)(EGLint); pfnGetCurrentSurface fGetCurrentSurface; typedef EGLContext (GLAPIENTRY * pfnGetCurrentContext)(void); pfnGetCurrentContext fGetCurrentContext; typedef EGLBoolean (GLAPIENTRY * pfnMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); pfnMakeCurrent fMakeCurrent; typedef EGLBoolean (GLAPIENTRY * pfnDestroyContext)(EGLDisplay dpy, EGLContext ctx); pfnDestroyContext fDestroyContext; typedef EGLContext (GLAPIENTRY * pfnCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); pfnCreateContext fCreateContext; typedef EGLBoolean (GLAPIENTRY * pfnDestroySurface)(EGLDisplay dpy, EGLSurface surface); pfnDestroySurface fDestroySurface; typedef EGLSurface (GLAPIENTRY * pfnCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); pfnCreateWindowSurface fCreateWindowSurface; typedef EGLSurface (GLAPIENTRY * pfnCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); pfnCreatePbufferSurface fCreatePbufferSurface; typedef EGLSurface (GLAPIENTRY * pfnCreatePixmapSurface)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list); pfnCreatePixmapSurface fCreatePixmapSurface; typedef EGLBoolean (GLAPIENTRY * pfnBindAPI)(EGLenum api); pfnBindAPI fBindAPI; typedef EGLBoolean (GLAPIENTRY * pfnInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor); pfnInitialize fInitialize; typedef EGLBoolean (GLAPIENTRY * pfnChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); pfnChooseConfig fChooseConfig; typedef EGLint (GLAPIENTRY * pfnGetError)(void); pfnGetError fGetError; typedef EGLBoolean (GLAPIENTRY * pfnGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); pfnGetConfigAttrib fGetConfigAttrib; typedef EGLBoolean (GLAPIENTRY * pfnGetConfigs)(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); pfnGetConfigs fGetConfigs; typedef EGLBoolean (GLAPIENTRY * pfnWaitNative)(EGLint engine); pfnWaitNative fWaitNative; typedef EGLCastToRelevantPtr (GLAPIENTRY * pfnGetProcAddress)(const char *procname); pfnGetProcAddress fGetProcAddress; typedef EGLBoolean (GLAPIENTRY * pfnSwapBuffers)(EGLDisplay dpy, EGLSurface surface); pfnSwapBuffers fSwapBuffers; typedef EGLBoolean (GLAPIENTRY * pfnCopyBuffers)(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target); pfnCopyBuffers fCopyBuffers; typedef const GLubyte* (GLAPIENTRY * pfnQueryString)(EGLDisplay, EGLint name); pfnQueryString fQueryString; pfnQueryString fQueryStringImplementationANDROID; typedef EGLBoolean (GLAPIENTRY * pfnQueryContext)(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value); pfnQueryContext fQueryContext; typedef EGLBoolean (GLAPIENTRY * pfnBindTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer); pfnBindTexImage fBindTexImage; typedef EGLBoolean (GLAPIENTRY * pfnReleaseTexImage)(EGLDisplay, EGLSurface surface, EGLint buffer); pfnReleaseTexImage fReleaseTexImage; typedef EGLImage (GLAPIENTRY * pfnCreateImage)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); pfnCreateImage fCreateImage; typedef EGLBoolean (GLAPIENTRY * pfnDestroyImage)(EGLDisplay dpy, EGLImage image); pfnDestroyImage fDestroyImage; // New extension which allow us to lock texture and get raw image pointer typedef EGLBoolean (GLAPIENTRY * pfnLockSurface)(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list); pfnLockSurface fLockSurface; typedef EGLBoolean (GLAPIENTRY * pfnUnlockSurface)(EGLDisplay dpy, EGLSurface surface); pfnUnlockSurface fUnlockSurface; typedef EGLBoolean (GLAPIENTRY * pfnQuerySurface)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); pfnQuerySurface fQuerySurface; typedef EGLBoolean (GLAPIENTRY * pfnQuerySurfacePointerANGLE)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value); pfnQuerySurfacePointerANGLE fQuerySurfacePointerANGLE; typedef EGLSync (GLAPIENTRY * pfnCreateSync)(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); pfnCreateSync fCreateSync; typedef EGLBoolean (GLAPIENTRY * pfnDestroySync)(EGLDisplay dpy, EGLSync sync); pfnDestroySync fDestroySync; typedef EGLint (GLAPIENTRY * pfnClientWaitSync)(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout); pfnClientWaitSync fClientWaitSync; typedef EGLBoolean (GLAPIENTRY * pfnGetSyncAttrib)(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLint *value); pfnGetSyncAttrib fGetSyncAttrib; typedef EGLint (GLAPIENTRY * pfnDupNativeFenceFDANDROID)(EGLDisplay dpy, EGLSync sync); pfnDupNativeFenceFDANDROID fDupNativeFenceFDANDROID; } mSymbols; #ifdef DEBUG static void BeforeGLCall(const char* glFunction); static void AfterGLCall(const char* glFunction); #endif #ifdef MOZ_B2G EGLContext CachedCurrentContext() { return sCurrentContext.get(); } void UnsetCachedCurrentContext() { sCurrentContext.set(nullptr); } void SetCachedCurrentContext(EGLContext aCtx) { sCurrentContext.set(aCtx); } bool CachedCurrentContextMatches() { return sCurrentContext.get() == fGetCurrentContext(); } private: static ThreadLocal sCurrentContext; public: #else EGLContext CachedCurrentContext() { return nullptr; } void UnsetCachedCurrentContext() {} void SetCachedCurrentContext(EGLContext aCtx) { } bool CachedCurrentContextMatches() { return true; } #endif private: bool mInitialized; PRLibrary* mEGLLibrary; EGLDisplay mEGLDisplay; bool mIsANGLE; }; extern GLLibraryEGL sEGLLibrary; #define EGL_DISPLAY() sEGLLibrary.Display() } /* namespace gl */ } /* namespace mozilla */ #endif /* GLLIBRARYEGL_H_ */