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
58QT_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
75typedef GLXFBConfig* (*_glXChooseFBConfig) (Display *dpy, int screen, const int *attrib_list, int *nelements);
76typedef int (*_glXGetFBConfigAttrib) (Display *dpy, GLXFBConfig config, int attribute, int *value);
77typedef GLXPbuffer (*_glXCreatePbuffer) (Display *dpy, GLXFBConfig config, const int *attrib_list);
78typedef void (*_glXDestroyPbuffer) (Display *dpy, GLXPbuffer pbuf);
79typedef GLXContext (*_glXCreateNewContext) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
80typedef Bool (*_glXMakeContextCurrent) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
81
82static _glXChooseFBConfig qt_glXChooseFBConfig = 0;
83static _glXCreateNewContext qt_glXCreateNewContext = 0;
84static _glXCreatePbuffer qt_glXCreatePbuffer = 0;
85static _glXDestroyPbuffer qt_glXDestroyPbuffer = 0;
86static _glXGetFBConfigAttrib qt_glXGetFBConfigAttrib = 0;
87static _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
96extern void* qglx_getProcAddress(const char* procName); // in qgl_x11.cpp
97
98static 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
117static 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
172bool 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
248bool QGLPixelBufferPrivate::cleanup()
249{
250 glXDestroyPbuffer(QX11Info::display(), pbuf);
251 return true;
252}
253
254bool QGLPixelBuffer::bindToDynamicTexture(GLuint)
255{
256 return false;
257}
258
259void QGLPixelBuffer::releaseFromDynamicTexture()
260{
261}
262
263bool 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
290QT_END_NAMESPACE
291