--- a/gfx/gl/GLContextEGL.h
+++ b/gfx/gl/GLContextEGL.h
@@ -129,16 +129,20 @@ protected:
bool mIsDoubleBuffered;
bool mCanBindToTexture;
bool mShareWithEGLImage;
bool mOwnsContext;
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);
#endif // defined(MOZ_WIDGET_ANDROID)
};
bool CreateConfig(EGLConfig* config, int32_t depth, bool enableDepthBuffer);
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -58,23 +58,63 @@
#include "mozilla/layers/CompositorOptions.h"
#include "mozilla/widget/CompositorWidget.h"
#include "nsDebug.h"
#include "nsIWidget.h"
#include "nsThreadUtils.h"
#include "ScopedGLHelpers.h"
#include "TextureImageEGL.h"
+#if defined(MOZ_WAYLAND)
+#include "nsAutoPtr.h"
+#include "nsDataHashtable.h"
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkwayland.h>
+#include <wayland-egl.h>
+#include <dlfcn.h>
+#endif
+
using namespace mozilla::gfx;
namespace mozilla {
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<nsPtrHashKey<void>, 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); \
} while (0)
#define ADD_ATTR_1(_array, _k) do { \
(_array).AppendElement(_k); \
} while (0)
@@ -120,16 +160,19 @@ is_power_of_two(int v)
static void
DestroySurface(EGLSurface oldSurface) {
if (oldSurface != EGL_NO_SURFACE) {
// TODO: This breaks TLS MakeCurrent caching.
sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), oldSurface);
+#if defined(MOZ_WAYLAND)
+ DeleteWaylandGLSurface(oldSurface);
+#endif
}
}
static EGLSurface
CreateFallbackSurface(const EGLConfig& config)
{
if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_surfaceless_context)) {
// We don't need a PBuffer surface in this case
@@ -617,16 +660,62 @@ TRY_AGAIN_POWER_OF_TWO:
NS_WARNING("Failed to create pbuffer surface");
return nullptr;
}
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,
// Old versions of llvmpipe seem to need this to properly create the pbuffer (bug 981856)
LOCAL_EGL_RED_SIZE, 8,
LOCAL_EGL_GREEN_SIZE, 8,
LOCAL_EGL_BLUE_SIZE, 8,
LOCAL_EGL_ALPHA_SIZE, 0,
@@ -836,17 +925,27 @@ GLContextProviderEGL::DestroyEGLSurface(
}
#endif // defined(ANDROID)
static void
FillContextAttribs(bool alpha, bool depth, bool stencil, bool bpp16,
bool es3, nsTArray<EGLint>* 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) {
out->AppendElement(LOCAL_EGL_OPENGL_ES3_BIT_KHR);
} else {
out->AppendElement(LOCAL_EGL_OPENGL_ES2_BIT);
}
@@ -955,31 +1054,42 @@ GLContextEGL::CreateEGLPBufferOffscreenC
return nullptr;
}
if (GLContext::ShouldSpew()) {
sEGLLibrary.DumpEGLConfig(config);
}
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!");
return nullptr;
}
RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(flags, configCaps, true,
config, surface,
out_failureId);
if (!gl) {
NS_WARNING("Failed to create GLContext from PBuffer");
sEGLLibrary.fDestroySurface(sEGLLibrary.Display(), surface);
+#if defined(MOZ_WAYLAND)
+ DeleteWaylandGLSurface(surface);
+#endif
return nullptr;
}
return gl.forget();
}
/*static*/ already_AddRefed<GLContext>
GLContextProviderEGL::CreateHeadless(CreateContextFlags flags,