Source code

Revision control

Copy as Markdown

Other Tools

/* 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_ */