source: trunk/src/opengl/qwindowsurface_gl.cpp@ 624

Last change on this file since 624 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 27.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtOpenGL module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <QtGui/QApplication>
43#include <QtGui/QColormap>
44#include <QtGui/QDesktopWidget>
45#include <QtGui/QPaintDevice>
46#include <QtGui/QWidget>
47
48#include <qglframebufferobject.h>
49#include <qglpixelbuffer.h>
50#include <qcolormap.h>
51#include <qdesktopwidget.h>
52#include <private/qwidget_p.h>
53#include "qdebug.h"
54
55#ifdef Q_WS_X11
56#include <private/qt_x11_p.h>
57#include <qx11info_x11.h>
58
59#ifndef QT_OPENGL_ES
60#include <GL/glx.h>
61#include <X11/Xlib.h>
62#endif
63#endif //Q_WS_X11
64
65#include <private/qglextensions_p.h>
66#include <private/qwindowsurface_gl_p.h>
67
68#include <private/qgl_p.h>
69
70#include <private/qglpixelbuffer_p.h>
71#include <private/qgraphicssystem_gl_p.h>
72
73#include <private/qpaintengineex_opengl2_p.h>
74#include <private/qpixmapdata_gl_p.h>
75
76#ifndef QT_OPENGL_ES_2
77#include <private/qpaintengine_opengl_p.h>
78#endif
79
80#ifndef GLX_ARB_multisample
81#define GLX_SAMPLE_BUFFERS_ARB 100000
82#define GLX_SAMPLES_ARB 100001
83#endif
84
85#ifdef QT_OPENGL_ES_1_CL
86#include "qgl_cl_p.h"
87#endif
88
89#ifdef QT_OPENGL_ES
90#include <private/qegl_p.h>
91#endif
92
93QT_BEGIN_NAMESPACE
94
95//
96// QGLGraphicsSystem
97//
98#ifdef Q_WS_WIN
99extern Q_GUI_EXPORT bool qt_win_owndc_required;
100#endif
101QGLGraphicsSystem::QGLGraphicsSystem()
102 : QGraphicsSystem()
103{
104#if defined(Q_WS_X11) && !defined(QT_OPENGL_ES)
105 // only override the system defaults if the user hasn't already
106 // picked a visual
107 if (X11->visual == 0 && X11->visual_id == -1 && X11->visual_class == -1) {
108 // find a double buffered, RGBA visual that supports OpenGL
109 // and set that as the default visual for windows in Qt
110 int i = 0;
111 int spec[16];
112 spec[i++] = GLX_RGBA;
113 spec[i++] = GLX_DOUBLEBUFFER;
114
115 if (!qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull()) {
116 spec[i++] = GLX_DEPTH_SIZE;
117 spec[i++] = 8;
118 spec[i++] = GLX_STENCIL_SIZE;
119 spec[i++] = 8;
120 spec[i++] = GLX_SAMPLE_BUFFERS_ARB;
121 spec[i++] = 1;
122 spec[i++] = GLX_SAMPLES_ARB;
123 spec[i++] = 4;
124 }
125
126 spec[i++] = XNone;
127
128 XVisualInfo *vi = glXChooseVisual(X11->display, X11->defaultScreen, spec);
129 if (vi) {
130 X11->visual_id = vi->visualid;
131 X11->visual_class = vi->c_class;
132
133 QGLFormat format;
134 int res;
135 glXGetConfig(X11->display, vi, GLX_LEVEL, &res);
136 format.setPlane(res);
137 glXGetConfig(X11->display, vi, GLX_DOUBLEBUFFER, &res);
138 format.setDoubleBuffer(res);
139 glXGetConfig(X11->display, vi, GLX_DEPTH_SIZE, &res);
140 format.setDepth(res);
141 if (format.depth())
142 format.setDepthBufferSize(res);
143 glXGetConfig(X11->display, vi, GLX_RGBA, &res);
144 format.setRgba(res);
145 glXGetConfig(X11->display, vi, GLX_RED_SIZE, &res);
146 format.setRedBufferSize(res);
147 glXGetConfig(X11->display, vi, GLX_GREEN_SIZE, &res);
148 format.setGreenBufferSize(res);
149 glXGetConfig(X11->display, vi, GLX_BLUE_SIZE, &res);
150 format.setBlueBufferSize(res);
151 glXGetConfig(X11->display, vi, GLX_ALPHA_SIZE, &res);
152 format.setAlpha(res);
153 if (format.alpha())
154 format.setAlphaBufferSize(res);
155 glXGetConfig(X11->display, vi, GLX_ACCUM_RED_SIZE, &res);
156 format.setAccum(res);
157 if (format.accum())
158 format.setAccumBufferSize(res);
159 glXGetConfig(X11->display, vi, GLX_STENCIL_SIZE, &res);
160 format.setStencil(res);
161 if (format.stencil())
162 format.setStencilBufferSize(res);
163 glXGetConfig(X11->display, vi, GLX_STEREO, &res);
164 format.setStereo(res);
165 glXGetConfig(X11->display, vi, GLX_SAMPLE_BUFFERS_ARB, &res);
166 format.setSampleBuffers(res);
167 if (format.sampleBuffers()) {
168 glXGetConfig(X11->display, vi, GLX_SAMPLES_ARB, &res);
169 format.setSamples(res);
170 }
171
172 QGLWindowSurface::surfaceFormat = format;
173 XFree(vi);
174
175 printf("using visual class %x, id %x\n", X11->visual_class, X11->visual_id);
176 }
177 }
178#elif defined(Q_WS_WIN)
179 QGLWindowSurface::surfaceFormat.setDoubleBuffer(true);
180
181 qt_win_owndc_required = true;
182#endif
183}
184
185//
186// QGLWindowSurface
187//
188
189class QGLGlobalShareWidget
190{
191public:
192 QGLGlobalShareWidget() : widget(0), initializing(false) {}
193
194 QGLWidget *shareWidget() {
195 if (!initializing && !widget && !cleanedUp) {
196 initializing = true;
197 widget = new QGLWidget;
198 // We dont need this internal widget to appear in QApplication::topLevelWidgets()
199 if (QWidgetPrivate::allWidgets)
200 QWidgetPrivate::allWidgets->remove(widget);
201 initializing = false;
202 }
203 return widget;
204 }
205
206 void cleanup() {
207 QGLWidget *w = widget;
208 cleanedUp = true;
209 widget = 0;
210 delete w;
211 }
212
213 static bool cleanedUp;
214
215private:
216 QGLWidget *widget;
217 bool initializing;
218};
219
220bool QGLGlobalShareWidget::cleanedUp = false;
221
222static void qt_cleanup_gl_share_widget();
223Q_GLOBAL_STATIC_WITH_INITIALIZER(QGLGlobalShareWidget, _qt_gl_share_widget,
224 {
225 qAddPostRoutine(qt_cleanup_gl_share_widget);
226 })
227
228static void qt_cleanup_gl_share_widget()
229{
230 _qt_gl_share_widget()->cleanup();
231}
232
233QGLWidget* qt_gl_share_widget()
234{
235 if (QGLGlobalShareWidget::cleanedUp)
236 return 0;
237 return _qt_gl_share_widget()->shareWidget();
238}
239
240
241struct QGLWindowSurfacePrivate
242{
243 QGLFramebufferObject *fbo;
244 QGLPixelBuffer *pb;
245 GLuint tex_id;
246 GLuint pb_tex_id;
247
248 int tried_fbo : 1;
249 int tried_pb : 1;
250 int destructive_swap_buffers : 1;
251 int geometry_updated : 1;
252
253 QGLContext *ctx;
254
255 QList<QGLContext **> contexts;
256
257 QRegion paintedRegion;
258 QSize size;
259
260 QList<QImage> buffers;
261 QGLWindowSurfaceGLPaintDevice glDevice;
262 QGLWindowSurface* q_ptr;
263};
264
265QGLFormat QGLWindowSurface::surfaceFormat;
266
267void QGLWindowSurfaceGLPaintDevice::endPaint()
268{
269 glFlush();
270 QGLPaintDevice::endPaint();
271}
272
273QSize QGLWindowSurfaceGLPaintDevice::size() const
274{
275 return d->size;
276}
277
278QGLContext* QGLWindowSurfaceGLPaintDevice::context() const
279{
280 return d->ctx;
281}
282
283
284int QGLWindowSurfaceGLPaintDevice::metric(PaintDeviceMetric m) const
285{
286 return qt_paint_device_metric(d->q_ptr->window(), m);
287}
288
289QPaintEngine *QGLWindowSurfaceGLPaintDevice::paintEngine() const
290{
291 return qt_qgl_paint_engine();
292}
293
294QGLWindowSurface::QGLWindowSurface(QWidget *window)
295 : QWindowSurface(window), d_ptr(new QGLWindowSurfacePrivate)
296{
297 Q_ASSERT(window->isTopLevel());
298 QGLExtensions::init();
299 d_ptr->pb = 0;
300 d_ptr->fbo = 0;
301 d_ptr->ctx = 0;
302#if defined (QT_OPENGL_ES_2)
303 d_ptr->tried_fbo = true;
304 d_ptr->tried_pb = true;
305#else
306 d_ptr->tried_fbo = false;
307 d_ptr->tried_pb = false;
308#endif
309 d_ptr->destructive_swap_buffers = qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull();
310 d_ptr->glDevice.d = d_ptr;
311 d_ptr->q_ptr = this;
312 d_ptr->geometry_updated = false;
313}
314
315QGLWindowSurface::~QGLWindowSurface()
316{
317 if (d_ptr->ctx)
318 glDeleteTextures(1, &d_ptr->tex_id);
319 foreach(QGLContext **ctx, d_ptr->contexts) {
320 delete *ctx;
321 *ctx = 0;
322 }
323
324 delete d_ptr->pb;
325 delete d_ptr->fbo;
326 delete d_ptr;
327}
328
329void QGLWindowSurface::deleted(QObject *object)
330{
331 // Make sure that the fbo is destroyed before destroying its context.
332 delete d_ptr->fbo;
333 d_ptr->fbo = 0;
334
335 QWidget *widget = qobject_cast<QWidget *>(object);
336 if (widget) {
337 QWidgetPrivate *widgetPrivate = widget->d_func();
338 if (widgetPrivate->extraData()) {
339 union { QGLContext **ctxPtr; void **voidPtr; };
340 voidPtr = &widgetPrivate->extraData()->glContext;
341 int index = d_ptr->contexts.indexOf(ctxPtr);
342 if (index != -1) {
343 delete *ctxPtr;
344 *ctxPtr = 0;
345 d_ptr->contexts.removeAt(index);
346 }
347 }
348 }