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#ifndef GLXConfigSelector_h
27#define GLXConfigSelector_h
28
29#if USE(GLX)
30
31#include "X11Helper.h"
32#include <opengl/GLDefs.h>
33#include <opengl/GLPlatformSurface.h>
34
35namespace WebCore {
36
37static int clientAttributes[] = {
38    // The specification is a set key value pairs stored in a simple array.
39    GLX_LEVEL,                          0,
40    static_cast<int>(GLX_VISUAL_ID),    0,
41    GLX_DRAWABLE_TYPE,                  GLX_PIXMAP_BIT,
42    GLX_BIND_TO_TEXTURE_TARGETS_EXT,    GLX_TEXTURE_2D_BIT_EXT,
43    GLX_BIND_TO_TEXTURE_RGBA_EXT,       TRUE,
44    0
45};
46
47static int glxSurfaceAttributes[] = {
48    GLX_LEVEL, 0,
49    GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
50    GLX_RENDER_TYPE,   0,
51    GLX_RED_SIZE,      1,
52    GLX_GREEN_SIZE,    1,
53    GLX_BLUE_SIZE,     1,
54    GLX_ALPHA_SIZE,    0,
55    GLX_DOUBLEBUFFER,  GL_FALSE,
56    None
57};
58
59class GLXConfigSelector {
60    WTF_MAKE_NONCOPYABLE(GLXConfigSelector);
61
62public:
63    GLXConfigSelector(GLPlatformSurface::SurfaceAttributes attr = GLPlatformSurface::Default)
64        : m_surfaceContextFBConfig(0)
65        , m_pixmapContextFBConfig(0)
66        , m_attributes(attr)
67    {
68    }
69
70    virtual ~GLXConfigSelector()
71    {
72    }
73
74    XVisualInfo* visualInfo(const GLXFBConfig& config)
75    {
76        return glXGetVisualFromFBConfig(X11Helper::nativeDisplay(), config);
77    }
78
79    GLXFBConfig pixmapContextConfig()
80    {
81        if (!m_pixmapContextFBConfig) {
82            validateAttributes();
83            m_pixmapContextFBConfig = findMatchingConfig(glxSurfaceAttributes, m_attributes & GLPlatformSurface::SupportAlpha ? 32 : 24);
84        }
85
86        return m_pixmapContextFBConfig;
87    }
88
89
90    GLXFBConfig surfaceContextConfig()
91    {
92        if (!m_surfaceContextFBConfig) {
93            glxSurfaceAttributes[3] = GLX_WINDOW_BIT;
94            glxSurfaceAttributes[7] = 8;
95            glxSurfaceAttributes[9] = 8;
96            glxSurfaceAttributes[11] = 8;
97            validateAttributes();
98            m_surfaceContextFBConfig = findMatchingConfig(glxSurfaceAttributes, m_attributes & GLPlatformSurface::SupportAlpha ? 32 : 24);
99        }
100
101        return m_surfaceContextFBConfig;
102    }
103
104    GLXFBConfig surfaceClientConfig(int depth, VisualID id)
105    {
106        clientAttributes[3] = static_cast<int>(id);
107        clientAttributes[8] = depth == 32 ? GLX_BIND_TO_TEXTURE_RGBA_EXT : GLX_BIND_TO_TEXTURE_RGB_EXT;
108        // Prefer to match with Visual Id.
109        GLXFBConfig config = findMatchingConfigWithVisualId(clientAttributes, depth, id);
110
111        if (!config)
112            config = findMatchingConfig(clientAttributes, depth);
113
114        return config;
115    }
116
117    void reset()
118    {
119        m_surfaceContextFBConfig = 0;
120        m_pixmapContextFBConfig = 0;
121    }
122
123    GLPlatformSurface::SurfaceAttributes attributes() const
124    {
125        return m_attributes;
126    }
127
128private:
129    void validateAttributes()
130    {
131        if (m_attributes & GLPlatformSurface::SupportAlpha) {
132            glxSurfaceAttributes[13] = 8;
133            glxSurfaceAttributes[5] = GLX_RGBA_BIT;
134        }
135
136        if (m_attributes & GLPlatformSurface::DoubleBuffered)
137            glxSurfaceAttributes[15] = GL_TRUE;
138    }
139
140    GLXFBConfig findMatchingConfig(const int attributes[], int depth = 32)
141    {
142        int numAvailableConfigs;
143        OwnPtrX11<GLXFBConfig> temp(glXChooseFBConfig(X11Helper::nativeDisplay(), DefaultScreen(X11Helper::nativeDisplay()), attributes, &numAvailableConfigs));
144
145        if (!numAvailableConfigs || !temp.get())
146            return 0;
147
148        OwnPtrX11<XVisualInfo> scopedVisualInfo;
149        for (int i = 0; i < numAvailableConfigs; ++i) {
150            scopedVisualInfo = glXGetVisualFromFBConfig(X11Helper::nativeDisplay(), temp[i]);
151            if (!scopedVisualInfo.get())
152                continue;
153
154#if USE(GRAPHICS_SURFACE) && USE(GLX)
155            if (X11Helper::isXRenderExtensionSupported()) {
156                XRenderPictFormat* format = XRenderFindVisualFormat(X11Helper::nativeDisplay(), scopedVisualInfo->visual);
157
158                if (format) {
159                    if (m_attributes & GLPlatformSurface::SupportAlpha) {
160                        if (scopedVisualInfo->depth == depth && format->direct.alphaMask > 0)
161                            return temp[i];
162                    } else if (!format->direct.alphaMask)
163                        return temp[i];
164                }
165            }
166#endif
167            if (scopedVisualInfo->depth == depth)
168                return temp[i];
169        }
170
171        // Did not find any visual supporting alpha, select the first available config.
172        scopedVisualInfo = glXGetVisualFromFBConfig(X11Helper::nativeDisplay(), temp[0]);
173
174        if ((m_attributes & GLPlatformSurface::SupportAlpha) && (scopedVisualInfo->depth != 32))
175            m_attributes &= ~GLPlatformSurface::SupportAlpha;
176
177        return temp[0];
178    }
179
180    GLXFBConfig findMatchingConfigWithVisualId(const int attributes[], int depth, VisualID id)
181    {
182        int numAvailableConfigs;
183        OwnPtrX11<GLXFBConfig> temp(glXChooseFBConfig(X11Helper::nativeDisplay(), DefaultScreen(X11Helper::nativeDisplay()), attributes, &numAvailableConfigs));
184
185        if (!numAvailableConfigs || !temp.get())
186            return 0;
187
188        OwnPtrX11<XVisualInfo> scopedVisualInfo;
189        for (int i = 0; i < numAvailableConfigs; ++i) {
190            scopedVisualInfo = glXGetVisualFromFBConfig(X11Helper::nativeDisplay(), temp[i]);
191            if (!scopedVisualInfo.get())
192                continue;
193
194            if (id && scopedVisualInfo->depth == depth && scopedVisualInfo->visualid == id)
195                return temp[i];
196        }
197
198        return 0;
199    }
200
201    GLXFBConfig m_surfaceContextFBConfig;
202    GLXFBConfig m_pixmapContextFBConfig;
203    GLPlatformSurface::SurfaceAttributes m_attributes : 3;
204};
205
206}
207
208#endif
209
210#endif
211
212