1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtOpenGL module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | #include <qlibrary.h> |
42 | #include <qdebug.h> |
43 | #include <private/qgl_p.h> |
44 | #include <private/qt_x11_p.h> |
45 | #include <private/qpaintengine_opengl_p.h> |
46 | |
47 | #include <qx11info_x11.h> |
48 | #include <GL/glx.h> |
49 | #include <qimage.h> |
50 | |
51 | #include "qglpixelbuffer.h" |
52 | #include "qglpixelbuffer_p.h" |
53 | |
54 | #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) |
55 | #include <dlfcn.h> |
56 | #endif |
57 | |
58 | QT_BEGIN_NAMESPACE |
59 | |
60 | #ifndef GLX_VERSION_1_3 |
61 | #define GLX_RGBA_BIT 0x00000002 |
62 | #define GLX_PBUFFER_BIT 0x00000004 |
63 | #define GLX_DRAWABLE_TYPE 0x8010 |
64 | #define GLX_RENDER_TYPE 0x8011 |
65 | #define GLX_RGBA_TYPE 0x8014 |
66 | #define GLX_PBUFFER_HEIGHT 0x8040 |
67 | #define GLX_PBUFFER_WIDTH 0x8041 |
68 | #endif |
69 | |
70 | #ifndef GLX_ARB_multisample |
71 | #define GLX_SAMPLE_BUFFERS_ARB 100000 |
72 | #define GLX_SAMPLES_ARB 100001 |
73 | #endif |
74 | |
75 | typedef GLXFBConfig* (*_glXChooseFBConfig) (Display *dpy, int screen, const int *attrib_list, int *nelements); |
76 | typedef int (*_glXGetFBConfigAttrib) (Display *dpy, GLXFBConfig config, int attribute, int *value); |
77 | typedef GLXPbuffer (*_glXCreatePbuffer) (Display *dpy, GLXFBConfig config, const int *attrib_list); |
78 | typedef void (*_glXDestroyPbuffer) (Display *dpy, GLXPbuffer pbuf); |
79 | typedef GLXContext (*_glXCreateNewContext) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct); |
80 | typedef Bool (*_glXMakeContextCurrent) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); |
81 | |
82 | static _glXChooseFBConfig qt_glXChooseFBConfig = 0; |
83 | static _glXCreateNewContext qt_glXCreateNewContext = 0; |
84 | static _glXCreatePbuffer qt_glXCreatePbuffer = 0; |
85 | static _glXDestroyPbuffer qt_glXDestroyPbuffer = 0; |
86 | static _glXGetFBConfigAttrib qt_glXGetFBConfigAttrib = 0; |
87 | static _glXMakeContextCurrent qt_glXMakeContextCurrent = 0; |
88 | |
89 | #define glXChooseFBConfig qt_glXChooseFBConfig |
90 | #define glXCreateNewContext qt_glXCreateNewContext |
91 | #define glXCreatePbuffer qt_glXCreatePbuffer |
92 | #define glXDestroyPbuffer qt_glXDestroyPbuffer |
93 | #define glXGetFBConfigAttrib qt_glXGetFBConfigAttrib |
94 | #define glXMakeContextCurrent qt_glXMakeContextCurrent |
95 | |
96 | extern void* qglx_getProcAddress(const char* procName); // in qgl_x11.cpp |
97 | |
98 | static bool qt_resolve_pbuffer_extensions() |
99 | { |
100 | static int resolved = false; |
101 | if (resolved && qt_glXMakeContextCurrent) |
102 | return true; |
103 | else if (resolved) |
104 | return false; |
105 | |
106 | qt_glXChooseFBConfig = (_glXChooseFBConfig) qglx_getProcAddress("glXChooseFBConfig" ); |
107 | qt_glXCreateNewContext = (_glXCreateNewContext) qglx_getProcAddress("glXCreateNewContext" ); |
108 | qt_glXCreatePbuffer = (_glXCreatePbuffer) qglx_getProcAddress("glXCreatePbuffer" ); |
109 | qt_glXDestroyPbuffer = (_glXDestroyPbuffer) qglx_getProcAddress("glXDestroyPbuffer" ); |
110 | qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) qglx_getProcAddress("glXGetFBConfigAttrib" ); |
111 | qt_glXMakeContextCurrent = (_glXMakeContextCurrent) qglx_getProcAddress("glXMakeContextCurrent" ); |
112 | |
113 | resolved = qt_glXMakeContextCurrent ? true : false; |
114 | return resolved; |
115 | } |
116 | |
117 | static void qt_format_to_attrib_list(const QGLFormat &f, int attribs[]) |
118 | { |
119 | int i = 0; |
120 | attribs[i++] = GLX_RENDER_TYPE; |
121 | attribs[i++] = GLX_RGBA_BIT; |
122 | attribs[i++] = GLX_DRAWABLE_TYPE; |
123 | attribs[i++] = GLX_PBUFFER_BIT; |
124 | attribs[i++] = GLX_RED_SIZE; |
125 | attribs[i++] = f.redBufferSize() == -1 ? 1 : f.redBufferSize(); |
126 | attribs[i++] = GLX_GREEN_SIZE; |
127 | attribs[i++] = f.greenBufferSize() == -1 ? 1 : f.greenBufferSize(); |
128 | attribs[i++] = GLX_BLUE_SIZE; |
129 | attribs[i++] = f.blueBufferSize() == -1 ? 1 : f.blueBufferSize(); |
130 | if (f.doubleBuffer()) { |
131 | attribs[i++] = GLX_DOUBLEBUFFER; |
132 | attribs[i++] = true; |
133 | } |
134 | if (f.depth()) { |
135 | attribs[i++] = GLX_DEPTH_SIZE; |
136 | attribs[i++] = f.depthBufferSize() == -1 ? 1 : f.depthBufferSize(); |
137 | } |
138 | if (f.stereo()) { |
139 | attribs[i++] = GLX_STEREO; |
140 | attribs[i++] = true; |
141 | } |
142 | if (f.stencil()) { |
143 | attribs[i++] = GLX_STENCIL_SIZE; |
144 | attribs[i++] = f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize(); |
145 | } |
146 | if (f.alpha()) { |
147 | attribs[i++] = GLX_ALPHA_SIZE; |
148 | attribs[i++] = f.alphaBufferSize() == -1 ? 1 : f.alphaBufferSize(); |
149 | } |
150 | if (f.accum()) { |
151 | attribs[i++] = GLX_ACCUM_RED_SIZE; |
152 | attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize(); |
153 | attribs[i++] = GLX_ACCUM_GREEN_SIZE; |
154 | attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize(); |
155 | attribs[i++] = GLX_ACCUM_BLUE_SIZE; |
156 | attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize(); |
157 | if (f.alpha()) { |
158 | attribs[i++] = GLX_ACCUM_ALPHA_SIZE; |
159 | attribs[i++] = f.accumBufferSize() == -1 ? 1 : f.accumBufferSize(); |
160 | } |
161 | } |
162 | if (f.sampleBuffers()) { |
163 | attribs[i++] = GLX_SAMPLE_BUFFERS_ARB; |
164 | attribs[i++] = 1; |
165 | attribs[i++] = GLX_SAMPLES_ARB; |
166 | attribs[i++] = f.samples() == -1 ? 4 : f.samples(); |
167 | } |
168 | |
169 | attribs[i] = XNone; |
170 | } |
171 | |
172 | bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidget *shareWidget) |
173 | { |
174 | if (!qt_resolve_pbuffer_extensions()) { |
175 | qWarning("QGLPixelBuffer: pbuffers are not supported on this system." ); |
176 | return false; |
177 | } |
178 | |
179 | int attribs[40]; |
180 | int num_configs = 0; |
181 | |
182 | qt_format_to_attrib_list(f, attribs); |
183 | |
184 | int screen = X11->defaultScreen; |
185 | if (shareWidget) |
186 | screen = shareWidget->x11Info().screen(); |
187 | |
188 | GLXFBConfig *configs = glXChooseFBConfig(X11->display, screen, attribs, &num_configs); |
189 | if (configs && num_configs) { |
190 | int res; |
191 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_LEVEL, &res); |
192 | format.setPlane(res); |
193 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_DOUBLEBUFFER, &res); |
194 | format.setDoubleBuffer(res); |
195 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_DEPTH_SIZE, &res); |
196 | format.setDepth(res); |
197 | if (format.depth()) |
198 | format.setDepthBufferSize(res); |
199 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_RGBA, &res); |
200 | format.setRgba(res); |
201 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_RED_SIZE, &res); |
202 | format.setRedBufferSize(res); |
203 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_GREEN_SIZE, &res); |
204 | format.setGreenBufferSize(res); |
205 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_BLUE_SIZE, &res); |
206 | format.setBlueBufferSize(res); |
207 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_ALPHA_SIZE, &res); |
208 | format.setAlpha(res); |
209 | if (format.alpha()) |
210 | format.setAlphaBufferSize(res); |
211 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_ACCUM_RED_SIZE, &res); |
212 | format.setAccum(res); |
213 | if (format.accum()) |
214 | format.setAccumBufferSize(res); |
215 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_STENCIL_SIZE, &res); |
216 | format.setStencil(res); |
217 | if (format.stencil()) |
218 | format.setStencilBufferSize(res); |
219 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_STEREO, &res); |
220 | format.setStereo(res); |
221 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_SAMPLE_BUFFERS_ARB, &res); |
222 | format.setSampleBuffers(res); |
223 | if (format.sampleBuffers()) { |
224 | glXGetFBConfigAttrib(X11->display, configs[0], GLX_SAMPLES_ARB, &res); |
225 | format.setSamples(res); |
226 | } |
227 | |
228 | int pb_attribs[] = {GLX_PBUFFER_WIDTH, size.width(), GLX_PBUFFER_HEIGHT, size.height(), XNone}; |
229 | GLXContext shareContext = 0; |
230 | if (shareWidget && shareWidget->d_func()->glcx) |
231 | shareContext = (GLXContext) shareWidget->d_func()->glcx->d_func()->cx; |
232 | |
233 | pbuf = glXCreatePbuffer(QX11Info::display(), configs[0], pb_attribs); |
234 | ctx = glXCreateNewContext(QX11Info::display(), configs[0], GLX_RGBA_TYPE, shareContext, true); |
235 | |
236 | XFree(configs); |
237 | if (!pbuf || !ctx) { |
238 | qWarning("QGLPixelBuffer: Unable to create a pbuffer/context - giving up." ); |
239 | return false; |
240 | } |
241 | return true; |
242 | } else { |
243 | qWarning("QGLPixelBuffer: Unable to find a context/format match - giving up." ); |
244 | return false; |
245 | } |
246 | } |
247 | |
248 | bool QGLPixelBufferPrivate::cleanup() |
249 | { |
250 | glXDestroyPbuffer(QX11Info::display(), pbuf); |
251 | return true; |
252 | } |
253 | |
254 | bool QGLPixelBuffer::bindToDynamicTexture(GLuint) |
255 | { |
256 | return false; |
257 | } |
258 | |
259 | void QGLPixelBuffer::releaseFromDynamicTexture() |
260 | { |
261 | } |
262 | |
263 | bool QGLPixelBuffer::hasOpenGLPbuffers() |
264 | { |
265 | bool ret = qt_resolve_pbuffer_extensions(); |
266 | |
267 | if (!ret) |
268 | return false; |
269 | |
270 | int attribs[40]; |
271 | int num_configs = 0; |
272 | |
273 | qt_format_to_attrib_list(QGLFormat::defaultFormat(), attribs); |
274 | |
275 | GLXFBConfig *configs = glXChooseFBConfig(X11->display, X11->defaultScreen, attribs, &num_configs); |
276 | GLXPbuffer pbuf = 0; |
277 | GLXContext ctx = 0; |
278 | |
279 | if (configs && num_configs) { |
280 | int pb_attribs[] = {GLX_PBUFFER_WIDTH, 128, GLX_PBUFFER_HEIGHT, 128, XNone}; |
281 | pbuf = glXCreatePbuffer(X11->display, configs[0], pb_attribs); |
282 | ctx = glXCreateNewContext(X11->display, configs[0], GLX_RGBA_TYPE, 0, true); |
283 | XFree(configs); |
284 | glXDestroyContext(X11->display, ctx); |
285 | glXDestroyPbuffer(X11->display, pbuf); |
286 | } |
287 | return pbuf && ctx; |
288 | } |
289 | |
290 | QT_END_NAMESPACE |
291 | |