diff options
Diffstat (limited to 'Source/WebCore/platform/graphics/egl')
4 files changed, 361 insertions, 118 deletions
diff --git a/Source/WebCore/platform/graphics/egl/GLContextEGL.cpp b/Source/WebCore/platform/graphics/egl/GLContextEGL.cpp index 329131601..a086efa98 100644 --- a/Source/WebCore/platform/graphics/egl/GLContextEGL.cpp +++ b/Source/WebCore/platform/graphics/egl/GLContextEGL.cpp @@ -22,7 +22,8 @@ #if USE(EGL) #include "GraphicsContext3D.h" -#include <wtf/OwnPtr.h> +#include "PlatformDisplay.h" +#include <EGL/egl.h> #if USE(CAIRO) #include <cairo.h> @@ -45,30 +46,6 @@ namespace WebCore { -static EGLDisplay gSharedEGLDisplay = EGL_NO_DISPLAY; - -#if USE(OPENGL_ES_2) -static const EGLenum gGLAPI = EGL_OPENGL_ES_API; -#else -static const EGLenum gGLAPI = EGL_OPENGL_API; -#endif - -static EGLDisplay sharedEGLDisplay() -{ - static bool initialized = false; - if (!initialized) { - initialized = true; -#if PLATFORM(X11) - gSharedEGLDisplay = eglGetDisplay(GLContext::sharedX11Display()); -#else - gSharedEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); -#endif - if (gSharedEGLDisplay != EGL_NO_DISPLAY && (!eglInitialize(gSharedEGLDisplay, 0, 0) || !eglBindAPI(gGLAPI))) - gSharedEGLDisplay = EGL_NO_DISPLAY; - } - return gSharedEGLDisplay; -} - static const EGLint gContextAttributes[] = { #if USE(OPENGL_ES_2) EGL_CONTEXT_CLIENT_VERSION, 2, @@ -76,7 +53,13 @@ static const EGLint gContextAttributes[] = { EGL_NONE }; -static bool getEGLConfig(EGLConfig* config, GLContextEGL::EGLSurfaceType surfaceType) +#if USE(OPENGL_ES_2) +static const EGLenum gEGLAPIVersion = EGL_OPENGL_ES_API; +#else +static const EGLenum gEGLAPIVersion = EGL_OPENGL_API; +#endif + +bool GLContextEGL::getEGLConfig(EGLDisplay display, EGLConfig* config, EGLSurfaceType surfaceType) { EGLint attributeList[] = { #if USE(OPENGL_ES_2) @@ -101,45 +84,52 @@ static bool getEGLConfig(EGLConfig* config, GLContextEGL::EGLSurfaceType surface attributeList[13] = EGL_PIXMAP_BIT; break; case GLContextEGL::WindowSurface: + case GLContextEGL::Surfaceless: attributeList[13] = EGL_WINDOW_BIT; break; } EGLint numberConfigsReturned; - return eglChooseConfig(sharedEGLDisplay(), attributeList, config, 1, &numberConfigsReturned) && numberConfigsReturned; + return eglChooseConfig(display, attributeList, config, 1, &numberConfigsReturned) && numberConfigsReturned; } -PassOwnPtr<GLContextEGL> GLContextEGL::createWindowContext(EGLNativeWindowType window, GLContext* sharingContext) +std::unique_ptr<GLContextEGL> GLContextEGL::createWindowContext(GLNativeWindowType window, PlatformDisplay& platformDisplay, EGLContext sharingContext) { - EGLContext eglSharingContext = sharingContext ? static_cast<GLContextEGL*>(sharingContext)->m_context : 0; - - EGLDisplay display = sharedEGLDisplay(); - if (display == EGL_NO_DISPLAY) - return nullptr; - + EGLDisplay display = platformDisplay.eglDisplay(); EGLConfig config; - if (!getEGLConfig(&config, WindowSurface)) + if (!getEGLConfig(display, &config, WindowSurface)) return nullptr; - EGLContext context = eglCreateContext(display, config, eglSharingContext, gContextAttributes); + EGLContext context = eglCreateContext(display, config, sharingContext, gContextAttributes); if (context == EGL_NO_CONTEXT) return nullptr; - EGLSurface surface = eglCreateWindowSurface(display, config, window, 0); - if (surface == EGL_NO_SURFACE) + EGLSurface surface = EGL_NO_SURFACE; +#if PLATFORM(GTK) +#if PLATFORM(X11) + if (platformDisplay.type() == PlatformDisplay::Type::X11) + surface = createWindowSurfaceX11(display, config, window); +#endif +#if PLATFORM(WAYLAND) + if (platformDisplay.type() == PlatformDisplay::Type::Wayland) + surface = createWindowSurfaceWayland(display, config, window); +#endif +#else + surface = eglCreateWindowSurface(display, config, static_cast<EGLNativeWindowType>(window), nullptr); +#endif + if (surface == EGL_NO_SURFACE) { + eglDestroyContext(display, context); return nullptr; + } - return adoptPtr(new GLContextEGL(context, surface, WindowSurface)); + return std::unique_ptr<GLContextEGL>(new GLContextEGL(platformDisplay, context, surface, WindowSurface)); } -PassOwnPtr<GLContextEGL> GLContextEGL::createPbufferContext(EGLContext sharingContext) +std::unique_ptr<GLContextEGL> GLContextEGL::createPbufferContext(PlatformDisplay& platformDisplay, EGLContext sharingContext) { - EGLDisplay display = sharedEGLDisplay(); - if (display == EGL_NO_DISPLAY) - return nullptr; - + EGLDisplay display = platformDisplay.eglDisplay(); EGLConfig config; - if (!getEGLConfig(&config, PbufferSurface)) + if (!getEGLConfig(display, &config, PbufferSurface)) return nullptr; EGLContext context = eglCreateContext(display, config, sharingContext, gContextAttributes); @@ -153,78 +143,91 @@ PassOwnPtr<GLContextEGL> GLContextEGL::createPbufferContext(EGLContext sharingCo return nullptr; } - return adoptPtr(new GLContextEGL(context, surface, PbufferSurface)); + return std::unique_ptr<GLContextEGL>(new GLContextEGL(platformDisplay, context, surface, PbufferSurface)); } -PassOwnPtr<GLContextEGL> GLContextEGL::createPixmapContext(EGLContext sharingContext) +std::unique_ptr<GLContextEGL> GLContextEGL::createSurfacelessContext(PlatformDisplay& platformDisplay, EGLContext sharingContext) { -#if PLATFORM(X11) - EGLDisplay display = sharedEGLDisplay(); + EGLDisplay display = platformDisplay.eglDisplay(); if (display == EGL_NO_DISPLAY) return nullptr; + const char* extensions = eglQueryString(display, EGL_EXTENSIONS); + if (!GLContext::isExtensionSupported(extensions, "EGL_KHR_surfaceless_context") && !GLContext::isExtensionSupported(extensions, "EGL_KHR_surfaceless_opengl")) + return nullptr; + EGLConfig config; - if (!getEGLConfig(&config, PixmapSurface)) + if (!getEGLConfig(display, &config, Surfaceless)) return nullptr; EGLContext context = eglCreateContext(display, config, sharingContext, gContextAttributes); if (context == EGL_NO_CONTEXT) return nullptr; - EGLint depth; - if (!eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depth)) - return nullptr; + return std::unique_ptr<GLContextEGL>(new GLContextEGL(platformDisplay, context, EGL_NO_SURFACE, Surfaceless)); +} - Pixmap pixmap = XCreatePixmap(sharedX11Display(), DefaultRootWindow(sharedX11Display()), 1, 1, depth); - if (!pixmap) +std::unique_ptr<GLContextEGL> GLContextEGL::createContext(GLNativeWindowType window, PlatformDisplay& platformDisplay) +{ + if (platformDisplay.eglDisplay() == EGL_NO_DISPLAY) return nullptr; - EGLSurface surface = eglCreatePixmapSurface(display, config, pixmap, 0); - - if (surface == EGL_NO_SURFACE) + if (eglBindAPI(gEGLAPIVersion) == EGL_FALSE) return nullptr; - return adoptPtr(new GLContextEGL(context, surface, PixmapSurface)); -#else - return nullptr; + EGLContext eglSharingContext = platformDisplay.sharingGLContext() ? static_cast<GLContextEGL*>(platformDisplay.sharingGLContext())->m_context : EGL_NO_CONTEXT; + auto context = window ? createWindowContext(window, platformDisplay, eglSharingContext) : nullptr; + if (!context) + context = createSurfacelessContext(platformDisplay, eglSharingContext); + if (!context) { +#if PLATFORM(X11) + if (platformDisplay.type() == PlatformDisplay::Type::X11) + context = createPixmapContext(platformDisplay, eglSharingContext); +#endif +#if PLATFORM(WAYLAND) + if (platformDisplay.type() == PlatformDisplay::Type::Wayland) + context = createWaylandContext(platformDisplay, eglSharingContext); #endif + } + if (!context) + context = createPbufferContext(platformDisplay, eglSharingContext); + + return context; } -PassOwnPtr<GLContextEGL> GLContextEGL::createContext(EGLNativeWindowType window, GLContext* sharingContext) +std::unique_ptr<GLContextEGL> GLContextEGL::createSharingContext(PlatformDisplay& platformDisplay) { - if (!sharedEGLDisplay()) + if (platformDisplay.eglDisplay() == EGL_NO_DISPLAY) return nullptr; - static bool initialized = false; - static bool success = true; - if (!initialized) { -#if !USE(OPENGL_ES_2) - success = initializeOpenGLShims(); -#endif - initialized = true; - } - if (!success) + if (eglBindAPI(gEGLAPIVersion) == EGL_FALSE) return nullptr; - EGLContext eglSharingContext = sharingContext ? static_cast<GLContextEGL*>(sharingContext)->m_context : 0; - OwnPtr<GLContextEGL> context = window ? createWindowContext(window, sharingContext) : nullptr; + auto context = createSurfacelessContext(platformDisplay); + if (!context) { +#if PLATFORM(X11) + if (platformDisplay.type() == PlatformDisplay::Type::X11) + context = createPixmapContext(platformDisplay); +#endif +#if PLATFORM(WAYLAND) + if (platformDisplay.type() == PlatformDisplay::Type::Wayland) + context = createWaylandContext(platformDisplay); +#endif + } if (!context) - context = createPixmapContext(eglSharingContext); + context = createPbufferContext(platformDisplay); - if (!context) - context = createPbufferContext(eglSharingContext); - - return context.release(); + return context; } -GLContextEGL::GLContextEGL(EGLContext context, EGLSurface surface, EGLSurfaceType type) - : m_context(context) +GLContextEGL::GLContextEGL(PlatformDisplay& display, EGLContext context, EGLSurface surface, EGLSurfaceType type) + : GLContext(display) + , m_context(context) , m_surface(surface) , m_type(type) -#if USE(CAIRO) - , m_cairoDevice(0) -#endif { + ASSERT(type != PixmapSurface); + ASSERT(type == Surfaceless || surface != EGL_NO_SURFACE); } GLContextEGL::~GLContextEGL() @@ -234,7 +237,7 @@ GLContextEGL::~GLContextEGL() cairo_device_destroy(m_cairoDevice); #endif - EGLDisplay display = sharedEGLDisplay(); + EGLDisplay display = m_display.eglDisplay(); if (m_context) { glBindFramebuffer(GL_FRAMEBUFFER, 0); eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); @@ -243,6 +246,10 @@ GLContextEGL::~GLContextEGL() if (m_surface) eglDestroySurface(display, m_surface); + +#if PLATFORM(WAYLAND) + destroyWaylandWindow(); +#endif } bool GLContextEGL::canRenderToDefaultFramebuffer() @@ -255,9 +262,10 @@ IntSize GLContextEGL::defaultFrameBufferSize() if (!canRenderToDefaultFramebuffer()) return IntSize(); + EGLDisplay display = m_display.eglDisplay(); EGLint width, height; - if (!eglQuerySurface(sharedEGLDisplay(), m_surface, EGL_WIDTH, &width) - || !eglQuerySurface(sharedEGLDisplay(), m_surface, EGL_HEIGHT, &height)) + if (!eglQuerySurface(display, m_surface, EGL_WIDTH, &width) + || !eglQuerySurface(display, m_surface, EGL_HEIGHT, &height)) return IntSize(); return IntSize(width, height); @@ -265,19 +273,19 @@ IntSize GLContextEGL::defaultFrameBufferSize() bool GLContextEGL::makeContextCurrent() { - ASSERT(m_context && m_surface); + ASSERT(m_context); GLContext::makeContextCurrent(); if (eglGetCurrentContext() == m_context) return true; - return eglMakeCurrent(sharedEGLDisplay(), m_surface, m_surface, m_context); + return eglMakeCurrent(m_display.eglDisplay(), m_surface, m_surface, m_context); } void GLContextEGL::swapBuffers() { ASSERT(m_surface); - eglSwapBuffers(sharedEGLDisplay(), m_surface); + eglSwapBuffers(m_display.eglDisplay(), m_surface); } void GLContextEGL::waitNative() @@ -285,6 +293,12 @@ void GLContextEGL::waitNative() eglWaitNative(EGL_CORE_NATIVE_ENGINE); } +void GLContextEGL::swapInterval(int interval) +{ + ASSERT(m_surface); + eglSwapInterval(m_display.eglDisplay(), interval); +} + #if USE(CAIRO) cairo_device_t* GLContextEGL::cairoDevice() { @@ -292,14 +306,14 @@ cairo_device_t* GLContextEGL::cairoDevice() return m_cairoDevice; #if ENABLE(ACCELERATED_2D_CANVAS) - m_cairoDevice = cairo_egl_device_create(sharedEGLDisplay(), m_context); + m_cairoDevice = cairo_egl_device_create(m_display.eglDisplay(), m_context); #endif return m_cairoDevice; } #endif -#if ENABLE(WEBGL) +#if ENABLE(GRAPHICS_CONTEXT_3D) PlatformGraphicsContext3D GLContextEGL::platformContext() { return m_context; diff --git a/Source/WebCore/platform/graphics/egl/GLContextEGL.h b/Source/WebCore/platform/graphics/egl/GLContextEGL.h index c887e0beb..e5a33597d 100644 --- a/Source/WebCore/platform/graphics/egl/GLContextEGL.h +++ b/Source/WebCore/platform/graphics/egl/GLContextEGL.h @@ -17,57 +17,92 @@ * Boston, MA 02110-1301 USA */ -#ifndef GLContextEGL_h -#define GLContextEGL_h +#pragma once #if USE(EGL) #include "GLContext.h" -#include <EGL/egl.h> +#if PLATFORM(X11) +#include "XUniqueResource.h" +#endif + +#if PLATFORM(WAYLAND) +#include "WlUniquePtr.h" +struct wl_egl_window; +#endif + +typedef void *EGLConfig; +typedef void *EGLContext; +typedef void *EGLDisplay; +typedef void *EGLSurface; namespace WebCore { -class GLContextEGL : public GLContext { +class GLContextEGL final : public GLContext { WTF_MAKE_NONCOPYABLE(GLContextEGL); public: - enum EGLSurfaceType { PbufferSurface, WindowSurface, PixmapSurface }; - static PassOwnPtr<GLContextEGL> createContext(EGLNativeWindowType, GLContext* sharingContext = 0); - static PassOwnPtr<GLContextEGL> createWindowContext(EGLNativeWindowType, GLContext* sharingContext); + static std::unique_ptr<GLContextEGL> createContext(GLNativeWindowType, PlatformDisplay&); + static std::unique_ptr<GLContextEGL> createSharingContext(PlatformDisplay&); virtual ~GLContextEGL(); - virtual bool makeContextCurrent(); - virtual void swapBuffers(); - virtual void waitNative(); - virtual bool canRenderToDefaultFramebuffer(); - virtual IntSize defaultFrameBufferSize(); + +private: + bool makeContextCurrent() override; + void swapBuffers() override; + void waitNative() override; + bool canRenderToDefaultFramebuffer() override; + IntSize defaultFrameBufferSize() override; + void swapInterval(int) override; #if USE(CAIRO) - virtual cairo_device_t* cairoDevice(); + cairo_device_t* cairoDevice() override; #endif + bool isEGLContext() const override { return true; } -#if ENABLE(WEBGL) - virtual PlatformGraphicsContext3D platformContext(); +#if ENABLE(GRAPHICS_CONTEXT_3D) + PlatformGraphicsContext3D platformContext() override; #endif -private: - static PassOwnPtr<GLContextEGL> createPbufferContext(EGLContext sharingContext); - static PassOwnPtr<GLContextEGL> createPixmapContext(EGLContext sharingContext); + enum EGLSurfaceType { PbufferSurface, WindowSurface, PixmapSurface, Surfaceless }; - static void addActiveContext(GLContextEGL*); - static void cleanupSharedEGLDisplay(void); + GLContextEGL(PlatformDisplay&, EGLContext, EGLSurface, EGLSurfaceType); +#if PLATFORM(X11) + GLContextEGL(PlatformDisplay&, EGLContext, EGLSurface, XUniquePixmap&&); +#endif +#if PLATFORM(WAYLAND) + GLContextEGL(PlatformDisplay&, EGLContext, EGLSurface, WlUniquePtr<struct wl_surface>&&, struct wl_egl_window*); + void destroyWaylandWindow(); +#endif + + static std::unique_ptr<GLContextEGL> createWindowContext(GLNativeWindowType, PlatformDisplay&, EGLContext sharingContext = nullptr); + static std::unique_ptr<GLContextEGL> createPbufferContext(PlatformDisplay&, EGLContext sharingContext = nullptr); + static std::unique_ptr<GLContextEGL> createSurfacelessContext(PlatformDisplay&, EGLContext sharingContext = nullptr); +#if PLATFORM(X11) + static std::unique_ptr<GLContextEGL> createPixmapContext(PlatformDisplay&, EGLContext sharingContext = nullptr); + static EGLSurface createWindowSurfaceX11(EGLDisplay, EGLConfig, GLNativeWindowType); +#endif +#if PLATFORM(WAYLAND) + static std::unique_ptr<GLContextEGL> createWaylandContext(PlatformDisplay&, EGLContext sharingContext = nullptr); + static EGLSurface createWindowSurfaceWayland(EGLDisplay, EGLConfig, GLNativeWindowType); +#endif - GLContextEGL(EGLContext, EGLSurface, EGLSurfaceType); + static bool getEGLConfig(EGLDisplay, EGLConfig*, EGLSurfaceType); - EGLContext m_context; - EGLSurface m_surface; + EGLContext m_context { nullptr }; + EGLSurface m_surface { nullptr }; EGLSurfaceType m_type; +#if PLATFORM(X11) + XUniquePixmap m_pixmap; +#endif +#if PLATFORM(WAYLAND) + WlUniquePtr<struct wl_surface> m_wlSurface; + struct wl_egl_window* m_wlWindow { nullptr }; +#endif #if USE(CAIRO) - cairo_device_t* m_cairoDevice; + cairo_device_t* m_cairoDevice { nullptr }; #endif }; } // namespace WebCore #endif // USE(EGL) - -#endif // GLContextEGL_h diff --git a/Source/WebCore/platform/graphics/egl/GLContextEGLWayland.cpp b/Source/WebCore/platform/graphics/egl/GLContextEGLWayland.cpp new file mode 100644 index 000000000..a0ed56fd9 --- /dev/null +++ b/Source/WebCore/platform/graphics/egl/GLContextEGLWayland.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2016 Igalia, S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "GLContextEGL.h" + +#if USE(EGL) && PLATFORM(WAYLAND) + +#include "PlatformDisplayWayland.h" +// These includes need to be in this order because wayland-egl.h defines WL_EGL_PLATFORM +// and egl.h checks that to decide whether it's Wayland platform. +#include <wayland-egl.h> +#include <EGL/egl.h> + +namespace WebCore { + +GLContextEGL::GLContextEGL(PlatformDisplay& display, EGLContext context, EGLSurface surface, WlUniquePtr<struct wl_surface>&& wlSurface, struct wl_egl_window* wlWindow) + : GLContext(display) + , m_context(context) + , m_surface(surface) + , m_type(WindowSurface) + , m_wlSurface(WTFMove(wlSurface)) + , m_wlWindow(wlWindow) +{ +} + +EGLSurface GLContextEGL::createWindowSurfaceWayland(EGLDisplay display, EGLConfig config, GLNativeWindowType window) +{ + return eglCreateWindowSurface(display, config, reinterpret_cast<EGLNativeWindowType>(window), nullptr); +} + +std::unique_ptr<GLContextEGL> GLContextEGL::createWaylandContext(PlatformDisplay& platformDisplay, EGLContext sharingContext) +{ + EGLDisplay display = platformDisplay.eglDisplay(); + EGLConfig config; + if (!getEGLConfig(display, &config, WindowSurface)) + return nullptr; + + static const EGLint contextAttributes[] = { +#if USE(OPENGL_ES_2) + EGL_CONTEXT_CLIENT_VERSION, 2, +#endif + EGL_NONE + }; + + EGLContext context = eglCreateContext(display, config, sharingContext, contextAttributes); + if (context == EGL_NO_CONTEXT) + return nullptr; + + WlUniquePtr<struct wl_surface> wlSurface(downcast<PlatformDisplayWayland>(platformDisplay).createSurface()); + if (!wlSurface) { + eglDestroyContext(display, context); + return nullptr; + } + + EGLNativeWindowType window = wl_egl_window_create(wlSurface.get(), 1, 1); + EGLSurface surface = eglCreateWindowSurface(display, config, window, 0); + if (surface == EGL_NO_SURFACE) { + eglDestroyContext(display, context); + wl_egl_window_destroy(window); + return nullptr; + } + + return std::unique_ptr<GLContextEGL>(new GLContextEGL(platformDisplay, context, surface, WTFMove(wlSurface), window)); +} + +void GLContextEGL::destroyWaylandWindow() +{ + if (m_wlWindow) + wl_egl_window_destroy(m_wlWindow); +} + +} // namespace WebCore + +#endif // USE(EGL) && PLATFORM(WAYLAND) diff --git a/Source/WebCore/platform/graphics/egl/GLContextEGLX11.cpp b/Source/WebCore/platform/graphics/egl/GLContextEGLX11.cpp new file mode 100644 index 000000000..8fdd4cad3 --- /dev/null +++ b/Source/WebCore/platform/graphics/egl/GLContextEGLX11.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016 Igalia, S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "GLContextEGL.h" + +#if USE(EGL) && PLATFORM(X11) +#include "PlatformDisplayX11.h" +#include "XErrorTrapper.h" +#include "XUniquePtr.h" +#include <EGL/egl.h> +#include <X11/Xlib.h> + +namespace WebCore { + +GLContextEGL::GLContextEGL(PlatformDisplay& display, EGLContext context, EGLSurface surface, XUniquePixmap&& pixmap) + : GLContext(display) + , m_context(context) + , m_surface(surface) + , m_type(PixmapSurface) + , m_pixmap(WTFMove(pixmap)) +{ +} + +EGLSurface GLContextEGL::createWindowSurfaceX11(EGLDisplay display, EGLConfig config, GLNativeWindowType window) +{ + return eglCreateWindowSurface(display, config, static_cast<EGLNativeWindowType>(window), nullptr); +} + +std::unique_ptr<GLContextEGL> GLContextEGL::createPixmapContext(PlatformDisplay& platformDisplay, EGLContext sharingContext) +{ + EGLDisplay display = platformDisplay.eglDisplay(); + EGLConfig config; + if (!getEGLConfig(display, &config, PixmapSurface)) + return nullptr; + + static const EGLint contextAttributes[] = { +#if USE(OPENGL_ES_2) + EGL_CONTEXT_CLIENT_VERSION, 2, +#endif + EGL_NONE + }; + EGLContext context = eglCreateContext(display, config, sharingContext, contextAttributes); + if (context == EGL_NO_CONTEXT) + return nullptr; + + EGLint visualId; + if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualId)) { + eglDestroyContext(display, context); + return nullptr; + } + + Display* x11Display = downcast<PlatformDisplayX11>(platformDisplay).native(); + + XVisualInfo visualInfo; + visualInfo.visualid = visualId; + int numVisuals = 0; + XUniquePtr<XVisualInfo> visualInfoList(XGetVisualInfo(x11Display, VisualIDMask, &visualInfo, &numVisuals)); + if (!visualInfoList || !numVisuals) { + eglDestroyContext(display, context); + return nullptr; + } + + // We are using VisualIDMask so there must be only one. + ASSERT(numVisuals == 1); + XUniquePixmap pixmap = XCreatePixmap(x11Display, DefaultRootWindow(x11Display), 1, 1, visualInfoList.get()[0].depth); + if (!pixmap) { + eglDestroyContext(display, context); + return nullptr; + } + + // Some drivers fail to create the surface producing BadDrawable X error and the default XError handler normally aborts. + // However, if the X error is ignored, eglCreatePixmapSurface() ends up returning a surface and we can continue creating + // the context. Since this is an offscreen context, it doesn't matter if the pixmap used is not valid because we never do + // swap buffers. So, we use a custom XError handler here that ignores BadDrawable errors and only warns about any other + // errors without aborting in any case. + XErrorTrapper trapper(x11Display, XErrorTrapper::Policy::Warn, { BadDrawable }); + EGLSurface surface = eglCreatePixmapSurface(display, config, reinterpret_cast<EGLNativePixmapType>(pixmap.get()), 0); + if (surface == EGL_NO_SURFACE) { + eglDestroyContext(display, context); + return nullptr; + } + + return std::unique_ptr<GLContextEGL>(new GLContextEGL(platformDisplay, context, surface, WTFMove(pixmap))); +} + +} // namespace WebCore + +#endif // USE(EGL) && PLATFORM(X11) |