diff -up firefox-60.0.1/gfx/gl/GLContextEGL.h.mozilla-1462642 firefox-60.0.1/gfx/gl/GLContextEGL.h --- firefox-60.0.1/gfx/gl/GLContextEGL.h.mozilla-1462642 2018-05-16 07:38:29.000000000 +0200 +++ firefox-60.0.1/gfx/gl/GLContextEGL.h 2018-05-25 10:54:09.271902218 +0200 @@ -133,6 +133,10 @@ protected: static EGLSurface CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config, EGLenum bindToTextureFormat, gfx::IntSize& pbsize); +#if defined(MOZ_WAYLAND) + static EGLSurface CreateWaylandBufferSurface(EGLConfig config, + gfx::IntSize& pbsize); +#endif #if defined(MOZ_WIDGET_ANDROID) public: EGLSurface CreateCompatibleSurface(void* aWindow); diff -up firefox-60.0.1/gfx/gl/GLContextProviderEGL.cpp.mozilla-1462642 firefox-60.0.1/gfx/gl/GLContextProviderEGL.cpp --- firefox-60.0.1/gfx/gl/GLContextProviderEGL.cpp.mozilla-1462642 2018-05-25 10:54:09.258902265 +0200 +++ firefox-60.0.1/gfx/gl/GLContextProviderEGL.cpp 2018-05-25 10:55:57.634553279 +0200 @@ -63,6 +63,17 @@ #include "ScopedGLHelpers.h" #include "TextureImageEGL.h" +#if defined(MOZ_WAYLAND) +#include "nsAutoPtr.h" +#include "nsDataHashtable.h" + +#include +#include +#include +#include +#include +#endif + using namespace mozilla::gfx; namespace mozilla { @@ -70,6 +81,35 @@ namespace gl { using namespace mozilla::widget; +#if defined(MOZ_WAYLAND) +class WaylandGLSurface { +public: + WaylandGLSurface(struct wl_surface *aWaylandSurface, + struct wl_egl_window *aEGLWindow); + ~WaylandGLSurface(); +private: + struct wl_surface *mWaylandSurface; + struct wl_egl_window *mEGLWindow; +}; + +static nsDataHashtable, WaylandGLSurface*> + sWaylandGLSurface; + +void +DeleteWaylandGLSurface(EGLSurface surface) +{ + // We're running on Wayland which means our EGLSurface may + // have attached Wayland backend data which must be released. + if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) { + auto entry = sWaylandGLSurface.Lookup(surface); + if (entry) { + delete entry.Data(); + entry.Remove(); + } + } +} +#endif + #define ADD_ATTR_2(_array, _k, _v) do { \ (_array).AppendElement(_k); \ (_array).AppendElement(_v); \ @@ -125,6 +165,9 @@ DestroySurface(EGLSurface oldSurface) { EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); sEGLLibrary.fDestroySurface(EGL_DISPLAY(), oldSurface); +#if defined(MOZ_WAYLAND) + DeleteWaylandGLSurface(oldSurface); +#endif } } @@ -588,6 +631,52 @@ TRY_AGAIN_POWER_OF_TWO: return surface; } +#if defined(MOZ_WAYLAND) +WaylandGLSurface::WaylandGLSurface(struct wl_surface *aWaylandSurface, + struct wl_egl_window *aEGLWindow) + : mWaylandSurface(aWaylandSurface) + , mEGLWindow(aEGLWindow) +{ +} + +WaylandGLSurface::~WaylandGLSurface() +{ + wl_egl_window_destroy(mEGLWindow); + wl_surface_destroy(mWaylandSurface); +} + +EGLSurface +GLContextEGL::CreateWaylandBufferSurface(EGLConfig config, + mozilla::gfx::IntSize& pbsize) +{ + // Available as of GTK 3.8+ + static auto sGdkWaylandDisplayGetWlCompositor = + (wl_compositor *(*)(GdkDisplay *)) + dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_compositor"); + + if (!sGdkWaylandDisplayGetWlCompositor) + return nullptr; + + struct wl_compositor *compositor = + sGdkWaylandDisplayGetWlCompositor(gdk_display_get_default()); + struct wl_surface *wlsurface = wl_compositor_create_surface(compositor); + struct wl_egl_window *eglwindow = + wl_egl_window_create(wlsurface, pbsize.width, pbsize.height); + + EGLSurface surface = + sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, eglwindow, 0); + + if (surface) { + WaylandGLSurface* waylandData = + new WaylandGLSurface(wlsurface, eglwindow); + auto entry = sWaylandGLSurface.LookupForAdd(surface); + entry.OrInsert([&waylandData](){ return waylandData; }); + } + + return surface; +} +#endif + static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = { LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT, LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, @@ -807,7 +896,17 @@ FillContextAttribs(bool alpha, bool dept bool es3, nsTArray* out) { out->AppendElement(LOCAL_EGL_SURFACE_TYPE); +#if defined(MOZ_WAYLAND) + if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) { + // Wayland on desktop does not support PBuffer or FBO. + // We create a dummy wl_egl_window instead. + out->AppendElement(LOCAL_EGL_WINDOW_BIT); + } else { + out->AppendElement(LOCAL_EGL_PBUFFER_BIT); + } +#else out->AppendElement(LOCAL_EGL_PBUFFER_BIT); +#endif out->AppendElement(LOCAL_EGL_RENDERABLE_TYPE); if (es3) { @@ -926,9 +1025,17 @@ GLContextEGL::CreateEGLPBufferOffscreenC } mozilla::gfx::IntSize pbSize(size); - EGLSurface surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config, - LOCAL_EGL_NONE, - pbSize); + EGLSurface surface = nullptr; +#if defined(MOZ_WAYLAND) + if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) { + surface = GLContextEGL::CreateWaylandBufferSurface(config, pbSize); + } else +#endif + { + surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config, + LOCAL_EGL_NONE, + pbSize); + } if (!surface) { *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_POT"); NS_WARNING("Failed to create PBuffer for context!"); @@ -941,6 +1048,9 @@ GLContextEGL::CreateEGLPBufferOffscreenC if (!gl) { NS_WARNING("Failed to create GLContext from PBuffer"); sEGLLibrary.fDestroySurface(sEGLLibrary.Display(), surface); +#if defined(MOZ_WAYLAND) + DeleteWaylandGLSurface(surface); +#endif return nullptr; }