1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
44 \brief The QGLPixelBuffer class encapsulates an OpenGL pbuffer.
49 Rendering into a pbuffer is normally done using full hardware
50 acceleration. This can be significantly faster than rendering
53 There are three approaches to using this class:
56 \li \b{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().
60 \li \b{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
65 \li \b{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
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.
86 Pbuffers are provided by the OpenGL \c pbuffer extension; call
87 hasOpenGLPbuffer() to find out if the system provides pbuffers.
89 \sa {opengl/pbuffers}{Pbuffers Example}
92 #include <QtCore/qglobal.h>
94 #include "gl2paintengineex/qpaintengineex_opengl2_p.h"
96 #include <qglpixelbuffer.h>
97 #include <private/qglpixelbuffer_p.h>
98 #include <private/qfont_p.h>
103 extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
106 QGLContext* QGLPBufferGLPaintDevice::context() const
108 return pbuf->d_func()->qctx;
111 void QGLPBufferGLPaintDevice::endPaint() {
113 QGLPaintDevice::endPaint();
116 void QGLPBufferGLPaintDevice::setPBuffer(QGLPixelBuffer* pb)
121 void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
124 if(init(size, format, shareWidget)) {
127 req_shareWidget = shareWidget;
129 qctx = new QGLContext(format);
130 qctx->d_func()->sharing = (shareWidget != 0);
131 if (shareWidget != 0 && shareWidget->d_func()->glcx) {
132 QGLContextGroup::addShare(qctx, shareWidget->d_func()->glcx);
133 shareWidget->d_func()->glcx->d_func()->sharing = true;
136 glDevice.setPBuffer(q);
137 qctx->d_func()->paintDevice = q;
138 qctx->d_func()->valid = true;
143 Constructs an OpenGL pbuffer of the given \a size. If no \a
144 format is specified, the \l{QGLFormat::defaultFormat()}{default
145 format} is used. If the \a shareWidget parameter points to a
146 valid QGLWidget, the pbuffer will share its context with \a
149 If you intend to bind this pbuffer as a dynamic texture, the width
150 and height components of \c size must be powers of two (e.g., 512
155 QGLPixelBuffer::QGLPixelBuffer(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
156 : d_ptr(new QGLPixelBufferPrivate(this))
159 d->common_init(size, format, shareWidget);
165 Constructs an OpenGL pbuffer with the \a width and \a height. If
166 no \a format is specified, the
167 \l{QGLFormat::defaultFormat()}{default format} is used. If the \a
168 shareWidget parameter points to a valid QGLWidget, the pbuffer
169 will share its context with \a shareWidget.
171 If you intend to bind this pbuffer as a dynamic texture, the width
172 and height components of \c size must be powers of two (e.g., 512
177 QGLPixelBuffer::QGLPixelBuffer(int width, int height, const QGLFormat &format, QGLWidget *shareWidget)
178 : d_ptr(new QGLPixelBufferPrivate(this))
181 d->common_init(QSize(width, height), format, shareWidget);
185 /*! \fn QGLPixelBuffer::~QGLPixelBuffer()
187 Destroys the pbuffer and frees any allocated resources.
189 QGLPixelBuffer::~QGLPixelBuffer()
193 // defined in qpaintengine_opengl.cpp
194 QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext());
195 if (current != d->qctx)
199 if (current && current != d->qctx)
200 current->makeCurrent();
203 /*! \fn bool QGLPixelBuffer::makeCurrent()
205 Makes this pbuffer the current OpenGL rendering context. Returns
206 true on success; otherwise returns false.
208 \sa QGLContext::makeCurrent(), doneCurrent()
211 bool QGLPixelBuffer::makeCurrent()
216 d->qctx->makeCurrent();
220 /*! \fn bool QGLPixelBuffer::doneCurrent()
222 Makes no context the current OpenGL context. Returns true on
223 success; otherwise returns false.
226 bool QGLPixelBuffer::doneCurrent()
231 d->qctx->doneCurrent();
236 \fn GLuint QGLPixelBuffer::generateDynamicTexture() const
238 Generates and binds a 2D GL texture that is the same size as the
239 pbuffer, and returns the texture's ID. This can be used in
240 conjunction with bindToDynamicTexture() and
241 updateDynamicTexture().
246 /*! \fn bool QGLPixelBuffer::bindToDynamicTexture(GLuint texture_id)
248 Binds the texture specified by \a texture_id to this pbuffer.
249 Returns true on success; otherwise returns false.
251 The texture must be of the same size and format as the pbuffer.
253 To unbind the texture, call releaseFromDynamicTexture(). While
254 the texture is bound, it is updated automatically when the
255 pbuffer contents change, eliminating the need for additional copy
260 \snippet code/src_opengl_qglpixelbuffer.cpp 0
262 \warning This function uses the \c {render_texture} extension,
263 which is currently not supported under X11. An alternative that
264 works on all systems (including X11) is to manually copy the
265 pbuffer contents to a texture using updateDynamicTexture().
267 \warning For the bindToDynamicTexture() call to succeed on the
268 Mac OS X, the pbuffer needs a shared context, i.e. the
269 QGLPixelBuffer must be created with a share widget.
271 \sa generateDynamicTexture(), releaseFromDynamicTexture()
274 /*! \fn void QGLPixelBuffer::releaseFromDynamicTexture()
276 Releases the pbuffer from any previously bound texture.
278 \sa bindToDynamicTexture()
281 /*! \fn bool QGLPixelBuffer::hasOpenGLPbuffers()
283 Returns true if the OpenGL \c pbuffer extension is present on
284 this system; otherwise returns false.
288 Copies the pbuffer contents into the texture specified with \a
291 The texture must be of the same size and format as the pbuffer.
295 \snippet code/src_opengl_qglpixelbuffer.cpp 1
297 An alternative on Windows and Mac OS X systems that support the
298 \c render_texture extension is to use bindToDynamicTexture() to
299 get dynamic updates of the texture.
301 \sa generateDynamicTexture(), bindToDynamicTexture()
303 void QGLPixelBuffer::updateDynamicTexture(GLuint texture_id) const
305 Q_D(const QGLPixelBuffer);
308 glBindTexture(GL_TEXTURE_2D, texture_id);
310 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, d->req_size.width(), d->req_size.height(), 0);
312 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, d->req_size.width(), d->req_size.height(), 0);
317 Returns the size of the pbuffer.
319 QSize QGLPixelBuffer::size() const
321 Q_D(const QGLPixelBuffer);
326 Returns the contents of the pbuffer as a QImage.
328 QImage QGLPixelBuffer::toImage() const
330 Q_D(const QGLPixelBuffer);
334 const_cast<QGLPixelBuffer *>(this)->makeCurrent();
335 return qt_gl_read_framebuffer(d->req_size, d->format.alpha(), true);
339 Returns the native pbuffer handle.
341 Qt::HANDLE QGLPixelBuffer::handle() const
343 Q_D(const QGLPixelBuffer);
346 return (Qt::HANDLE) d->pbuf;
350 Returns true if this pbuffer is valid; otherwise returns false.
352 bool QGLPixelBuffer::isValid() const
354 Q_D(const QGLPixelBuffer);
358 Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>, qt_buffer_2_engine)
361 QPaintEngine *QGLPixelBuffer::paintEngine() const
363 return qt_buffer_2_engine()->engine();
367 int QGLPixelBuffer::metric(PaintDeviceMetric metric) const
369 Q_D(const QGLPixelBuffer);
371 float dpmx = qt_defaultDpiX()*100./2.54;
372 float dpmy = qt_defaultDpiY()*100./2.54;
373 int w = d->req_size.width();
374 int h = d->req_size.height();
383 return qRound(w * 1000 / dpmx);
386 return qRound(h * 1000 / dpmy);
392 return 32;//d->depth;
395 return qRound(dpmx * 0.0254);
398 return qRound(dpmy * 0.0254);
400 case PdmPhysicalDpiX:
401 return qRound(dpmx * 0.0254);
403 case PdmPhysicalDpiY:
404 return qRound(dpmy * 0.0254);
407 qWarning("QGLPixelBuffer::metric(), Unhandled metric type: %d\n", metric);
414 Generates and binds a 2D GL texture to the current context, based
415 on \a image. The generated texture id is returned and can be used
416 in later glBindTexture() calls.
418 The \a target parameter specifies the texture target.
420 Equivalent to calling QGLContext::bindTexture().
424 GLuint QGLPixelBuffer::bindTexture(const QImage &image, GLenum target)
428 return d->qctx->bindTexture(image, target, GLint(GL_RGBA8));
430 return d->qctx->bindTexture(image, target, GL_RGBA);
436 Generates and binds a 2D GL texture based on \a pixmap.
438 Equivalent to calling QGLContext::bindTexture().
442 GLuint QGLPixelBuffer::bindTexture(const QPixmap &pixmap, GLenum target)
446 return d->qctx->bindTexture(pixmap, target, GLint(GL_RGBA8));
448 return d->qctx->bindTexture(pixmap, target, GL_RGBA);
454 Reads the DirectDrawSurface (DDS) compressed file \a fileName and
455 generates a 2D GL texture from it.
457 Equivalent to calling QGLContext::bindTexture().
461 GLuint QGLPixelBuffer::bindTexture(const QString &fileName)
464 return d->qctx->bindTexture(fileName);
468 Removes the texture identified by \a texture_id from the texture cache.
470 Equivalent to calling QGLContext::deleteTexture().
472 void QGLPixelBuffer::deleteTexture(GLuint texture_id)
475 d->qctx->deleteTexture(texture_id);
481 Draws the given texture, \a textureId, to the given target rectangle,
482 \a target, in OpenGL model space. The \a textureTarget should be a 2D
485 Equivalent to the corresponding QGLContext::drawTexture().
487 void QGLPixelBuffer::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
490 d->qctx->drawTexture(target, textureId, textureTarget);
496 Draws the given texture, \a textureId, at the given \a point in OpenGL model
497 space. The textureTarget parameter should be a 2D texture target.
499 Equivalent to the corresponding QGLContext::drawTexture().
501 void QGLPixelBuffer::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
504 d->qctx->drawTexture(point, textureId, textureTarget);
508 Returns the format of the pbuffer. The format may be different
509 from the one that was requested.
511 QGLFormat QGLPixelBuffer::format() const
513 Q_D(const QGLPixelBuffer);
517 /*! \fn int QGLPixelBuffer::devType() const