Get declarative and wayland EGL backend working for Qt compositor.
[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(winFormat, shareGlContext);
154
155         d->glFormat = QGLFormat::fromSurfaceFormat(d->guiGlContext->format());
156         d->valid = d->guiGlContext->isValid();
157         if (d->valid) {
158             d->guiGlContext->setQGLContextHandle(this,qDeleteQGLContext);
159         }
160         d->setupSharing();
161     }
162
163
164     return d->valid;
165 }
166
167 void QGLContext::reset()
168 {
169     Q_D(QGLContext);
170     if (!d->valid)
171         return;
172     d->cleanup();
173
174     d->crWin = false;
175     d->sharing = false;
176     d->valid = false;
177     d->transpColor = QColor();
178     d->initDone = false;
179     QGLContextGroup::removeShare(this);
180     if (d->guiGlContext) {
181         d->guiGlContext->setQGLContextHandle(0,0);
182     }
183 }
184
185 void QGLContext::makeCurrent()
186 {
187     Q_D(QGLContext);
188     if (!d->paintDevice || d->paintDevice->devType() != QInternal::Widget)
189         return;
190
191     QWidget *widget = static_cast<QWidget *>(d->paintDevice);
192     if (!widget->windowHandle())
193         return;
194
195     if (d->guiGlContext->makeCurrent(widget->windowHandle())) {
196         if (!d->workaroundsCached) {
197             d->workaroundsCached = true;
198             const char *renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
199             if (renderer && strstr(renderer, "Mali")) {
200                 d->workaround_brokenFBOReadBack = true;
201             }
202         }
203     }
204 }
205
206 void QGLContext::doneCurrent()
207 {
208     Q_D(QGLContext);
209     d->guiGlContext->doneCurrent();
210 }
211
212 void QGLContext::swapBuffers() const
213 {
214     Q_D(const QGLContext);
215     if (!d->paintDevice || d->paintDevice->devType() != QInternal::Widget)
216         return;
217
218     QWidget *widget = static_cast<QWidget *>(d->paintDevice);
219     if (!widget->windowHandle())
220         return;
221
222     d->guiGlContext->swapBuffers(widget->windowHandle());
223 }
224
225 void *QGLContext::getProcAddress(const QString &procName) const
226 {
227     Q_D(const QGLContext);
228     return (void *)d->guiGlContext->getProcAddress(procName.toAscii());
229 }
230
231 void QGLWidget::setContext(QGLContext *context,
232                             const QGLContext* shareContext,
233                             bool deleteOldContext)
234 {
235     Q_D(QGLWidget);
236     if (context == 0) {
237         qWarning("QGLWidget::setContext: Cannot set null context");
238         return;
239     }
240
241     if (context->device() == 0) // a context may refere to more than 1 window.
242         context->setDevice(this); //but its better to point to 1 of them than none of them.
243
244     QGLContext* oldcx = d->glcx;
245     d->glcx = context;
246
247     if (!d->glcx->isValid())
248         d->glcx->create(shareContext ? shareContext : oldcx);
249
250     if (deleteOldContext)
251         delete oldcx;
252 }
253
254 void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
255 {
256     initContext(context, shareWidget);
257 }
258
259 bool QGLFormat::hasOpenGLOverlays()
260 {
261     return false;
262 }
263
264 QColor QGLContext::overlayTransparentColor() const
265 {
266     return QColor(); // Invalid color
267 }
268
269 uint QGLContext::colorIndex(const QColor&) const
270 {
271     return 0;
272 }
273
274 void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
275 {
276     Q_UNUSED(fnt);
277     Q_UNUSED(listBase);
278 }
279
280 /*
281     QGLTemporaryContext implementation
282 */
283 class QGLTemporaryContextPrivate
284 {
285 public:
286     QWindow *window;
287     QGuiGLContext *context;
288
289     QGLContext *oldContext;
290 };
291
292 QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
293     : d(new QGLTemporaryContextPrivate)
294 {
295     d->oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
296
297     d->window = new QWindow;
298     d->window->setSurfaceType(QWindow::OpenGLSurface);
299     d->window->setGeometry(QRect(0, 0, 3, 3));
300     d->window->create();
301
302     d->context = new QGuiGLContext;
303     d->context->makeCurrent(d->window);
304 }
305
306 QGLTemporaryContext::~QGLTemporaryContext()
307 {
308     if (d->oldContext)
309         d->oldContext->makeCurrent();
310
311     delete d->context;
312     delete d->window;
313 }
314
315
316 bool QGLWidgetPrivate::renderCxPm(QPixmap*)
317 {
318     return false;
319 }
320
321 /*! \internal
322   Free up any allocated colormaps. This fn is only called for
323   top-level widgets.
324 */
325 void QGLWidgetPrivate::cleanupColormaps()
326 {
327 }
328
329 void QGLWidget::setMouseTracking(bool enable)
330 {
331     Q_UNUSED(enable);
332 }
333
334 bool QGLWidget::event(QEvent *e)
335 {
336     return QWidget::event(e);
337 }
338
339 void QGLWidget::resizeEvent(QResizeEvent *e)
340 {
341     Q_D(QGLWidget);
342
343     QWidget::resizeEvent(e);
344     if (!isValid())
345         return;
346     makeCurrent();
347     if (!d->glcx->initialized())
348         glInit();
349     resizeGL(width(), height());
350 }
351
352
353 const QGLContext* QGLWidget::overlayContext() const
354 {
355     return 0;
356 }
357
358 void QGLWidget::makeOverlayCurrent()
359 {
360 }
361
362
363 void QGLWidget::updateOverlayGL()
364 {
365 }
366
367 const QGLColormap & QGLWidget::colormap() const
368 {
369     Q_D(const QGLWidget);
370     return d->cmap;
371 }
372
373 void QGLWidget::setColormap(const QGLColormap & c)
374 {
375     Q_UNUSED(c);
376 }
377
378 QGLContext::QGLContext(QGuiGLContext *context)
379     : d_ptr(new QGLContextPrivate(this))
380 {
381     Q_D(QGLContext);
382     d->init(0, QGLFormat::fromSurfaceFormat(context->format()));
383     d->guiGlContext = context;
384     d->guiGlContext->setQGLContextHandle(this,qDeleteQGLContext);
385     d->valid = context->isValid();
386     d->setupSharing();
387 }
388
389 QGuiGLContext *QGLContext::contextHandle() const
390 {
391     Q_D(const QGLContext);
392     return d->guiGlContext;
393 }
394
395 /*!
396     Returns a OpenGL context for the window context specified by \a windowContext
397 */
398 QGLContext *QGLContext::fromGuiGLContext(QGuiGLContext *context)
399 {
400     if (!context)
401         return 0;
402     if (context->qGLContextHandle()) {
403         return reinterpret_cast<QGLContext *>(context->qGLContextHandle());
404     }
405     QGLContext *glContext = new QGLContext(context);
406     //Dont call create on context. This can cause the platformFormat to be set on the widget, which
407     //will cause the platformWindow to be recreated.
408     return glContext;
409 }
410
411 QT_END_NAMESPACE