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

Last change on this file since 443 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 19.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtOpenGL module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department 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 "qdebug.h"
53
54#ifdef Q_WS_X11
55#include <private/qt_x11_p.h>
56#include <qx11info_x11.h>
57#include <private/qwidget_p.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#include <private/qpaintengine_opengl_p.h>
73
74#ifndef GLX_ARB_multisample
75#define GLX_SAMPLE_BUFFERS_ARB 100000
76#define GLX_SAMPLES_ARB 100001
77#endif
78
79QT_BEGIN_NAMESPACE
80
81//
82// QGLGraphicsSystem
83//
84#ifdef Q_WS_WIN
85Q_GUI_EXPORT bool qt_win_owndc_required;
86#endif
87QGLGraphicsSystem::QGLGraphicsSystem()
88 : QGraphicsSystem()
89{
90#if defined(Q_WS_X11) && !defined(QT_OPENGL_ES)
91 // only override the system defaults if the user hasn't already
92 // picked a visual
93 if (X11->visual == 0 && X11->visual_id == -1 && X11->visual_class == -1) {
94 // find a double buffered, RGBA visual that supports OpenGL
95 // and set that as the default visual for windows in Qt
96 int i = 0;
97 int spec[16];
98 spec[i++] = GLX_RGBA;
99#if 0
100 spec[i++] = GLX_DOUBLEBUFFER;
101 spec[i++] = GLX_DEPTH_SIZE;
102 spec[i++] = 8;
103 spec[i++] = GLX_STENCIL_SIZE;
104 spec[i++] = 8;
105 spec[i++] = GLX_SAMPLE_BUFFERS_ARB;
106 spec[i++] = 1;
107 spec[i++] = GLX_SAMPLES_ARB;
108 spec[i++] = 4;
109#endif
110 spec[i++] = XNone;
111
112 XVisualInfo *vi = glXChooseVisual(X11->display, X11->defaultScreen, spec);
113 if (vi) {
114 X11->visual_id = vi->visualid;
115 X11->visual_class = vi->c_class;
116
117 QGLFormat format;
118 int res;
119 glXGetConfig(X11->display, vi, GLX_LEVEL, &res);
120 format.setPlane(res);
121 glXGetConfig(X11->display, vi, GLX_DOUBLEBUFFER, &res);
122 format.setDoubleBuffer(res);
123 glXGetConfig(X11->display, vi, GLX_DEPTH_SIZE, &res);
124 format.setDepth(res);
125 if (format.depth())
126 format.setDepthBufferSize(res);
127 glXGetConfig(X11->display, vi, GLX_RGBA, &res);
128 format.setRgba(res);
129 glXGetConfig(X11->display, vi, GLX_RED_SIZE, &res);
130 format.setRedBufferSize(res);
131 glXGetConfig(X11->display, vi, GLX_GREEN_SIZE, &res);
132 format.setGreenBufferSize(res);
133 glXGetConfig(X11->display, vi, GLX_BLUE_SIZE, &res);
134 format.setBlueBufferSize(res);
135 glXGetConfig(X11->display, vi, GLX_ALPHA_SIZE, &res);
136 format.setAlpha(res);
137 if (format.alpha())
138 format.setAlphaBufferSize(res);
139 glXGetConfig(X11->display, vi, GLX_ACCUM_RED_SIZE, &res);
140 format.setAccum(res);
141 if (format.accum())
142 format.setAccumBufferSize(res);
143 glXGetConfig(X11->display, vi, GLX_STENCIL_SIZE, &res);
144 format.setStencil(res);
145 if (format.stencil())
146 format.setStencilBufferSize(res);
147 glXGetConfig(X11->display, vi, GLX_STEREO, &res);
148 format.setStereo(res);
149 glXGetConfig(X11->display, vi, GLX_SAMPLE_BUFFERS_ARB, &res);
150 format.setSampleBuffers(res);
151 if (format.sampleBuffers()) {
152 glXGetConfig(X11->display, vi, GLX_SAMPLES_ARB, &res);
153 format.setSamples(res);
154 }
155
156 QGLWindowSurface::surfaceFormat = format;
157 XFree(vi);
158
159 printf("using visual class %x, id %x\n", X11->visual_class, X11->visual_id);
160 }
161 }
162#elif defined(Q_WS_WIN)
163 QGLWindowSurface::surfaceFormat.setDoubleBuffer(false);
164
165 qt_win_owndc_required = true;
166#endif
167}
168
169//
170// QGLWindowSurface
171//
172
173class QGLGlobalShareWidget
174{
175public:
176 QGLGlobalShareWidget() : widget(0) {}
177
178 QGLWidget *shareWidget() {
179 if (!widget && !cleanedUp) {
180 widget = new QGLWidget;
181 }
182 return widget;
183 }
184
185 void cleanup() {
186 delete widget;
187 widget = 0;
188 cleanedUp = true;
189 }
190
191 static bool cleanedUp;
192
193private:
194 QGLWidget *widget;
195};
196
197bool QGLGlobalShareWidget::cleanedUp = false;
198
199static void qt_cleanup_gl_share_widget();
200Q_GLOBAL_STATIC_WITH_INITIALIZER(QGLGlobalShareWidget, _qt_gl_share_widget,
201 {
202 qAddPostRoutine(qt_cleanup_gl_share_widget);
203 })
204
205static void qt_cleanup_gl_share_widget()
206{
207 _qt_gl_share_widget()->cleanup();
208}
209
210QGLWidget* qt_gl_share_widget()
211{
212 if (QGLGlobalShareWidget::cleanedUp)
213 return 0;
214 return _qt_gl_share_widget()->shareWidget();
215}
216
217struct QGLWindowSurfacePrivate
218{
219 QGLFramebufferObject *fbo;
220 QGLPixelBuffer *pb;
221 GLuint tex_id;
222 GLuint pb_tex_id;
223
224 int tried_fbo : 1;
225 int tried_pb : 1;
226
227 QGLContext *ctx;
228
229 QList<QGLContext **> contexts;
230
231 QRegion paintedRegion;
232 QSize size;
233
234 QList<QImage> buffers;
235};
236
237QGLFormat QGLWindowSurface::surfaceFormat;
238
239QGLWindowSurface::QGLWindowSurface(QWidget *window)
240 : QWindowSurface(window), d_ptr(new QGLWindowSurfacePrivate)
241{
242 Q_ASSERT(window->isTopLevel());
243 QGLExtensions::init();
244 d_ptr->pb = 0;
245 d_ptr->fbo = 0;
246 d_ptr->ctx = 0;
247 d_ptr->tried_fbo = false;
248 d_ptr->tried_pb = false;
249}
250
251QGLWindowSurface::~QGLWindowSurface()
252{
253 if (d_ptr->ctx)
254 glDeleteTextures(1, &d_ptr->tex_id);
255 foreach(QGLContext **ctx, d_ptr->contexts) {
256 delete *ctx;
257 *ctx = 0;
258 }
259
260 delete d_ptr->pb;
261 delete d_ptr->fbo;
262 delete d_ptr;
263}
264
265void QGLWindowSurface::hijackWindow(QWidget *widget)
266{
267 QWidgetPrivate *widgetPrivate = widget->d_func();
268 widgetPrivate->createExtra();
269 if (widgetPrivate->extraData()->glContext)
270 return;
271
272 QGLContext *ctx = new QGLContext(surfaceFormat, widget);
273 ctx->create(qt_gl_share_widget()->context());
274#ifdef Q_WS_MAC
275 ctx->updatePaintDevice();
276#endif
277 widgetPrivate->extraData()->glContext = ctx;
278
279 union { QGLContext **ctxPtr; void **voidPtr; };
280
281 voidPtr = &widgetPrivate->extraData()->glContext;
282 d_ptr->contexts << ctxPtr;
283 qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size();
284}
285
286#if !defined(QT_OPENGL_ES_2)
287Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_window_surface_paintengine)
288#endif
289
290/*! \reimp */
291QPaintEngine *QGLWindowSurface::paintEngine() const
292{
293#if !defined(QT_OPENGL_ES_2)
294 return qt_gl_window_surface_paintengine();
295#else
296 return 0;
297#endif
298}
299
300int QGLWindowSurface::metric(PaintDeviceMetric m) const
301{
302 return window()->metric(m);
303}
304
305QGLContext *QGLWindowSurface::context() const
306{
307 return d_ptr->ctx;
308}
309
310QPaintDevice *QGLWindowSurface::paintDevice()
311{
312 if (d_ptr->pb)
313 return d_ptr->pb;
314
315 if (d_ptr->ctx)
316 return this;
317
318 QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
319 ctx->makeCurrent();
320 return d_ptr->fbo;
321}
322
323static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, const QRectF &src = QRectF());
324
325void QGLWindowSurface::beginPaint(const QRegion &)
326{
327}
328
329void QGLWindowSurface::endPaint(const QRegion &rgn)
330{
331 if (context())
332 d_ptr->paintedRegion |= rgn;
333
334 d_ptr->buffers.clear();
335}
336
337void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset)
338{
339 QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget();
340 Q_ASSERT(parent);
341
342 hijackWindow(parent);
343
344 QRect br = rgn.boundingRect().translated(offset);
345 br = br.intersected(window()->rect());
346 QPoint wOffset = qt_qwidget_data(parent)->wrect.topLeft();
347 QRect rect = br.translated(-offset - wOffset);
348
349 const GLenum target = qt_gl_preferredTextureTarget();
350
351 if (context()) {
352 context()->makeCurrent();
353