1/*
2 * Copyright (C) 2012 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 "GLXSurface.h"
28
29#if USE(ACCELERATED_COMPOSITING) && USE(GLX)
30
31namespace WebCore {
32
33static PFNGLXBINDTEXIMAGEEXTPROC pGlXBindTexImageEXT = 0;
34static PFNGLXRELEASETEXIMAGEEXTPROC pGlXReleaseTexImageEXT = 0;
35
36static bool resolveGLMethods()
37{
38    static bool resolved = false;
39    if (resolved)
40        return true;
41
42    pGlXBindTexImageEXT = reinterpret_cast<PFNGLXBINDTEXIMAGEEXTPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXBindTexImageEXT")));
43    pGlXReleaseTexImageEXT = reinterpret_cast<PFNGLXRELEASETEXIMAGEEXTPROC>(glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXReleaseTexImageEXT")));
44
45    resolved = pGlXBindTexImageEXT && pGlXReleaseTexImageEXT;
46
47    return resolved;
48}
49
50static int glxAttributes[] = {
51    GLX_TEXTURE_FORMAT_EXT,
52    GLX_TEXTURE_FORMAT_RGBA_EXT,
53    GLX_TEXTURE_TARGET_EXT,
54    GLX_TEXTURE_2D_EXT,
55    0
56};
57
58static bool isMesaGLX()
59{
60    static bool isMesa = !!strstr(glXGetClientString(X11Helper::nativeDisplay(), GLX_VENDOR), "Mesa");
61    return isMesa;
62}
63
64GLXTransportSurface::GLXTransportSurface(const IntSize& size, SurfaceAttributes attributes)
65    : GLTransportSurface(size, attributes)
66{
67    m_sharedDisplay = X11Helper::nativeDisplay();
68    attributes |= GLPlatformSurface::DoubleBuffered;
69    m_configSelector = adoptPtr(new GLXConfigSelector(attributes));
70    OwnPtrX11<XVisualInfo> visInfo(m_configSelector->visualInfo(m_configSelector->surfaceContextConfig()));
71
72    if (!visInfo.get()) {
73        destroy();
74        return;
75    }
76
77    X11Helper::createOffScreenWindow(&m_bufferHandle, *visInfo.get(), size);
78
79    if (!m_bufferHandle) {
80        destroy();
81        return;
82    }
83
84    m_drawable = m_bufferHandle;
85}
86
87GLXTransportSurface::~GLXTransportSurface()
88{
89}
90
91PlatformSurfaceConfig GLXTransportSurface::configuration()
92{
93    return m_configSelector->surfaceContextConfig();
94}
95
96void GLXTransportSurface::setGeometry(const IntRect& newRect)
97{
98    GLTransportSurface::setGeometry(newRect);
99    X11Helper::resizeWindow(newRect, m_drawable);
100    // Force resize of GL surface after window resize.
101    glXSwapBuffers(sharedDisplay(), m_drawable);
102}
103
104void GLXTransportSurface::swapBuffers()
105{
106    if (!m_drawable)
107        return;
108
109    glXSwapBuffers(sharedDisplay(), m_drawable);
110}
111
112void GLXTransportSurface::destroy()
113{
114    GLTransportSurface::destroy();
115
116    if (m_bufferHandle) {
117        X11Helper::destroyWindow(m_bufferHandle);
118        m_bufferHandle = 0;
119        m_drawable = 0;
120    }
121
122    m_configSelector = nullptr;
123}
124
125GLPlatformSurface::SurfaceAttributes GLXTransportSurface::attributes() const
126{
127    return m_configSelector->attributes();
128}
129
130GLXOffScreenSurface::GLXOffScreenSurface(SurfaceAttributes surfaceAttributes)
131    : GLPlatformSurface(surfaceAttributes)
132    , m_pixmap(0)
133    , m_glxPixmap(0)
134{
135    initialize(surfaceAttributes);
136}
137
138GLXOffScreenSurface::~GLXOffScreenSurface()
139{
140}
141
142void GLXOffScreenSurface::initialize(SurfaceAttributes attributes)
143{
144    m_sharedDisplay = X11Helper::nativeDisplay();
145
146    m_configSelector = adoptPtr(new GLXConfigSelector(attributes));
147
148    OwnPtrX11<XVisualInfo> visualInfo(m_configSelector->visualInfo(m_configSelector->pixmapContextConfig()));
149    X11Helper::createPixmap(&m_pixmap, *visualInfo.get());
150
151    if (!m_pixmap) {
152        destroy();
153        return;
154    }
155
156    m_glxPixmap = glXCreateGLXPixmap(m_sharedDisplay, visualInfo.get(), m_pixmap);
157
158    if (!m_glxPixmap) {
159        destroy();
160        return;
161    }
162
163    m_drawable = m_glxPixmap;
164}
165
166PlatformSurfaceConfig GLXOffScreenSurface::configuration()
167{
168    return m_configSelector->pixmapContextConfig();
169}
170
171void GLXOffScreenSurface::destroy()
172{
173    freeResources();
174}
175
176void GLXOffScreenSurface::freeResources()
177{
178    Display* display = sharedDisplay();
179
180    if (!display)
181        return;
182
183    if (m_glxPixmap) {
184        glXDestroyGLXPixmap(display, m_glxPixmap);
185        glXWaitGL();
186        m_glxPixmap = 0;
187    }
188
189    if (m_pixmap) {
190        X11Helper::destroyPixmap(m_pixmap);
191        m_pixmap = 0;
192    }
193
194    m_configSelector = nullptr;
195    m_drawable = 0;
196}
197
198GLXTransportSurfaceClient::GLXTransportSurfaceClient(const PlatformBufferHandle handle, bool hasAlpha)
199    : GLTransportSurfaceClient()
200{
201    if (!resolveGLMethods())
202        return;
203
204    XWindowAttributes attr;
205    Display* display = X11Helper::nativeDisplay();
206    if (!XGetWindowAttributes(display, handle, &attr))
207        return;
208
209    // Ensure that the window is mapped.
210    if (attr.map_state == IsUnmapped || attr.map_state == IsUnviewable)
211        return;
212
213    ScopedXPixmapCreationErrorHandler handler;
214
215    XRenderPictFormat* format = XRenderFindVisualFormat(display, attr.visual);
216    m_xPixmap = XCompositeNameWindowPixmap(display, handle);
217
218    if (!m_xPixmap)
219        return;
220
221    glxAttributes[1] = (format->depth == 32 && hasAlpha) ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT;
222
223    GLPlatformSurface::SurfaceAttributes sharedSurfaceAttributes = GLPlatformSurface::Default;
224
225    if (hasAlpha)
226        sharedSurfaceAttributes = GLPlatformSurface::SupportAlpha;
227
228    GLXConfigSelector configSelector(sharedSurfaceAttributes);
229
230    m_glxPixmap = glXCreatePixmap(display, configSelector.surfaceClientConfig(format->depth, XVisualIDFromVisual(attr.visual)), m_xPixmap, glxAttributes);
231
232    if (!m_glxPixmap || !handler.isValidOperation()) {
233        destroy();
234        return;
235    }
236
237    createTexture();
238    glXWaitX();
239    pGlXBindTexImageEXT(display, m_glxPixmap, GLX_FRONT_EXT, 0);
240}
241
242GLXTransportSurfaceClient::~GLXTransportSurfaceClient()
243{
244}
245
246void GLXTransportSurfaceClient::destroy()
247{
248    Display* display = X11Helper::nativeDisplay();
249    if (!display)
250        return;
251
252    if (m_texture) {
253        pGlXReleaseTexImageEXT(display, m_glxPixmap, GLX_FRONT_EXT);
254        GLTransportSurfaceClient::destroy();
255    }
256
257    if (m_glxPixmap) {
258        glXDestroyPixmap(display, m_glxPixmap);
259        m_glxPixmap = 0;
260        glXWaitGL();
261    }
262
263    if (m_xPixmap) {
264        X11Helper::destroyPixmap(m_xPixmap);
265        m_xPixmap = 0;
266    }
267}
268
269void GLXTransportSurfaceClient::prepareTexture()
270{
271    if (isMesaGLX() && m_texture) {
272        Display* display = X11Helper::nativeDisplay();
273        glBindTexture(GL_TEXTURE_2D, m_texture);
274        // Mesa doesn't re-bind texture to the front buffer on glXSwapBufer
275        // Manually release previous lock and rebind texture to surface to ensure frame updates.
276        pGlXReleaseTexImageEXT(display, m_glxPixmap, GLX_FRONT_EXT);
277        pGlXBindTexImageEXT(display, m_glxPixmap, GLX_FRONT_EXT, 0);
278    }
279}
280
281}
282
283#endif
284