1/*
2 * Copyright (C) 2016 Igalia, S.L.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include "config.h"
20#include "GLContextEGL.h"
21
22#if USE(EGL) && PLATFORM(X11)
23#include "PlatformDisplayX11.h"
24#include "XErrorTrapper.h"
25#include "XUniquePtr.h"
26#include <EGL/egl.h>
27#include <X11/Xlib.h>
28
29namespace WebCore {
30
31GLContextEGL::GLContextEGL(PlatformDisplay& display, EGLContext context, EGLSurface surface, XUniquePixmap&& pixmap)
32 : GLContext(display)
33 , m_context(context)
34 , m_surface(surface)
35 , m_type(PixmapSurface)
36 , m_pixmap(WTFMove(pixmap))
37{
38}
39
40EGLSurface GLContextEGL::createWindowSurfaceX11(EGLDisplay display, EGLConfig config, GLNativeWindowType window)
41{
42 return eglCreateWindowSurface(display, config, static_cast<EGLNativeWindowType>(window), nullptr);
43}
44
45std::unique_ptr<GLContextEGL> GLContextEGL::createPixmapContext(PlatformDisplay& platformDisplay, EGLContext sharingContext)
46{
47 EGLDisplay display = platformDisplay.eglDisplay();
48 EGLConfig config;
49 if (!getEGLConfig(display, &config, PixmapSurface))
50 return nullptr;
51
52 EGLContext context = createContextForEGLVersion(platformDisplay, config, sharingContext);
53 if (context == EGL_NO_CONTEXT)
54 return nullptr;
55
56 EGLint visualId;
57 if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualId)) {
58 eglDestroyContext(display, context);
59 return nullptr;
60 }
61
62 Display* x11Display = downcast<PlatformDisplayX11>(platformDisplay).native();
63
64 XVisualInfo visualInfo;
65 visualInfo.visualid = visualId;
66 int numVisuals = 0;
67 XUniquePtr<XVisualInfo> visualInfoList(XGetVisualInfo(x11Display, VisualIDMask, &visualInfo, &numVisuals));
68 if (!visualInfoList || !numVisuals) {
69 eglDestroyContext(display, context);
70 return nullptr;
71 }
72
73 // We are using VisualIDMask so there must be only one.
74 ASSERT(numVisuals == 1);
75 XUniquePixmap pixmap = XCreatePixmap(x11Display, DefaultRootWindow(x11Display), 1, 1, visualInfoList.get()[0].depth);
76 if (!pixmap) {
77 eglDestroyContext(display, context);
78 return nullptr;
79 }
80
81 // Some drivers fail to create the surface producing BadDrawable X error and the default XError handler normally aborts.
82 // However, if the X error is ignored, eglCreatePixmapSurface() ends up returning a surface and we can continue creating
83 // the context. Since this is an offscreen context, it doesn't matter if the pixmap used is not valid because we never do
84 // swap buffers. So, we use a custom XError handler here that ignores BadDrawable errors and only warns about any other
85 // errors without aborting in any case.
86 XErrorTrapper trapper(x11Display, XErrorTrapper::Policy::Warn, { BadDrawable });
87 EGLSurface surface = eglCreatePixmapSurface(display, config, reinterpret_cast<EGLNativePixmapType>(pixmap.get()), 0);
88 if (surface == EGL_NO_SURFACE) {
89 eglDestroyContext(display, context);
90 return nullptr;
91 }
92
93 return std::unique_ptr<GLContextEGL>(new GLContextEGL(platformDisplay, context, surface, WTFMove(pixmap)));
94}
95
96} // namespace WebCore
97
98#endif // USE(EGL) && PLATFORM(X11)
99