[EFL][WebGL] Add proper checks to enable GraphicsSurface usage on EGL without XCompos...
[WebKit-https.git] / Source / WebCore / platform / graphics / surfaces / glx / X11Helper.cpp
1 /*
2  * Copyright (C) 2013 Intel Corporation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "X11Helper.h"
28
29 namespace WebCore {
30
31 // Used for handling XError.
32 static bool validOperation = true;
33 static int handleXPixmapCreationError(Display*, XErrorEvent* event)
34 {
35     if (event->error_code == BadMatch || event->error_code == BadWindow || event->error_code == BadAlloc) {
36         validOperation = false;
37
38         switch (event->error_code) {
39         case BadMatch:
40             LOG_ERROR("BadMatch.");
41             break;
42         case BadWindow:
43             LOG_ERROR("BadWindow.");
44             break;
45         case BadAlloc:
46             LOG_ERROR("BadAlloc.");
47             break;
48         default:
49             break;
50         }
51     }
52
53     return 0;
54 }
55
56 struct DisplayConnection {
57     DisplayConnection()
58     {
59         m_display = XOpenDisplay(0);
60
61         if (!m_display)
62             LOG_ERROR("Failed to make connection with X");
63     }
64
65     ~DisplayConnection()
66     {
67         XCloseDisplay(m_display);
68     }
69
70     Display* display() { return m_display; }
71 private:
72     Display* m_display;
73 };
74
75 struct OffScreenRootWindow {
76
77     OffScreenRootWindow()
78     {
79         m_window = 0;
80         Display* dpy = X11Helper::nativeDisplay();
81         if (!dpy)
82             return;
83
84         XSetWindowAttributes attributes;
85         attributes.override_redirect = true;
86         m_window = XCreateSimpleWindow(dpy, XDefaultRootWindow(dpy), -1, -1, 1, 1, 0, BlackPixel(dpy, 0), WhitePixel(dpy, 0));
87         // From http://tronche.com/gui/x/xlib/window/attributes/
88         XChangeWindowAttributes(dpy, m_window, CWOverrideRedirect, &attributes);
89         XMapWindow(dpy, m_window);
90
91         if (!m_window)
92             LOG_ERROR("Failed to create offscreen root window.");
93     }
94
95     ~OffScreenRootWindow()
96     {
97         if (!X11Helper::nativeDisplay())
98             return;
99
100         if (m_window) {
101             XUnmapWindow(X11Helper::nativeDisplay(), m_window);
102             XDestroyWindow(X11Helper::nativeDisplay(), m_window);
103             m_window = 0;
104         }
105     }
106
107     Window rootWindow()
108     {
109         return m_window;
110     }
111
112 private:
113     Window m_window;
114 };
115
116 ScopedXPixmapCreationErrorHandler::ScopedXPixmapCreationErrorHandler()
117 {
118     // XSync must be called to ensure that current errors are handled by the original handler.
119     XSync(X11Helper::nativeDisplay(), false);
120     m_previousErrorHandler = XSetErrorHandler(handleXPixmapCreationError);
121 }
122
123 ScopedXPixmapCreationErrorHandler::~ScopedXPixmapCreationErrorHandler()
124 {
125     // Restore the original handler.
126     XSetErrorHandler(m_previousErrorHandler);
127 }
128
129 bool ScopedXPixmapCreationErrorHandler::isValidOperation() const
130 {
131     validOperation = true;
132     // XSync is needed to catch possible errors as they are generated asynchronously.
133     XSync(X11Helper::nativeDisplay(), false);
134     return validOperation;
135 }
136
137 void X11Helper::resizeWindow(const IntRect& newRect, const uint32_t windowId)
138 {
139     XResizeWindow(nativeDisplay(), windowId, newRect.width(), newRect.height());
140     XFlush(nativeDisplay());
141 }
142
143 void X11Helper::createPixmap(Pixmap* handleId, const XVisualInfo& visualInfo, const IntSize& size)
144 {
145     Display* display = nativeDisplay();
146     if (!display)
147         return;
148
149     if (!visualInfo.visual) {
150         LOG_ERROR("Failed to find valid XVisual.");
151         return;
152     }
153
154     Window xWindow = offscreenRootWindow();
155     if (!xWindow) {
156         LOG_ERROR("Failed to create offscreen root window.");
157         return;
158     }
159
160     Pixmap tempHandleId = XCreatePixmap(display, xWindow, size.width(), size.height(), visualInfo.depth);
161
162     if (!tempHandleId) {
163         LOG_ERROR("Failed to create offscreen pixmap.");
164         return;
165     }
166
167     *handleId = tempHandleId;
168     XSync(X11Helper::nativeDisplay(), false);
169 }
170
171 void X11Helper::destroyPixmap(const uint32_t pixmapId)
172 {
173     if (!pixmapId)
174         return;
175
176     Display* display = nativeDisplay();
177     if (!display)
178         return;
179
180     XFreePixmap(display, pixmapId);
181     XSync(X11Helper::nativeDisplay(), false);
182 }
183
184 void X11Helper::createOffScreenWindow(uint32_t* handleId, const XVisualInfo& visInfo, const IntSize& size)
185 {
186 #if USE(GRAPHICS_SURFACE) && USE(GLX)
187     Display* display = nativeDisplay();
188     if (!display)
189         return;
190
191     if (!visInfo.visual) {
192         LOG_ERROR("Failed to find valid XVisual.");
193         return;
194     }
195
196     Window xWindow = offscreenRootWindow();
197     if (!xWindow)
198         return;
199
200     Colormap cmap = XCreateColormap(display, xWindow, visInfo.visual, AllocNone);
201     XSetWindowAttributes attribute;
202     attribute.background_pixel = WhitePixel(display, 0);
203     attribute.border_pixel = BlackPixel(display, 0);
204     attribute.colormap = cmap;
205     attribute.event_mask = ResizeRedirectMask;
206     uint32_t tempHandleId = XCreateWindow(display, xWindow, 0, 0, size.width(), size.height(), 0, visInfo.depth, InputOutput, visInfo.visual, CWBackPixel | CWBorderPixel | CWColormap, &attribute);
207
208     if (!tempHandleId) {
209         LOG_ERROR("Failed to create offscreen window.");
210         return;
211     }
212
213     XSetWindowBackgroundPixmap(display, tempHandleId, 0);
214     XCompositeRedirectWindow(display, tempHandleId, CompositeRedirectManual);
215     XMapWindow(display, tempHandleId);
216     *handleId = tempHandleId;
217 #else
218     UNUSED_PARAM(handleId);
219     UNUSED_PARAM(visInfo);
220     UNUSED_PARAM(size);
221 #endif
222 }
223
224 #if USE(EGL)
225 void X11Helper::createOffScreenWindow(uint32_t* handleId, const EGLint id, bool supportsAlpha, const IntSize& size)
226 {
227 #if USE(GRAPHICS_SURFACE)
228     VisualID visualId = static_cast<VisualID>(id);
229
230     if (!visualId)
231         return;
232
233     // EGL has suggested a visual id, so get the rest of the visual info for that id.
234     XVisualInfo visualInfoTemplate;
235     memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
236     visualInfoTemplate.visualid = visualId;
237     int matchingCount = 0;
238     OwnPtrX11<XVisualInfo> matchingVisuals(XGetVisualInfo(nativeDisplay(), VisualIDMask, &visualInfoTemplate, &matchingCount));
239     XVisualInfo* foundVisual = 0;
240
241     if (matchingVisuals) {
242         for (int i = 0; i< matchingCount; i++) {
243             XVisualInfo* temp = &matchingVisuals[i];
244             int matchingdepth = supportsAlpha ? 32 : 24;
245
246             if (temp->depth == matchingdepth) {
247                 foundVisual = temp;
248                 break;
249             }
250         }
251
252         if (foundVisual)
253             createOffScreenWindow(handleId, *foundVisual, size);
254     }
255 #else
256     UNUSED_PARAM(handleId);
257     UNUSED_PARAM(id);
258     UNUSED_PARAM(size);
259 #endif
260 }
261 #endif
262
263 void X11Helper::destroyWindow(const uint32_t windowId)
264 {
265     if (!windowId)
266         return;
267
268     Display* display = nativeDisplay();
269     if (!display)
270         return;
271
272     XDestroyWindow(display, windowId);
273 }
274
275 bool X11Helper::isXRenderExtensionSupported()
276 {
277     static bool queryDone = false;
278     static bool supportsXRenderExtension = false;
279
280     if (!queryDone) {
281         queryDone = true;
282 #if USE(GRAPHICS_SURFACE) && USE(GLX)
283         Display* display = nativeDisplay();
284
285         if (display) {
286             int eventBasep, errorBasep;
287             supportsXRenderExtension = XRenderQueryExtension(display, &eventBasep, &errorBasep);
288         }
289 #endif
290     }
291
292     return supportsXRenderExtension;
293 }
294
295 Display* X11Helper::nativeDisplay()
296 {
297     // Display connection will only be broken at program shutdown.
298     static DisplayConnection displayConnection;
299     return displayConnection.display();
300 }
301
302 Window X11Helper::offscreenRootWindow()
303 {
304     static OffScreenRootWindow offscreenWindow;
305     return offscreenWindow.rootWindow();
306 }
307
308 }
309