Merge branch 'master' into refactor
[qt:qtbase.git] / src / opengl / qgl_qpa.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QApplication>
43 #include <private/qapplication_p.h>
44 #include <QPixmap>
45 #include <QDebug>
46
47 #include <private/qapplication_p.h>
48 #include <QtGui/QPlatformGLContext>
49 #include <QtGui/QPlatformWindow>
50 #include <QtGui/QSurfaceFormat>
51
52 #include "qgl.h"
53 #include "qgl_p.h"
54
55 QT_BEGIN_NAMESPACE
56
57 /*!
58     Returns an OpenGL format for the window format specified by \a format.
59 */
60 QGLFormat QGLFormat::fromSurfaceFormat(const QSurfaceFormat &format)
61 {
62     QGLFormat retFormat;
63     if (format.alphaBufferSize() >= 0)
64         retFormat.setAlphaBufferSize(format.alphaBufferSize());
65     if (format.blueBufferSize() >= 0)
66         retFormat.setBlueBufferSize(format.blueBufferSize());
67     if (format.greenBufferSize() >= 0)
68         retFormat.setGreenBufferSize(format.greenBufferSize());
69     if (format.redBufferSize() >= 0)
70         retFormat.setRedBufferSize(format.redBufferSize());
71     if (format.depthBufferSize() >= 0)
72         retFormat.setDepthBufferSize(format.depthBufferSize());
73     if (format.samples() > 1) {
74         retFormat.setSampleBuffers(format.samples());
75         retFormat.setSamples(true);
76     }
77     if (format.stencilBufferSize() > 0) {
78         retFormat.setStencil(true);
79         retFormat.setStencilBufferSize(format.stencilBufferSize());
80     }
81     retFormat.setDoubleBuffer(format.swapBehavior() != QSurfaceFormat::SingleBuffer);
82     retFormat.setStereo(format.stereo());
83     return retFormat;
84 }
85
86 /*!
87     Returns a window format for the OpenGL format specified by \a format.
88 */
89 QSurfaceFormat QGLFormat::toSurfaceFormat(const QGLFormat &format)
90 {
91     QSurfaceFormat retFormat;
92     if (format.alpha())
93         retFormat.setAlphaBufferSize(format.alphaBufferSize() == -1 ? 1 : format.alphaBufferSize());
94     if (format.blueBufferSize() >= 0)
95         retFormat.setBlueBufferSize(format.blueBufferSize());
96     if (format.greenBufferSize() >= 0)
97         retFormat.setGreenBufferSize(format.greenBufferSize());
98     if (format.redBufferSize() >= 0)
99         retFormat.setRedBufferSize(format.redBufferSize());
100     if (format.depth())
101         retFormat.setDepthBufferSize(format.depthBufferSize() == -1 ? 1 : format.depthBufferSize());
102     retFormat.setSwapBehavior(format.doubleBuffer() ? QSurfaceFormat::DoubleBuffer : QSurfaceFormat::DefaultSwapBehavior);
103     if (format.sampleBuffers())
104         retFormat.setSamples(format.samples() == -1 ? 4 : format.samples());
105     if (format.stencil())
106         retFormat.setStencilBufferSize(format.stencilBufferSize() == -1 ? 1 : format.stencilBufferSize());
107     retFormat.setStereo(format.stereo());
108     return retFormat;
109 }
110
111 void QGLContextPrivate::setupSharing() {
112     Q_Q(QGLContext);
113     QGuiGLContext *sharedContext = guiGlContext->shareContext();
114     if (sharedContext) {
115         QGLContext *actualSharedContext = QGLContext::fromGuiGLContext(sharedContext);
116         sharing = true;
117         QGLContextGroup::addShare(q, actualSharedContext);
118     }
119 }
120
121 bool QGLFormat::hasOpenGL()
122 {
123     return QApplicationPrivate::platformIntegration()
124             ->hasCapability(QPlatformIntegration::OpenGL);
125 }
126
127 void qDeleteQGLContext(void *handle)
128 {
129     QGLContext *context = static_cast<QGLContext *>(handle);
130     delete context;
131 }
132
133 bool QGLContext::chooseContext(const QGLContext* shareContext)
134 {
135     Q_D(QGLContext);
136     if(!d->paintDevice || d->paintDevice->devType() != QInternal::Widget) {
137         d->valid = false;
138     }else {
139         QWidget *widget = static_cast<QWidget *>(d->paintDevice);
140         QGLFormat glformat = format();
141         QSurfaceFormat winFormat = QGLFormat::toSurfaceFormat(glformat);
142         if (widget->testAttribute(Qt::WA_TranslucentBackground))
143             winFormat.setAlphaBufferSize(qMax(winFormat.alphaBufferSize(), 8));
144
145         if (!widget->windowHandle()->handle()) {
146             widget->windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
147             widget->windowHandle()->setFormat(winFormat);
148             widget->winId();//make window
149         }
150
151         delete d->guiGlContext;
152         QGuiGLContext *shareGlContext = shareContext ? shareContext->d_func()->guiGlContext : 0;
153         d->guiGlContext = new QGuiGLContext;
154         d->guiGlContext->setFormat(winFormat);
155         d->guiGlContext->setShareContext(shareGlContext);
156         d->valid = d->guiGlContext->create();
157
158         if (d->valid)
159             d->guiGlContext->setQGLContextHandle(this,qDeleteQGLContext);
160
161         d->glFormat = QGLFormat::fromSurfaceFormat(d->guiGlContext->format());
162         d->setupSharing();
163     }
164
165
166     return d->valid;
167 }
168
169 void QGLContext::reset()
170 {
171     Q_D(QGLContext);
172     if (!d->valid)
173         return;
174     d->cleanup();
175
176     d->crWin = false;
177     d->sharing = false;
178     d->valid = false;
179     d->transpColor = QColor();
180     d->initDone = false;
181     QGLContextGroup::removeShare(this);
182     if (d->guiGlContext) {
183         d->guiGlContext->setQGLContextHandle(0,0);
184     }
185 }
186
187 void QGLContext::makeCurrent()
188 {
189     Q_D(QGLContext);
190     if (!d->paintDevice || d->paintDevice->devType() != QInternal::Widget)
191         return;
192
193     QWidget *widget = static_cast<QWidget *>(d->paintDevice);
194     if (!widget->windowHandle())
195         return;
196
197     if (d->guiGlContext->makeCurrent(widget->windowHandle())) {
198         if (!d->workaroundsCached) {
199             d->workaroundsCached = true;
200             const char *renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
201             if (renderer && strstr(renderer, "Mali")) {
202                 d->workaround_brokenFBOReadBack = true;
203             }
204         }
205     }
206 }
207
208 void QGLContext::doneCurrent()
209 {
210     Q_D(QGLContext);
211     d->guiGlContext->doneCurrent();
212 }
213
214 void QGLContext::swapBuffers() const
215 {
216     Q_D(const QGLContext);
217     if (!d->paintDevice || d->paintDevice->devType() != QInternal::Widget)
218         return;
219
220     QWidget *widget = static_cast<QWidget *>(d->paintDevice);
221     if (!widget->windowHandle())
222         return;
223
224     d->guiGlContext->swapBuffers(widget->windowHandle());
225 }
226
227 void *QGLContext::getProcAddress(const QString &procName) const
228 {
229     Q_D(const QGLContext);
230     return (void *)d->guiGlContext->getProcAddress(procName.toAscii());
231 }
232
233 void QGLWidget::setContext(QGLContext *context,
234                             const QGLContext* shareContext,
235                             bool deleteOldContext)
236 {
237     Q_D(QGLWidget);
238     if (context == 0) {
239         qWarning("QGLWidget::setContext: Cannot set null context");
240         return;
241     }
242
243     if (context->device() == 0) // a context may refere to more than 1 window.
244         context->setDevice(this); //but its better to point to 1 of them than none of them.
245
246     QGLContext* oldcx = d->glcx;
247     d->glcx = context;
248
249     if (!d->glcx->isValid())
250         d->glcx->create(shareContext ? shareContext : oldcx);
251
252     if (deleteOldContext)
253         delete oldcx;
254 }
255
256 void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
257 {
258     initContext(context, shareWidget);
259 }
260
261 bool QGLFormat::hasOpenGLOverlays()
262 {
263     return false;
264 }
265
266 QColor QGLContext::overlayTransparentColor() const
267 {
268     return QColor(); // Invalid color
269 }
270
271 uint QGLContext::colorIndex(const QColor&) const
272 {
273     return 0;
274 }
275
276 void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
277 {
278     Q_UNUSED(fnt);
279     Q_UNUSED(listBase);
280 }
281
282 /*
283     QGLTemporaryContext implementation
284 */
285 class QGLTemporaryContextPrivate
286 {
287 public:
288     QWindow *window;
289     QGuiGLContext *context;
290
291     QGLContext *oldContext;
292 };
293
294 QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
295     : d(new QGLTemporaryContextPrivate)
296 {
297     d->oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
298
299     d->window = new QWindow;
300     d->window->setSurfaceType(QWindow::OpenGLSurface);
301     d->window->setGeometry(QRect(0, 0, 3, 3));
302     d->window->create();
303
304     d->context = new QGuiGLContext;
305     d->context->create();
306     d->context->makeCurrent(d->window);
307 }
308
309 QGLTemporaryContext::~QGLTemporaryContext()
310 {
311     if (d->oldContext)
312         d->oldContext->makeCurrent();
313
314     delete d->context;
315     delete d->window;
316 }
317
318
319 bool QGLWidgetPrivate::renderCxPm(QPixmap*)
320 {
321     return false;
322 }
323
324 /*! \internal
325   Free up any allocated colormaps. This fn is only called for
326   top-level widgets.
327 */
328 void QGLWidgetPrivate::cleanupColormaps()
329 {
330 }
331
332 void QGLWidget::setMouseTracking(bool enable)
333 {
334     Q_UNUSED(enable);
335 }
336
337 bool QGLWidget::event(QEvent *e)
338 {
339     return QWidget::event(e);
340 }
341
342 void QGLWidget::resizeEvent(QResizeEvent *e)
343 {
344     Q_D(QGLWidget);
345
346     QWidget::resizeEvent(e);
347     if (!isValid())
348         return;
349     makeCurrent();
350     if (!d->glcx->initialized())
351         glInit();
352     resizeGL(width(), height());
353 }
354
355
356 const QGLContext* QGLWidget::overlayContext() const
357 {
358     return 0;
359 }
360
361 void QGLWidget::makeOverlayCurrent()
362 {
363 }
364
365
366 void QGLWidget::updateOverlayGL()
367 {
368 }
369
370 const QGLColormap & QGLWidget::colormap() const
371 {
372     Q_D(const QGLWidget);
373     return d->cmap;
374 }
375
376 void QGLWidget::setColormap(const QGLColormap & c)
377 {
378     Q_UNUSED(c);
379 }
380
381 QGLContext::QGLContext(QGuiGLContext *context)
382     : d_ptr(new QGLContextPrivate(this))
383 {
384     Q_D(QGLContext);
385     d->init(0, QGLFormat::fromSurfaceFormat(context->format()));
386     d->guiGlContext = context;
387     d->guiGlContext->setQGLContextHandle(this,qDeleteQGLContext);
388     d->valid = context->isValid();
389     d->setupSharing();
390 }
391
392 QGuiGLContext *QGLContext::contextHandle() const
393 {
394     Q_D(const QGLContext);
395     return d->guiGlContext;
396 }
397
398 /*!
399     Returns a OpenGL context for the window context specified by \a windowContext
400 */
401 QGLContext *QGLContext::fromGuiGLContext(QGuiGLContext *context)
402 {
403     if (!context)
404         return 0;
405     if (context->qGLContextHandle()) {
406         return reinterpret_cast<QGLContext *>(context->qGLContextHandle());
407     }
408     QGLContext *glContext = new QGLContext(context);
409     //Dont call create on context. This can cause the platformFormat to be set on the widget, which
410     //will cause the platformWindow to be recreated.
411     return glContext;
412 }
413
414 QT_END_NAMESPACE