Merge branch 'master' of scm.dev.nokia.troll.no:qt/qt-doc-staging
[qt:qt.git] / src / opengl / qglpixelbuffer.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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
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 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 /*!
43     \class QGLPixelBuffer
44     \brief The QGLPixelBuffer class encapsulates an OpenGL pbuffer.
45     \since 4.1
46
47     \ingroup painting-3D
48
49     Rendering into a pbuffer is normally done using full hardware
50     acceleration. This can be significantly faster than rendering
51     into a QPixmap.
52
53     There are three approaches to using this class:
54
55     \list 1
56     \o \bold{We can draw into the pbuffer and convert it to a QImage
57        using toImage().} This is normally much faster than calling
58        QGLWidget::renderPixmap().
59
60     \o \bold{We can draw into the pbuffer and copy the contents into
61        an OpenGL texture using updateDynamicTexture().} This allows
62        us to create dynamic textures and works on all systems
63        with pbuffer support.
64
65     \o \bold{On systems that support it, we can bind the pbuffer to
66        an OpenGL texture.} The texture is then updated automatically
67        when the pbuffer contents change, eliminating the need for
68        additional copy operations. This is supported only on Windows
69        and Mac OS X systems that provide the \c render_texture
70        extension. Note that under Windows, a multi-sampled pbuffer
71        can't be used in conjunction with the \c render_texture
72        extension. If a multi-sampled pbuffer is requested under
73        Windows, the \c render_texture extension is turned off for that
74        pbuffer.
75
76
77     \endlist
78
79
80     \section1 Threading
81
82     As of Qt 4.8, it's possible to render into a QGLPixelBuffer using
83     a QPainter in a separate thread. Note that OpenGL 2.0 or OpenGL ES
84     2.0 is required for this to work. Also, under X11, it's necessary
85     to set the Qt::AA_X11InitThreads application attribute.
86
87     Pbuffers are provided by the OpenGL \c pbuffer extension; call
88     hasOpenGLPbuffer() to find out if the system provides pbuffers.
89
90     \sa {opengl/pbuffers}{Pbuffers Example}
91 */
92
93 #include <QtCore/qglobal.h>
94
95 #if !defined(QT_OPENGL_ES_1)
96 #include <private/qpaintengineex_opengl2_p.h>
97 #endif
98
99 #include <qglpixelbuffer.h>
100 #include <private/qglpixelbuffer_p.h>
101 #include <private/qfont_p.h>
102 #include <qimage.h>
103
104 #ifndef QT_OPENGL_ES_2
105 #include <private/qpaintengine_opengl_p.h>
106 #endif
107
108 QT_BEGIN_NAMESPACE
109
110 #if !defined(QT_OPENGL_ES_2)
111 extern void qgl_cleanup_glyph_cache(QGLContext *);
112 #else
113 void qgl_cleanup_glyph_cache(QGLContext *) {}
114 #endif
115
116 extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
117
118
119 QGLContext* QGLPBufferGLPaintDevice::context() const
120 {
121     return pbuf->d_func()->qctx;
122 }
123
124 void QGLPBufferGLPaintDevice::endPaint() {
125     glFlush();
126     QGLPaintDevice::endPaint();
127 }
128
129 void QGLPBufferGLPaintDevice::setPBuffer(QGLPixelBuffer* pb)
130 {
131     pbuf = pb;
132 }
133
134 void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
135 {
136     Q_Q(QGLPixelBuffer);
137     if(init(size, format, shareWidget)) {
138         req_size = size;
139         req_format = format;
140         req_shareWidget = shareWidget;
141         invalid = false;
142         qctx = new QGLContext(format);
143         qctx->d_func()->sharing = (shareWidget != 0);
144         if (shareWidget != 0 && shareWidget->d_func()->glcx) {
145             QGLContextGroup::addShare(qctx, shareWidget->d_func()->glcx);
146             shareWidget->d_func()->glcx->d_func()->sharing = true;
147         }
148
149         glDevice.setPBuffer(q);
150         qctx->d_func()->paintDevice = q;
151         qctx->d_func()->valid = true;
152 #if defined(Q_WS_WIN) && !defined(QT_OPENGL_ES)
153         qctx->d_func()->dc = dc;
154         qctx->d_func()->rc = ctx;
155 #elif (defined(Q_WS_X11) && defined(QT_NO_EGL))
156         qctx->d_func()->cx = ctx;
157         qctx->d_func()->pbuf = (void *) pbuf;
158         qctx->d_func()->vi = 0;
159 #elif defined(Q_WS_MAC)
160         qctx->d_func()->cx = ctx;
161         qctx->d_func()->vi = 0;
162 #elif !defined(QT_NO_EGL)
163         qctx->d_func()->eglContext = ctx;
164         qctx->d_func()->eglSurface = pbuf;
165 #endif
166     }
167 }
168
169 /*!
170     Constructs an OpenGL pbuffer of the given \a size. If no \a
171     format is specified, the \l{QGLFormat::defaultFormat()}{default
172     format} is used. If the \a shareWidget parameter points to a
173     valid QGLWidget, the pbuffer will share its context with \a
174     shareWidget.
175
176     If you intend to bind this pbuffer as a dynamic texture, the width
177     and height components of \c size must be powers of two (e.g., 512
178     x 128).
179
180     \sa size(), format()
181 */
182 QGLPixelBuffer::QGLPixelBuffer(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
183     : d_ptr(new QGLPixelBufferPrivate(this))
184 {
185     Q_D(QGLPixelBuffer);
186     d->common_init(size, format, shareWidget);
187 }
188
189
190 /*! \overload
191
192     Constructs an OpenGL pbuffer with the \a width and \a height. If
193     no \a format is specified, the
194     \l{QGLFormat::defaultFormat()}{default format} is used. If the \a
195     shareWidget parameter points to a valid QGLWidget, the pbuffer
196     will share its context with \a shareWidget.
197
198     If you intend to bind this pbuffer as a dynamic texture, the width
199     and height components of \c size must be powers of two (e.g., 512
200     x 128).
201
202     \sa size(), format()
203 */
204 QGLPixelBuffer::QGLPixelBuffer(int width, int height, const QGLFormat &format, QGLWidget *shareWidget)
205     : d_ptr(new QGLPixelBufferPrivate(this))
206 {
207     Q_D(QGLPixelBuffer);
208     d->common_init(QSize(width, height), format, shareWidget);
209 }
210
211
212 /*! \fn QGLPixelBuffer::~QGLPixelBuffer()
213
214     Destroys the pbuffer and frees any allocated resources.
215 */
216 QGLPixelBuffer::~QGLPixelBuffer()
217 {
218     Q_D(QGLPixelBuffer);
219
220     // defined in qpaintengine_opengl.cpp
221     QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext());
222     if (current != d->qctx)
223         makeCurrent();
224     qgl_cleanup_glyph_cache(d->qctx);
225     d->cleanup();
226     delete d->qctx;
227     if (current && current != d->qctx)
228         current->makeCurrent();
229 }
230
231 /*! \fn bool QGLPixelBuffer::makeCurrent()
232
233     Makes this pbuffer the current OpenGL rendering context. Returns
234     true on success; otherwise returns false.
235
236     \sa QGLContext::makeCurrent(), doneCurrent()
237 */
238
239 bool QGLPixelBuffer::makeCurrent()
240 {
241     Q_D(QGLPixelBuffer);
242     if (d->invalid)
243         return false;
244     d->qctx->makeCurrent();
245     return true;
246 }
247
248 /*! \fn bool QGLPixelBuffer::doneCurrent()
249
250     Makes no context the current OpenGL context. Returns true on
251     success; otherwise returns false.
252 */
253
254 bool QGLPixelBuffer::doneCurrent()
255 {
256     Q_D(QGLPixelBuffer);
257     if (d->invalid)
258         return false;
259     d->qctx->doneCurrent();
260     return true;
261 }
262
263 /*!
264     Generates and binds a 2D GL texture that is the same size as the
265     pbuffer, and returns the texture's ID. This can be used in
266     conjunction with bindToDynamicTexture() and
267     updateDynamicTexture().
268
269     \sa size()
270 */
271
272 #if (defined(Q_WS_X11) || defined(Q_WS_WIN)) && defined(QT_NO_EGL)
273 GLuint QGLPixelBuffer::generateDynamicTexture() const
274 {
275     Q_D(const QGLPixelBuffer);
276     GLuint texture;
277     glGenTextures(1, &texture);
278     glBindTexture(GL_TEXTURE_2D, texture);
279     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, d->req_size.width(), d->req_size.height(), 0, GL_RGBA, GL_FLOAT, 0);
280     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
281     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
282     return texture;
283 }
284 #endif
285
286 /*! \fn bool QGLPixelBuffer::bindToDynamicTexture(GLuint texture_id)
287
288     Binds the texture specified by \a texture_id to this pbuffer.
289     Returns true on success; otherwise returns false.
290
291     The texture must be of the same size and format as the pbuffer.
292
293     To unbind the texture, call releaseFromDynamicTexture(). While
294     the texture is bound, it is updated automatically when the
295     pbuffer contents change, eliminating the need for additional copy
296     operations.
297
298     Example:
299
300     \snippet doc/src/snippets/code/src_opengl_qglpixelbuffer.cpp 0
301
302     \warning This function uses the \c {render_texture} extension,
303     which is currently not supported under X11. An alternative that
304     works on all systems (including X11) is to manually copy the
305     pbuffer contents to a texture using updateDynamicTexture().
306
307     \warning For the bindToDynamicTexture() call to succeed on the
308     Mac OS X, the pbuffer needs a shared context, i.e. the
309     QGLPixelBuffer must be created with a share widget.
310
311     \sa generateDynamicTexture(), releaseFromDynamicTexture()
312 */
313
314 /*! \fn void QGLPixelBuffer::releaseFromDynamicTexture()
315
316     Releases the pbuffer from any previously bound texture.
317
318     \sa bindToDynamicTexture()
319 */
320
321 /*! \fn bool QGLPixelBuffer::hasOpenGLPbuffers()
322
323     Returns true if the OpenGL \c pbuffer extension is present on
324     this system; otherwise returns false.
325 */
326
327 /*!
328     Copies the pbuffer contents into the texture specified with \a
329     texture_id.
330
331     The texture must be of the same size and format as the pbuffer.
332
333     Example:
334
335     \snippet doc/src/snippets/code/src_opengl_qglpixelbuffer.cpp 1
336
337     An alternative on Windows and Mac OS X systems that support the
338     \c render_texture extension is to use bindToDynamicTexture() to
339     get dynamic updates of the texture.
340
341     \sa generateDynamicTexture(), bindToDynamicTexture()
342 */
343 void QGLPixelBuffer::updateDynamicTexture(GLuint texture_id) const
344 {
345     Q_D(const QGLPixelBuffer);
346     if (d->invalid)
347         return;
348     glBindTexture(GL_TEXTURE_2D, texture_id);
349 #ifndef QT_OPENGL_ES
350     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, d->req_size.width(), d->req_size.height(), 0);
351 #else
352     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, d->req_size.width(), d->req_size.height(), 0);
353 #endif
354 }
355
356 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
357 void QGLPixelBuffer::updateDynamicTexture(QMacCompatGLuint texture_id) const
358 {
359     updateDynamicTexture(GLuint(texture_id));
360 }
361 #endif
362
363 /*!
364     Returns the size of the pbuffer.
365 */
366 QSize QGLPixelBuffer::size() const
367 {
368     Q_D(const QGLPixelBuffer);
369     return d->req_size;
370 }
371
372 /*!
373     Returns the contents of the pbuffer as a QImage.
374 */
375 QImage QGLPixelBuffer::toImage() const
376 {
377     Q_D(const QGLPixelBuffer);
378     if (d->invalid)
379         return QImage();
380
381     const_cast<QGLPixelBuffer *>(this)->makeCurrent();
382     return qt_gl_read_framebuffer(d->req_size, d->format.alpha(), true);
383 }
384
385 /*!
386     Returns the native pbuffer handle.
387 */
388 Qt::HANDLE QGLPixelBuffer::handle() const
389 {
390     Q_D(const QGLPixelBuffer);
391     if (d->invalid)
392         return 0;
393     return (Qt::HANDLE) d->pbuf;
394 }
395
396 /*!
397     Returns true if this pbuffer is valid; otherwise returns false.
398 */
399 bool QGLPixelBuffer::isValid() const
400 {
401     Q_D(const QGLPixelBuffer);
402     return !d->invalid;
403 }
404
405 #if !defined(QT_OPENGL_ES_1)
406 Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>, qt_buffer_2_engine)
407 #endif
408
409 #ifndef QT_OPENGL_ES_2
410 Q_GLOBAL_STATIC(QGLEngineThreadStorage<QOpenGLPaintEngine>, qt_buffer_engine)
411 #endif
412
413 /*! \reimp */
414 QPaintEngine *QGLPixelBuffer::paintEngine() const
415 {
416 #if defined(QT_OPENGL_ES_1)
417     return qt_buffer_engine()->engine();
418 #elif defined(QT_OPENGL_ES_2)
419     return qt_buffer_2_engine()->engine();
420 #else
421     if (qt_gl_preferGL2Engine())
422         return qt_buffer_2_engine()->engine();
423     else
424         return qt_buffer_engine()->engine();
425 #endif
426 }
427
428 /*! \reimp */
429 int QGLPixelBuffer::metric(PaintDeviceMetric metric) const
430 {
431     Q_D(const QGLPixelBuffer);
432
433     float dpmx = qt_defaultDpiX()*100./2.54;
434     float dpmy = qt_defaultDpiY()*100./2.54;
435     int w = d->req_size.width();
436     int h = d->req_size.height();
437     switch (metric) {
438     case PdmWidth:
439         return w;
440
441     case PdmHeight:
442         return h;
443
444     case PdmWidthMM:
445         return qRound(w * 1000 / dpmx);
446
447     case PdmHeightMM:
448         return qRound(h * 1000 / dpmy);
449
450     case PdmNumColors:
451         return 0;
452
453     case PdmDepth:
454         return 32;//d->depth;
455
456     case PdmDpiX:
457         return qRound(dpmx * 0.0254);
458
459     case PdmDpiY:
460         return qRound(dpmy * 0.0254);
461
462     case PdmPhysicalDpiX:
463         return qRound(dpmx * 0.0254);
464
465     case PdmPhysicalDpiY:
466         return qRound(dpmy * 0.0254);
467
468     default:
469         qWarning("QGLPixelBuffer::metric(), Unhandled metric type: %d\n", metric);
470         break;
471     }
472     return 0;
473 }
474
475 /*!
476     Generates and binds a 2D GL texture to the current context, based
477     on \a image. The generated texture id is returned and can be used
478     in later glBindTexture() calls.
479
480     The \a target parameter specifies the texture target.
481
482     Equivalent to calling QGLContext::bindTexture().
483
484     \sa deleteTexture()
485 */
486 GLuint QGLPixelBuffer::bindTexture(const QImage &image, GLenum target)
487 {
488     Q_D(QGLPixelBuffer);
489 #ifndef QT_OPENGL_ES
490     return d->qctx->bindTexture(image, target, GLint(GL_RGBA8));
491 #else
492     return d->qctx->bindTexture(image, target, GL_RGBA);
493 #endif
494 }
495
496 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
497 /*! \internal */
498 GLuint QGLPixelBuffer::bindTexture(const QImage &image, QMacCompatGLenum target)
499 {
500     Q_D(QGLPixelBuffer);
501     return d->qctx->bindTexture(image, target, QMacCompatGLint(GL_RGBA8));
502 }
503 #endif
504
505 /*! \overload
506
507     Generates and binds a 2D GL texture based on \a pixmap.
508
509     Equivalent to calling QGLContext::bindTexture().
510
511     \sa deleteTexture()
512 */
513 GLuint QGLPixelBuffer::bindTexture(const QPixmap &pixmap, GLenum target)
514 {
515     Q_D(QGLPixelBuffer);
516 #ifndef QT_OPENGL_ES
517     return d->qctx->bindTexture(pixmap, target, GLint(GL_RGBA8));
518 #else
519     return d->qctx->bindTexture(pixmap, target, GL_RGBA);
520 #endif
521 }
522
523 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
524 /*! \internal */
525 GLuint QGLPixelBuffer::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target)
526 {
527     Q_D(QGLPixelBuffer);
528     return d->qctx->bindTexture(pixmap, target, QMacCompatGLint(GL_RGBA8));
529 }
530 #endif
531
532 /*! \overload
533
534     Reads the DirectDrawSurface (DDS) compressed file \a fileName and
535     generates a 2D GL texture from it.
536
537     Equivalent to calling QGLContext::bindTexture().
538
539     \sa deleteTexture()
540 */
541 GLuint QGLPixelBuffer::bindTexture(const QString &fileName)
542 {
543     Q_D(QGLPixelBuffer);
544     return d->qctx->bindTexture(fileName);
545 }
546
547 /*!
548     Removes the texture identified by \a texture_id from the texture cache.
549
550     Equivalent to calling QGLContext::deleteTexture().
551  */
552 void QGLPixelBuffer::deleteTexture(GLuint texture_id)
553 {
554     Q_D(QGLPixelBuffer);
555     d->qctx->deleteTexture(texture_id);
556 }
557
558 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
559 /*! \internal */
560 void QGLPixelBuffer::deleteTexture(QMacCompatGLuint texture_id)
561 {
562     Q_D(QGLPixelBuffer);
563     d->qctx->deleteTexture(texture_id);
564 }
565 #endif
566
567 /*!
568     \since 4.4
569
570     Draws the given texture, \a textureId, to the given target rectangle,
571     \a target, in OpenGL model space. The \a textureTarget should be a 2D
572     texture target.
573
574     Equivalent to the corresponding QGLContext::drawTexture().
575 */
576 void QGLPixelBuffer::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
577 {
578     Q_D(QGLPixelBuffer);
579     d->qctx->drawTexture(target, textureId, textureTarget);
580 }
581
582 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
583 /*! \internal */
584 void QGLPixelBuffer::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
585 {
586     Q_D(QGLPixelBuffer);
587     d->qctx->drawTexture(target, textureId, textureTarget);
588 }
589 #endif
590
591 /*!
592     \since 4.4
593
594     Draws the given texture, \a textureId, at the given \a point in OpenGL model
595     space. The textureTarget parameter should be a 2D texture target.
596
597     Equivalent to the corresponding QGLContext::drawTexture().
598 */
599 void QGLPixelBuffer::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
600 {
601     Q_D(QGLPixelBuffer);
602     d->qctx->drawTexture(point, textureId, textureTarget);
603 }
604
605 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
606 /*! \internal */
607 void QGLPixelBuffer::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
608 {
609     Q_D(QGLPixelBuffer);
610     d->qctx->drawTexture(point, textureId, textureTarget);
611 }
612 #endif
613
614 /*!
615     Returns the format of the pbuffer. The format may be different
616     from the one that was requested.
617 */
618 QGLFormat QGLPixelBuffer::format() const
619 {
620     Q_D(const QGLPixelBuffer);
621     return d->format;
622 }
623
624 /*! \fn int QGLPixelBuffer::devType() const
625     \internal
626 */
627
628 QT_END_NAMESPACE