diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/gl/GLLibraryEGL.h | 993 |
1 files changed, 993 insertions, 0 deletions
diff --git a/gfx/gl/GLLibraryEGL.h b/gfx/gl/GLLibraryEGL.h new file mode 100644 index 0000000000..de296508bb --- /dev/null +++ b/gfx/gl/GLLibraryEGL.h @@ -0,0 +1,993 @@ +/* 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 "base/platform_thread.h" // for PlatformThreadId +#include "gfxEnv.h" +#include "GLContext.h" +#include "mozilla/EnumTypeTraits.h" +#include "mozilla/gfx/Logging.h" +#include "mozilla/Maybe.h" +#include "mozilla/Mutex.h" +#include "mozilla/RefPtr.h" +#include "mozilla/StaticMutex.h" +#include "mozilla/StaticPtr.h" +#include "nsISupports.h" +#include "prlink.h" + +#include <bitset> +#include <memory> +#include <unordered_map> + +#ifdef MOZ_WIDGET_ANDROID +# include "mozilla/ProfilerLabels.h" +# include "AndroidBuild.h" +#endif + +#if defined(MOZ_X11) +# define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)mozilla::DefaultXDisplay()) +#else +# define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) +#endif + +struct ID3D11Device; + +extern "C" { +struct AHardwareBuffer; +} + +namespace angle { +class Platform; +} + +namespace mozilla { + +namespace gfx { +class DataSourceSurface; +} + +namespace gl { + +class SymbolLoader; + +PRLibrary* LoadApitraceLibrary(); + +void BeforeEGLCall(const char* funcName); +void AfterEGLCall(const char* funcName); + +class EglDisplay; +/** + * 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 GLLibraryEGL.cpp. + */ +enum class EGLLibExtension { + ANDROID_get_native_client_buffer, + ANGLE_device_creation, + ANGLE_device_creation_d3d11, + ANGLE_platform_angle, + ANGLE_platform_angle_d3d, + EXT_device_enumeration, + EXT_device_query, + EXT_platform_device, + MESA_platform_surfaceless, + Max +}; + +/** + * 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 GLLibraryEGL.cpp. + */ +enum class EGLExtension { + KHR_image_base, + KHR_image_pixmap, + KHR_gl_texture_2D_image, + ANGLE_surface_d3d_texture_2d_share_handle, + EXT_create_context_robustness, + KHR_image, + KHR_fence_sync, + KHR_wait_sync, + ANDROID_native_fence_sync, + EGL_ANDROID_image_crop, + ANGLE_d3d_share_handle_client_buffer, + KHR_create_context, + KHR_stream, + KHR_stream_consumer_gltexture, + NV_stream_consumer_gltexture_yuv, + ANGLE_stream_producer_d3d_texture, + KHR_surfaceless_context, + KHR_create_context_no_error, + MOZ_create_context_provoking_vertex_dont_care, + EXT_swap_buffers_with_damage, + KHR_swap_buffers_with_damage, + EXT_buffer_age, + KHR_partial_update, + NV_robustness_video_memory_purge, + EXT_image_dma_buf_import, + EXT_image_dma_buf_import_modifiers, + MESA_image_dma_buf_export, + KHR_no_config_context, + Max +}; + +// - + +class GLLibraryEGL final { + friend class EglDisplay; + + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GLLibraryEGL) + + private: + PRLibrary* mEGLLibrary = nullptr; + PRLibrary* mGLLibrary = nullptr; + bool mIsANGLE = false; + std::bitset<UnderlyingValue(EGLLibExtension::Max)> mAvailableExtensions; + std::weak_ptr<EglDisplay> mDefaultDisplay; + std::unordered_map<EGLDisplay, std::weak_ptr<EglDisplay>> mActiveDisplays; + + public: + static RefPtr<GLLibraryEGL> Get(nsACString* const out_failureId); + static void Shutdown(); + + private: + ~GLLibraryEGL() = default; + + static StaticMutex sMutex; + static StaticRefPtr<GLLibraryEGL> sInstance MOZ_GUARDED_BY(sMutex); + + bool Init(nsACString* const out_failureId); + void InitLibExtensions(); + + std::shared_ptr<EglDisplay> CreateDisplayLocked( + bool forceAccel, nsACString* const out_failureId, + const StaticMutexAutoLock& aProofOfLock); + + public: + Maybe<SymbolLoader> GetSymbolLoader() const; + + std::shared_ptr<EglDisplay> CreateDisplay(bool forceAccel, + nsACString* const out_failureId); + std::shared_ptr<EglDisplay> CreateDisplay(ID3D11Device*); + std::shared_ptr<EglDisplay> DefaultDisplay(nsACString* const out_failureId); + + bool IsExtensionSupported(EGLLibExtension aKnownExtension) const { + return mAvailableExtensions[UnderlyingValue(aKnownExtension)]; + } + + void MarkExtensionUnsupported(EGLLibExtension aKnownExtension) { + mAvailableExtensions[UnderlyingValue(aKnownExtension)] = false; + } + + bool IsANGLE() const { return mIsANGLE; } + + // - + // PFN wrappers + +#ifdef MOZ_WIDGET_ANDROID +# define PROFILE_CALL AUTO_PROFILER_LABEL(__func__, GRAPHICS); +#else +# define PROFILE_CALL +#endif + +#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 DEBUG +# define BEFORE_CALL BeforeEGLCall(MOZ_FUNCTION_NAME); +# define AFTER_CALL AfterEGLCall(MOZ_FUNCTION_NAME); +#else +# define BEFORE_CALL +# define AFTER_CALL +#endif + +#define WRAP(X) \ + PROFILE_CALL \ + BEFORE_CALL \ + const auto ret = mSymbols.X; \ + AFTER_CALL \ + return ret + + public: + EGLDisplay fGetDisplay(void* display_id) const { + WRAP(fGetDisplay(display_id)); + } + + EGLDisplay fGetPlatformDisplay(EGLenum platform, void* native_display, + const EGLAttrib* attrib_list) const { + WRAP(fGetPlatformDisplay(platform, native_display, attrib_list)); + } + + EGLSurface fGetCurrentSurface(EGLint id) const { + WRAP(fGetCurrentSurface(id)); + } + + EGLContext fGetCurrentContext() const { WRAP(fGetCurrentContext()); } + + EGLBoolean fBindAPI(EGLenum api) const { WRAP(fBindAPI(api)); } + + EGLint fGetError() const { WRAP(fGetError()); } + + EGLBoolean fWaitNative(EGLint engine) const { WRAP(fWaitNative(engine)); } + + EGLCastToRelevantPtr fGetProcAddress(const char* procname) const { + WRAP(fGetProcAddress(procname)); + } + + // ANGLE_device_creation + EGLDeviceEXT fCreateDeviceANGLE(EGLint device_type, void* native_device, + const EGLAttrib* attrib_list) const { + WRAP(fCreateDeviceANGLE(device_type, native_device, attrib_list)); + } + + EGLBoolean fReleaseDeviceANGLE(EGLDeviceEXT device) { + WRAP(fReleaseDeviceANGLE(device)); + } + + // ANDROID_get_native_client_buffer + EGLClientBuffer fGetNativeClientBufferANDROID( + const struct AHardwareBuffer* buffer) { + WRAP(fGetNativeClientBufferANDROID(buffer)); + } + + private: + EGLBoolean fTerminate(EGLDisplay display) const { WRAP(fTerminate(display)); } + + // - + + mutable Mutex mMutex = Mutex{"GLLibraryEGL::mMutex"}; + mutable std::unordered_map<EGLContext, PlatformThreadId> + mOwningThreadByContext MOZ_GUARDED_BY(mMutex); + + EGLBoolean fMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, + EGLContext ctx) const { + const bool CHECK_CONTEXT_OWNERSHIP = true; + if (CHECK_CONTEXT_OWNERSHIP) { + const MutexAutoLock lock(mMutex); + const auto tid = PlatformThread::CurrentId(); + const auto prevCtx = fGetCurrentContext(); + + if (prevCtx) { + mOwningThreadByContext[prevCtx] = 0; + } + if (ctx) { + auto& ctxOwnerThread = mOwningThreadByContext[ctx]; + if (ctxOwnerThread && ctxOwnerThread != tid) { + gfxCriticalError() + << "EGLContext#" << ctx << " is owned by/Current on" + << " thread#" << ctxOwnerThread << " but MakeCurrent requested on" + << " thread#" << tid << "!"; + if (gfxEnv::MOZ_EGL_RELEASE_ASSERT_CONTEXT_OWNERSHIP()) { + MOZ_CRASH("MOZ_EGL_RELEASE_ASSERT_CONTEXT_OWNERSHIP"); + } + return false; + } + ctxOwnerThread = tid; + } + } + + // Always reset the TLS current context. + // If we're called by TLS-caching MakeCurrent, after we return true, + // the caller will set the TLS correctly anyway. + GLContext::ResetTLSCurrentContext(); + + WRAP(fMakeCurrent(dpy, draw, read, ctx)); + } + + // - + + EGLBoolean fDestroyContext(EGLDisplay dpy, EGLContext ctx) const { + { + const MutexAutoLock lock(mMutex); + mOwningThreadByContext.erase(ctx); + } + + WRAP(fDestroyContext(dpy, ctx)); + } + + EGLContext fCreateContext(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint* attrib_list) const { + WRAP(fCreateContext(dpy, config, share_context, attrib_list)); + } + + EGLBoolean fDestroySurface(EGLDisplay dpy, EGLSurface surface) const { + WRAP(fDestroySurface(dpy, surface)); + } + + public: + EGLSurface fCreateWindowSurface(EGLDisplay dpy, EGLConfig config, + EGLNativeWindowType win, + const EGLint* attrib_list) const { + WRAP(fCreateWindowSurface(dpy, config, win, attrib_list)); + } + + private: + EGLSurface fCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, + const EGLint* attrib_list) const { + WRAP(fCreatePbufferSurface(dpy, config, attrib_list)); + } + + EGLSurface fCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, + EGLClientBuffer buffer, + EGLConfig config, + const EGLint* attrib_list) const { + WRAP(fCreatePbufferFromClientBuffer(dpy, buftype, buffer, config, + attrib_list)); + } + + EGLSurface fCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, + EGLNativePixmapType pixmap, + const EGLint* attrib_list) const { + WRAP(fCreatePixmapSurface(dpy, config, pixmap, attrib_list)); + } + + EGLBoolean fInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) const { + WRAP(fInitialize(dpy, major, minor)); + } + + EGLBoolean fChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, + EGLConfig* configs, EGLint config_size, + EGLint* num_config) const { + WRAP(fChooseConfig(dpy, attrib_list, configs, config_size, num_config)); + } + + EGLBoolean fGetConfigAttrib(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint* value) const { + WRAP(fGetConfigAttrib(dpy, config, attribute, value)); + } + + EGLBoolean fGetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size, + EGLint* num_config) const { + WRAP(fGetConfigs(dpy, configs, config_size, num_config)); + } + + EGLBoolean fSwapBuffers(EGLDisplay dpy, EGLSurface surface) const { + WRAP(fSwapBuffers(dpy, surface)); + } + + EGLBoolean fCopyBuffers(EGLDisplay dpy, EGLSurface surface, + EGLNativePixmapType target) const { + WRAP(fCopyBuffers(dpy, surface, target)); + } + + public: + const GLubyte* fQueryString(EGLDisplay dpy, EGLint name) const { + WRAP(fQueryString(dpy, name)); + } + + private: + EGLBoolean fQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, + EGLint* value) const { + WRAP(fQueryContext(dpy, ctx, attribute, value)); + } + + EGLBoolean fBindTexImage(EGLDisplay dpy, EGLSurface surface, + EGLint buffer) const { + WRAP(fBindTexImage(dpy, surface, buffer)); + } + + EGLBoolean fReleaseTexImage(EGLDisplay dpy, EGLSurface surface, + EGLint buffer) const { + WRAP(fReleaseTexImage(dpy, surface, buffer)); + } + + EGLBoolean fSwapInterval(EGLDisplay dpy, EGLint interval) const { + WRAP(fSwapInterval(dpy, interval)); + } + + EGLImage fCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, + EGLClientBuffer buffer, + const EGLint* attrib_list) const { + WRAP(fCreateImageKHR(dpy, ctx, target, buffer, attrib_list)); + } + + EGLBoolean fDestroyImage(EGLDisplay dpy, EGLImage image) const { + WRAP(fDestroyImageKHR(dpy, image)); + } + + EGLBoolean fQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, + EGLint* value) const { + WRAP(fQuerySurface(dpy, surface, attribute, value)); + } + + EGLBoolean fQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, void** value) const { + WRAP(fQuerySurfacePointerANGLE(dpy, surface, attribute, value)); + } + + EGLSync fCreateSync(EGLDisplay dpy, EGLenum type, + const EGLint* attrib_list) const { + WRAP(fCreateSyncKHR(dpy, type, attrib_list)); + } + + EGLBoolean fDestroySync(EGLDisplay dpy, EGLSync sync) const { + WRAP(fDestroySyncKHR(dpy, sync)); + } + + EGLint fClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, + EGLTime timeout) const { + WRAP(fClientWaitSyncKHR(dpy, sync, flags, timeout)); + } + + EGLBoolean fGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, + EGLint* value) const { + WRAP(fGetSyncAttribKHR(dpy, sync, attribute, value)); + } + + EGLint fWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) const { + WRAP(fWaitSyncKHR(dpy, sync, flags)); + } + + EGLint fDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSync sync) const { + WRAP(fDupNativeFenceFDANDROID(dpy, sync)); + } + + // KHR_stream + EGLStreamKHR fCreateStreamKHR(EGLDisplay dpy, + const EGLint* attrib_list) const { + WRAP(fCreateStreamKHR(dpy, attrib_list)); + } + + EGLBoolean fDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) const { + WRAP(fDestroyStreamKHR(dpy, stream)); + } + + EGLBoolean fQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, + EGLenum attribute, EGLint* value) const { + WRAP(fQueryStreamKHR(dpy, stream, attribute, value)); + } + + // KHR_stream_consumer_gltexture + EGLBoolean fStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, + EGLStreamKHR stream) const { + WRAP(fStreamConsumerGLTextureExternalKHR(dpy, stream)); + } + + EGLBoolean fStreamConsumerAcquireKHR(EGLDisplay dpy, + EGLStreamKHR stream) const { + WRAP(fStreamConsumerAcquireKHR(dpy, stream)); + } + + EGLBoolean fStreamConsumerReleaseKHR(EGLDisplay dpy, + EGLStreamKHR stream) const { + WRAP(fStreamConsumerReleaseKHR(dpy, stream)); + } + + // EXT_device_query + EGLBoolean fQueryDisplayAttribEXT(EGLDisplay dpy, EGLint attribute, + EGLAttrib* value) const { + WRAP(fQueryDisplayAttribEXT(dpy, attribute, value)); + } + + public: + EGLBoolean fQueryDeviceAttribEXT(EGLDeviceEXT device, EGLint attribute, + EGLAttrib* value) const { + WRAP(fQueryDeviceAttribEXT(device, attribute, value)); + } + + const char* fQueryDeviceStringEXT(EGLDeviceEXT device, EGLint name) { + WRAP(fQueryDeviceStringEXT(device, name)); + } + + private: + // NV_stream_consumer_gltexture_yuv + EGLBoolean fStreamConsumerGLTextureExternalAttribsNV( + EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib* attrib_list) const { + WRAP(fStreamConsumerGLTextureExternalAttribsNV(dpy, stream, attrib_list)); + } + + // ANGLE_stream_producer_d3d_texture + EGLBoolean fCreateStreamProducerD3DTextureANGLE( + EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib* attrib_list) const { + WRAP(fCreateStreamProducerD3DTextureANGLE(dpy, stream, attrib_list)); + } + + EGLBoolean fStreamPostD3DTextureANGLE(EGLDisplay dpy, EGLStreamKHR stream, + void* texture, + const EGLAttrib* attrib_list) const { + WRAP(fStreamPostD3DTextureANGLE(dpy, stream, texture, attrib_list)); + } + + // EGL_EXT_swap_buffers_with_damage / EGL_KHR_swap_buffers_with_damage + EGLBoolean fSwapBuffersWithDamage(EGLDisplay dpy, EGLSurface surface, + const EGLint* rects, EGLint n_rects) { + WRAP(fSwapBuffersWithDamage(dpy, surface, rects, n_rects)); + } + + // EGL_KHR_partial_update + EGLBoolean fSetDamageRegion(EGLDisplay dpy, EGLSurface surface, + const EGLint* rects, EGLint n_rects) { + WRAP(fSetDamageRegion(dpy, surface, rects, n_rects)); + } + // EGL_MESA_image_dma_buf_export + EGLBoolean fExportDMABUFImageQuery(EGLDisplay dpy, EGLImage image, + int* fourcc, int* num_planes, + uint64_t* modifiers) { + WRAP( + fExportDMABUFImageQueryMESA(dpy, image, fourcc, num_planes, modifiers)); + } + EGLBoolean fExportDMABUFImage(EGLDisplay dpy, EGLImage image, int* fds, + EGLint* strides, EGLint* offsets) { + WRAP(fExportDMABUFImageMESA(dpy, image, fds, strides, offsets)); + } + + public: + // EGL_EXT_device_enumeration + EGLBoolean fQueryDevicesEXT(EGLint max_devices, EGLDeviceEXT* devices, + EGLint* num_devices) { + WRAP(fQueryDevicesEXT(max_devices, devices, num_devices)); + } + +#undef WRAP + +#undef WRAP +#undef PROFILE_CALL +#undef BEFORE_CALL +#undef AFTER_CALL +#undef MOZ_FUNCTION_NAME + + //// + + private: + struct { + EGLCastToRelevantPtr(GLAPIENTRY* fGetProcAddress)(const char* procname); + EGLDisplay(GLAPIENTRY* fGetDisplay)(void* display_id); + EGLDisplay(GLAPIENTRY* fGetPlatformDisplay)(EGLenum platform, + void* native_display, + const EGLAttrib* attrib_list); + EGLBoolean(GLAPIENTRY* fTerminate)(EGLDisplay dpy); + EGLSurface(GLAPIENTRY* fGetCurrentSurface)(EGLint); + EGLContext(GLAPIENTRY* fGetCurrentContext)(void); + EGLBoolean(GLAPIENTRY* fMakeCurrent)(EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx); + EGLBoolean(GLAPIENTRY* fDestroyContext)(EGLDisplay dpy, EGLContext ctx); + EGLContext(GLAPIENTRY* fCreateContext)(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint* attrib_list); + EGLBoolean(GLAPIENTRY* fDestroySurface)(EGLDisplay dpy, EGLSurface surface); + EGLSurface(GLAPIENTRY* fCreateWindowSurface)(EGLDisplay dpy, + EGLConfig config, + EGLNativeWindowType win, + const EGLint* attrib_list); + EGLSurface(GLAPIENTRY* fCreatePbufferSurface)(EGLDisplay dpy, + EGLConfig config, + const EGLint* attrib_list); + EGLSurface(GLAPIENTRY* fCreatePbufferFromClientBuffer)( + EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint* attrib_list); + EGLSurface(GLAPIENTRY* fCreatePixmapSurface)(EGLDisplay dpy, + EGLConfig config, + EGLNativePixmapType pixmap, + const EGLint* attrib_list); + EGLBoolean(GLAPIENTRY* fBindAPI)(EGLenum api); + EGLBoolean(GLAPIENTRY* fInitialize)(EGLDisplay dpy, EGLint* major, + EGLint* minor); + EGLBoolean(GLAPIENTRY* fChooseConfig)(EGLDisplay dpy, + const EGLint* attrib_list, + EGLConfig* configs, + EGLint config_size, + EGLint* num_config); + EGLint(GLAPIENTRY* fGetError)(void); + EGLBoolean(GLAPIENTRY* fGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint* value); + EGLBoolean(GLAPIENTRY* fGetConfigs)(EGLDisplay dpy, EGLConfig* configs, + EGLint config_size, EGLint* num_config); + EGLBoolean(GLAPIENTRY* fWaitNative)(EGLint engine); + EGLBoolean(GLAPIENTRY* fSwapBuffers)(EGLDisplay dpy, EGLSurface surface); + EGLBoolean(GLAPIENTRY* fCopyBuffers)(EGLDisplay dpy, EGLSurface surface, + EGLNativePixmapType target); + const GLubyte*(GLAPIENTRY* fQueryString)(EGLDisplay, EGLint name); + EGLBoolean(GLAPIENTRY* fQueryContext)(EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint* value); + EGLBoolean(GLAPIENTRY* fBindTexImage)(EGLDisplay, EGLSurface surface, + EGLint buffer); + EGLBoolean(GLAPIENTRY* fReleaseTexImage)(EGLDisplay, EGLSurface surface, + EGLint buffer); + EGLBoolean(GLAPIENTRY* fSwapInterval)(EGLDisplay dpy, EGLint interval); + EGLImage(GLAPIENTRY* fCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, + EGLenum target, + EGLClientBuffer buffer, + const EGLint* attrib_list); + EGLBoolean(GLAPIENTRY* fDestroyImageKHR)(EGLDisplay dpy, EGLImage image); + EGLBoolean(GLAPIENTRY* fQuerySurface)(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint* value); + EGLBoolean(GLAPIENTRY* fQuerySurfacePointerANGLE)(EGLDisplay dpy, + EGLSurface surface, + EGLint attribute, + void** value); + EGLSync(GLAPIENTRY* fCreateSyncKHR)(EGLDisplay dpy, EGLenum type, + const EGLint* attrib_list); + EGLBoolean(GLAPIENTRY* fDestroySyncKHR)(EGLDisplay dpy, EGLSync sync); + EGLint(GLAPIENTRY* fClientWaitSyncKHR)(EGLDisplay dpy, EGLSync sync, + EGLint flags, EGLTime timeout); + EGLBoolean(GLAPIENTRY* fGetSyncAttribKHR)(EGLDisplay dpy, EGLSync sync, + EGLint attribute, EGLint* value); + EGLint(GLAPIENTRY* fWaitSyncKHR)(EGLDisplay dpy, EGLSync sync, + EGLint flags); + EGLint(GLAPIENTRY* fDupNativeFenceFDANDROID)(EGLDisplay dpy, EGLSync sync); + // KHR_stream + EGLStreamKHR(GLAPIENTRY* fCreateStreamKHR)(EGLDisplay dpy, + const EGLint* attrib_list); + EGLBoolean(GLAPIENTRY* fDestroyStreamKHR)(EGLDisplay dpy, + EGLStreamKHR stream); + EGLBoolean(GLAPIENTRY* fQueryStreamKHR)(EGLDisplay dpy, EGLStreamKHR stream, + EGLenum attribute, EGLint* value); + // KHR_stream_consumer_gltexture + EGLBoolean(GLAPIENTRY* fStreamConsumerGLTextureExternalKHR)( + EGLDisplay dpy, EGLStreamKHR stream); + EGLBoolean(GLAPIENTRY* fStreamConsumerAcquireKHR)(EGLDisplay dpy, + EGLStreamKHR stream); + EGLBoolean(GLAPIENTRY* fStreamConsumerReleaseKHR)(EGLDisplay dpy, + EGLStreamKHR stream); + // EXT_device_query + EGLBoolean(GLAPIENTRY* fQueryDisplayAttribEXT)(EGLDisplay dpy, + EGLint attribute, + EGLAttrib* value); + EGLBoolean(GLAPIENTRY* fQueryDeviceAttribEXT)(EGLDeviceEXT device, + EGLint attribute, + EGLAttrib* value); + const char*(GLAPIENTRY* fQueryDeviceStringEXT)(EGLDeviceEXT device, + EGLint name); + + // NV_stream_consumer_gltexture_yuv + EGLBoolean(GLAPIENTRY* fStreamConsumerGLTextureExternalAttribsNV)( + EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib* attrib_list); + // ANGLE_stream_producer_d3d_texture + EGLBoolean(GLAPIENTRY* fCreateStreamProducerD3DTextureANGLE)( + EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib* attrib_list); + EGLBoolean(GLAPIENTRY* fStreamPostD3DTextureANGLE)( + EGLDisplay dpy, EGLStreamKHR stream, void* texture, + const EGLAttrib* attrib_list); + // ANGLE_device_creation + EGLDeviceEXT(GLAPIENTRY* fCreateDeviceANGLE)(EGLint device_type, + void* native_device, + const EGLAttrib* attrib_list); + EGLBoolean(GLAPIENTRY* fReleaseDeviceANGLE)(EGLDeviceEXT device); + // EGL_EXT_swap_buffers_with_damage / EGL_KHR_swap_buffers_with_damage + EGLBoolean(GLAPIENTRY* fSwapBuffersWithDamage)(EGLDisplay dpy, + EGLSurface surface, + const EGLint* rects, + EGLint n_rects); + // EGL_KHR_partial_update + EGLBoolean(GLAPIENTRY* fSetDamageRegion)(EGLDisplay dpy, EGLSurface surface, + const EGLint* rects, + EGLint n_rects); + EGLClientBuffer(GLAPIENTRY* fGetNativeClientBufferANDROID)( + const struct AHardwareBuffer* buffer); + + // EGL_MESA_image_dma_buf_export + EGLBoolean(GLAPIENTRY* fExportDMABUFImageQueryMESA)(EGLDisplay dpy, + EGLImage image, + int* fourcc, + int* num_planes, + uint64_t* modifiers); + EGLBoolean(GLAPIENTRY* fExportDMABUFImageMESA)(EGLDisplay dpy, + EGLImage image, int* fds, + EGLint* strides, + EGLint* offsets); + + EGLBoolean(GLAPIENTRY* fQueryDevicesEXT)(EGLint max_devices, + EGLDeviceEXT* devices, + EGLint* num_devices); + + } mSymbols = {}; +}; + +static bool ShouldLeakEglDisplay() { + // We are seeing crashes in eglTerminate on the Samsung S22 family of devices + // running Android 14, so we leak the EGLDisplay rather than call + // eglTerminate. +#ifdef MOZ_WIDGET_ANDROID + if (jni::GetAPIVersion() >= 34) { + const auto board = java::sdk::Build::BOARD()->ToString(); + if (board.EqualsASCII("s5e9925")) { + return true; + } + } +#endif + return false; +} + +class EglDisplay final { + public: + const RefPtr<GLLibraryEGL> mLib; + const EGLDisplay mDisplay; + const bool mIsWARP; + + private: + std::bitset<UnderlyingValue(EGLExtension::Max)> mAvailableExtensions; + + struct PrivateUseOnly final {}; + + public: + static std::shared_ptr<EglDisplay> Create( + GLLibraryEGL&, EGLDisplay, bool isWarp, + const StaticMutexAutoLock& aProofOfLock); + + // Only `public` for make_shared. + EglDisplay(const PrivateUseOnly&, GLLibraryEGL&, EGLDisplay, bool isWarp); + + public: + ~EglDisplay(); + + bool IsExtensionSupported(EGLExtension aKnownExtension) const { + return mAvailableExtensions[UnderlyingValue(aKnownExtension)]; + } + + void MarkExtensionUnsupported(EGLExtension aKnownExtension) { + mAvailableExtensions[UnderlyingValue(aKnownExtension)] = false; + } + + void DumpEGLConfig(EGLConfig) const; + void DumpEGLConfigs() const; + + void Shutdown(); + + // - + + bool HasKHRImageBase() const { + return IsExtensionSupported(EGLExtension::KHR_image) || + IsExtensionSupported(EGLExtension::KHR_image_base); + } + + bool HasKHRImagePixmap() const { + return IsExtensionSupported(EGLExtension::KHR_image) || + IsExtensionSupported(EGLExtension::KHR_image_pixmap); + } + + // - + + EGLBoolean fTerminate() { + static const bool shouldLeak = ShouldLeakEglDisplay(); + if (shouldLeak) { + return LOCAL_EGL_TRUE; + } + return mLib->fTerminate(mDisplay); + } + + EGLBoolean fMakeCurrent(EGLSurface draw, EGLSurface read, + EGLContext ctx) const { + return mLib->fMakeCurrent(mDisplay, draw, read, ctx); + } + + EGLBoolean fDestroyContext(EGLContext ctx) const { + return mLib->fDestroyContext(mDisplay, ctx); + } + + EGLContext fCreateContext(EGLConfig config, EGLContext share_context, + const EGLint* attrib_list) const { + return mLib->fCreateContext(mDisplay, config, share_context, attrib_list); + } + + EGLBoolean fDestroySurface(EGLSurface surface) const { + return mLib->fDestroySurface(mDisplay, surface); + } + + EGLSurface fCreateWindowSurface(EGLConfig config, EGLNativeWindowType win, + const EGLint* attrib_list) const { + return mLib->fCreateWindowSurface(mDisplay, config, win, attrib_list); + } + + EGLSurface fCreatePbufferSurface(EGLConfig config, + const EGLint* attrib_list) const { + return mLib->fCreatePbufferSurface(mDisplay, config, attrib_list); + } + + EGLSurface fCreatePbufferFromClientBuffer(EGLenum buftype, + EGLClientBuffer buffer, + EGLConfig config, + const EGLint* attrib_list) const { + return mLib->fCreatePbufferFromClientBuffer(mDisplay, buftype, buffer, + config, attrib_list); + } + + EGLBoolean fChooseConfig(const EGLint* attrib_list, EGLConfig* configs, + EGLint config_size, EGLint* num_config) const { + return mLib->fChooseConfig(mDisplay, attrib_list, configs, config_size, + num_config); + } + + EGLBoolean fGetConfigAttrib(EGLConfig config, EGLint attribute, + EGLint* value) const { + return mLib->fGetConfigAttrib(mDisplay, config, attribute, value); + } + + EGLBoolean fGetConfigs(EGLConfig* configs, EGLint config_size, + EGLint* num_config) const { + return mLib->fGetConfigs(mDisplay, configs, config_size, num_config); + } + + EGLBoolean fSwapBuffers(EGLSurface surface) const { + return mLib->fSwapBuffers(mDisplay, surface); + } + + EGLBoolean fBindTexImage(EGLSurface surface, EGLint buffer) const { + return mLib->fBindTexImage(mDisplay, surface, buffer); + } + + EGLBoolean fReleaseTexImage(EGLSurface surface, EGLint buffer) const { + return mLib->fReleaseTexImage(mDisplay, surface, buffer); + } + + EGLBoolean fSwapInterval(EGLint interval) const { + return mLib->fSwapInterval(mDisplay, interval); + } + + EGLImage fCreateImage(EGLContext ctx, EGLenum target, EGLClientBuffer buffer, + const EGLint* attribList) const { + MOZ_ASSERT(HasKHRImageBase()); + return mLib->fCreateImage(mDisplay, ctx, target, buffer, attribList); + } + + EGLBoolean fDestroyImage(EGLImage image) const { + MOZ_ASSERT(HasKHRImageBase()); + return mLib->fDestroyImage(mDisplay, image); + } + + EGLBoolean fQuerySurface(EGLSurface surface, EGLint attribute, + EGLint* value) const { + return mLib->fQuerySurface(mDisplay, surface, attribute, value); + } + + EGLBoolean fQuerySurfacePointerANGLE(EGLSurface surface, EGLint attribute, + void** value) const { + MOZ_ASSERT(IsExtensionSupported( + EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle)); + return mLib->fQuerySurfacePointerANGLE(mDisplay, surface, attribute, value); + } + + EGLSync fCreateSync(EGLenum type, const EGLint* attrib_list) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_fence_sync)); + return mLib->fCreateSync(mDisplay, type, attrib_list); + } + + EGLBoolean fDestroySync(EGLSync sync) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_fence_sync)); + return mLib->fDestroySync(mDisplay, sync); + } + + EGLint fClientWaitSync(EGLSync sync, EGLint flags, EGLTime timeout) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_fence_sync)); + return mLib->fClientWaitSync(mDisplay, sync, flags, timeout); + } + + EGLBoolean fGetSyncAttrib(EGLSync sync, EGLint attribute, + EGLint* value) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_fence_sync)); + return mLib->fGetSyncAttrib(mDisplay, sync, attribute, value); + } + + EGLint fWaitSync(EGLSync sync, EGLint flags) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_wait_sync)); + return mLib->fWaitSync(mDisplay, sync, flags); + } + + EGLint fDupNativeFenceFDANDROID(EGLSync sync) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::ANDROID_native_fence_sync)); + return mLib->fDupNativeFenceFDANDROID(mDisplay, sync); + } + + // EXT_device_query + EGLBoolean fQueryDisplayAttribEXT(EGLint attribute, EGLAttrib* value) const { + MOZ_ASSERT(mLib->IsExtensionSupported(EGLLibExtension::EXT_device_query)); + return mLib->fQueryDisplayAttribEXT(mDisplay, attribute, value); + } + + // KHR_stream + EGLStreamKHR fCreateStreamKHR(const EGLint* attrib_list) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_stream)); + return mLib->fCreateStreamKHR(mDisplay, attrib_list); + } + + EGLBoolean fDestroyStreamKHR(EGLStreamKHR stream) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_stream)); + return mLib->fDestroyStreamKHR(mDisplay, stream); + } + + EGLBoolean fQueryStreamKHR(EGLStreamKHR stream, EGLenum attribute, + EGLint* value) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_stream)); + return mLib->fQueryStreamKHR(mDisplay, stream, attribute, value); + } + + // KHR_stream_consumer_gltexture + EGLBoolean fStreamConsumerGLTextureExternalKHR(EGLStreamKHR stream) const { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::KHR_stream_consumer_gltexture)); + return mLib->fStreamConsumerGLTextureExternalKHR(mDisplay, stream); + } + + EGLBoolean fStreamConsumerAcquireKHR(EGLStreamKHR stream) const { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::KHR_stream_consumer_gltexture)); + return mLib->fStreamConsumerAcquireKHR(mDisplay, stream); + } + + EGLBoolean fStreamConsumerReleaseKHR(EGLStreamKHR stream) const { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::KHR_stream_consumer_gltexture)); + return mLib->fStreamConsumerReleaseKHR(mDisplay, stream); + } + + // NV_stream_consumer_gltexture_yuv + EGLBoolean fStreamConsumerGLTextureExternalAttribsNV( + EGLStreamKHR stream, const EGLAttrib* attrib_list) const { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::NV_stream_consumer_gltexture_yuv)); + return mLib->fStreamConsumerGLTextureExternalAttribsNV(mDisplay, stream, + attrib_list); + } + + // ANGLE_stream_producer_d3d_texture + EGLBoolean fCreateStreamProducerD3DTextureANGLE( + EGLStreamKHR stream, const EGLAttrib* attrib_list) const { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::ANGLE_stream_producer_d3d_texture)); + return mLib->fCreateStreamProducerD3DTextureANGLE(mDisplay, stream, + attrib_list); + } + + EGLBoolean fStreamPostD3DTextureANGLE(EGLStreamKHR stream, void* texture, + const EGLAttrib* attrib_list) const { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::ANGLE_stream_producer_d3d_texture)); + return mLib->fStreamPostD3DTextureANGLE(mDisplay, stream, texture, + attrib_list); + } + + // EGL_EXT_swap_buffers_with_damage / EGL_KHR_swap_buffers_with_damage + EGLBoolean fSwapBuffersWithDamage(EGLSurface surface, const EGLint* rects, + EGLint n_rects) { + MOZ_ASSERT( + IsExtensionSupported(EGLExtension::EXT_swap_buffers_with_damage) || + IsExtensionSupported(EGLExtension::KHR_swap_buffers_with_damage)); + return mLib->fSwapBuffersWithDamage(mDisplay, surface, rects, n_rects); + } + + // EGL_KHR_partial_update + EGLBoolean fSetDamageRegion(EGLSurface surface, const EGLint* rects, + EGLint n_rects) { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::KHR_partial_update)); + return mLib->fSetDamageRegion(mDisplay, surface, rects, n_rects); + } + + EGLBoolean fExportDMABUFImageQuery(EGLImage image, int* fourcc, + int* num_planes, + uint64_t* modifiers) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::MESA_image_dma_buf_export)); + return mLib->fExportDMABUFImageQuery(mDisplay, image, fourcc, num_planes, + modifiers); + } + EGLBoolean fExportDMABUFImage(EGLImage image, int* fds, EGLint* strides, + EGLint* offsets) const { + MOZ_ASSERT(IsExtensionSupported(EGLExtension::MESA_image_dma_buf_export)); + return mLib->fExportDMABUFImage(mDisplay, image, fds, strides, offsets); + } +}; + +} /* namespace gl */ +} /* namespace mozilla */ + +#endif /* GLLIBRARYEGL_H_ */ |