Fix setMouseTracking on QGLWidget
[qt:qtbase.git] / src / opengl / qgl_qpa.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
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 <qpa/qplatformopenglcontext.h>
49 #include <qpa/qplatformwindow.h>
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     QOpenGLContext *sharedContext = guiGlContext->shareContext();
114     if (sharedContext) {
115         QGLContext *actualSharedContext = QGLContext::fromOpenGLContext(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         if (d->ownContext)
152             delete d->guiGlContext;
153         d->ownContext = true;
154         QOpenGLContext *shareGlContext = shareContext ? shareContext->d_func()->guiGlContext : 0;
155         d->guiGlContext = new QOpenGLContext;
156         d->guiGlContext->setFormat(winFormat);
157         d->guiGlContext->setShareContext(shareGlContext);
158         d->valid = d->guiGlContext->create();
159
160         if (d->valid)
161             d->guiGlContext->setQGLContextHandle(this,qDeleteQGLContext);
162
163         d->glFormat = QGLFormat::fromSurfaceFormat(d->guiGlContext->format());
164         d->setupSharing();
165     }
166
167
168     return d->valid;
169 }
170
171 void QGLContext::reset()
172 {
173     Q_D(QGLContext);
174     if (!d->valid)
175         return;
176     d->cleanup();
177
178     d->crWin = false;
179     d->sharing = false;
180     d->valid = false;
181     d->transpColor = QColor();
182     d->initDone = false;
183     QGLContextGroup::removeShare(this);
184     if (d->guiGlContext) {
185         if (d->ownContext)
186             delete d->guiGlContext;
187         else
188             d->guiGlContext->setQGLContextHandle(0,0);
189         d->guiGlContext = 0;
190     }
191     d->ownContext = false;
192 }
193
194 void QGLContext::makeCurrent()
195 {
196     Q_D(QGLContext);
197     if (!d->paintDevice || d->paintDevice->devType() != QInternal::Widget)
198         return;
199
200     QWidget *widget = static_cast<QWidget *>(d->paintDevice);
201     if (!widget->windowHandle())
202         return;
203
204     if (d->guiGlContext->makeCurrent(widget->windowHandle())) {
205         if (!d->workaroundsCached) {
206             d->workaroundsCached = true;
207             const char *renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
208             if (renderer && strstr(renderer, "Mali")) {
209                 d->workaround_brokenFBOReadBack = true;
210             }
211         }
212     }
213 }
214
215 void QGLContext::doneCurrent()
216 {
217     Q_D(QGLContext);
218     d->guiGlContext->doneCurrent();
219 }
220
221 void QGLContext::swapBuffers() const
222 {
223     Q_D(const QGLContext);
224     if (!d->paintDevice || d->paintDevice->devType() != QInternal::Widget)
225         return;
226
227     QWidget *widget = static_cast<QWidget *>(d->paintDevice);
228     if (!widget->windowHandle())
229         return;
230
231     d->guiGlContext->swapBuffers(widget->windowHandle());
232 }
233
234 QFunctionPointer QGLContext::getProcAddress(const QString &procName) const
235 {
236     Q_D(const QGLContext);
237     return d->guiGlContext->getProcAddress(procName.toLatin1());
238 }
239
240 void QGLWidget::setContext(QGLContext *context,
241                             const QGLContext* shareContext,
242                             bool deleteOldContext)
243 {
244     Q_D(QGLWidget);
245     if (context == 0) {
246         qWarning("QGLWidget::setContext: Cannot set null context");
247         return;
248     }
249
250     if (context->device() == 0) // a context may refere to more than 1 window.
251         context->setDevice(this); //but its better to point to 1 of them than none of them.
252
253     QGLContext* oldcx = d->glcx;
254     d->glcx = context;
255
256     if (!d->glcx->isValid())
257         d->glcx->create(shareContext ? shareContext : oldcx);
258
259     if (deleteOldContext)
260         delete oldcx;
261 }
262
263 void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
264 {
265     initContext(context, shareWidget);
266 }
267
268 bool QGLFormat::hasOpenGLOverlays()
269 {
270     return false;
271 }
272
273 QColor QGLContext::overlayTransparentColor() const
274 {
275     return QColor(); // Invalid color
276 }
277
278 uint QGLContext::colorIndex(const QColor&) const
279 {
280     return 0;
281 }
282
283 void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
284 {
285     Q_UNUSED(fnt);
286     Q_UNUSED(listBase);
287 }
288
289 /*
290     QGLTemporaryContext implementation
291 */
292 class QGLTemporaryContextPrivate
293 {
294 public:
295     QWindow *window;
296     QOpenGLContext *context;
297
298     QGLContext *oldContext;
299 };
300
301 QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
302     : d(new QGLTemporaryContextPrivate)
303 {
304     d->oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
305
306     d->window = new QWindow;
307     d->window->setSurfaceType(QWindow::OpenGLSurface);
308     d->window->setGeometry(QRect(0, 0, 3, 3));
309     d->window->create();
310
311     d->context = new QOpenGLContext;
312     d->context->create();
313     d->context->makeCurrent(d->window);
314 }
315
316 QGLTemporaryContext::~QGLTemporaryContext()
317 {
318     if (d->oldContext)
319         d->oldContext->makeCurrent();
320
321     delete d->context;
322     delete d->window;
323 }
324
325
326 bool QGLWidgetPrivate::renderCxPm(QPixmap*)
327 {
328     return false;
329 }
330
331 /*! \internal
332   Free up any allocated colormaps. This fn is only called for
333   top-level widgets.
334 */
335 void QGLWidgetPrivate::cleanupColormaps()
336 {
337 }
338
339 bool QGLWidget::event(QEvent *e)
340 {
341     return QWidget::event(e);
342 }
343
344 void QGLWidget::resizeEvent(QResizeEvent *e)
345 {
346     Q_D(QGLWidget);
347
348     QWidget::resizeEvent(e);
349     if (!isValid())
350         return;
351     makeCurrent();
352     if (!d->glcx->initialized())
353         glInit();
354     resizeGL(width(), height());
355 }
356
357
358 const QGLContext* QGLWidget::overlayContext() const
359 {
360     return 0;
361 }
362
363 void QGLWidget::makeOverlayCurrent()
364 {
365 }
366
367
368 void QGLWidget::updateOverlayGL()
369 {
370 }
371
372 const QGLColormap & QGLWidget::colormap() const
373 {
374     Q_D(const QGLWidget);
375     return d->cmap;
376 }
377
378 void QGLWidget::setColormap(const QGLColormap & c)
379 {
380     Q_UNUSED(c);
381 }
382
383 QGLContext::QGLContext(QOpenGLContext *context)
384     : d_ptr(new QGLContextPrivate(this))
385 {
386     Q_D(QGLContext);
387     d->init(0, QGLFormat::fromSurfaceFormat(context->format()));
388     d->guiGlContext = context;
389     d->guiGlContext->setQGLContextHandle(this,qDeleteQGLContext);
390     d->ownContext = false;
391     d->valid = context->isValid();
392     d->setupSharing();
393 }
394
395 QOpenGLContext *QGLContext::contextHandle() const
396 {
397     Q_D(const QGLContext);
398     return d->guiGlContext;
399 }
400
401 /*!
402     Returns a OpenGL context for the window context specified by \a windowContext
403 */
404 QGLContext *QGLContext::fromOpenGLContext(QOpenGLContext *context)
405 {
406     if (!context)
407         return 0;
408     if (context->qGLContextHandle()) {
409         return reinterpret_cast<QGLContext *>(context->qGLContextHandle());
410     }
411     QGLContext *glContext = new QGLContext(context);
412     //Dont call create on context. This can cause the platformFormat to be set on the widget, which
413     //will cause the platformWindow to be recreated.
414     return glContext;
415 }
416
417 QT_END_NAMESPACE