summaryrefslogtreecommitdiffstats
path: root/src/opengl/qglpixelbuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl/qglpixelbuffer.cpp')
-rw-r--r--src/opengl/qglpixelbuffer.cpp582
1 files changed, 582 insertions, 0 deletions
diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp
new file mode 100644
index 0000000000..5f74f26c91
--- /dev/null
+++ b/src/opengl/qglpixelbuffer.cpp
@@ -0,0 +1,582 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QGLPixelBuffer
+ \brief The QGLPixelBuffer class encapsulates an OpenGL pbuffer.
+ \since 4.1
+
+ \ingroup multimedia
+
+ Rendering into a pbuffer is normally done using full hardware
+ acceleration. This can be significantly faster than rendering
+ into a QPixmap.
+
+ There are three approaches to using this class:
+
+ \list 1
+ \o \bold{We can draw into the pbuffer and convert it to a QImage
+ using toImage().} This is normally much faster than calling
+ QGLWidget::renderPixmap().
+
+ \o \bold{We can draw into the pbuffer and copy the contents into
+ an OpenGL texture using updateDynamicTexture().} This allows
+ us to create dynamic textures and works on all systems
+ with pbuffer support.
+
+ \o \bold{On systems that support it, we can bind the pbuffer to
+ an OpenGL texture.} The texture is then updated automatically
+ when the pbuffer contents change, eliminating the need for
+ additional copy operations. This is supported only on Windows
+ and Mac OS X systems that provide the \c render_texture
+ extension.
+ \endlist
+
+ Pbuffers are provided by the OpenGL \c pbuffer extension; call
+ hasOpenGLPbuffer() to find out if the system provides pbuffers.
+
+ \sa {opengl/pbuffers}{Pbuffers Example}
+*/
+
+
+#include <qglpixelbuffer.h>
+#include <private/qglpixelbuffer_p.h>
+#include <qimage.h>
+
+#if !defined(QT_OPENGL_ES_2)
+#include <private/qpaintengine_opengl_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QT_OPENGL_ES_2)
+extern void qgl_cleanup_glyph_cache(QGLContext *);
+#else
+void qgl_cleanup_glyph_cache(QGLContext *) {}
+#endif
+
+extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
+
+void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
+{
+ Q_Q(QGLPixelBuffer);
+ if(init(size, format, shareWidget)) {
+ req_size = size;
+ req_format = format;
+ req_shareWidget = shareWidget;
+ invalid = false;
+ qctx = new QGLContext(format);
+ qctx->d_func()->sharing = (shareWidget != 0);
+ if (shareWidget != 0 && shareWidget->d_func()->glcx)
+ qgl_share_reg()->addShare(qctx, shareWidget->d_func()->glcx);
+
+ qctx->d_func()->paintDevice = q;
+ qctx->d_func()->valid = true;
+#if defined(Q_WS_WIN) && !defined(QT_OPENGL_ES)
+ qctx->d_func()->dc = dc;
+ qctx->d_func()->rc = ctx;
+#elif (defined(Q_WS_X11) && !defined(QT_OPENGL_ES))
+ qctx->d_func()->cx = ctx;
+ qctx->d_func()->pbuf = (void *) pbuf;
+ qctx->d_func()->vi = 0;
+#elif defined(Q_WS_MAC)
+ qctx->d_func()->cx = ctx;
+ qctx->d_func()->vi = 0;
+#elif defined(QT_OPENGL_ES)
+ qctx->d_func()->eglContext = ctx;
+#endif
+ }
+}
+
+/*!
+ Constructs an OpenGL pbuffer of the given \a size. If no \a
+ format is specified, the \l{QGLFormat::defaultFormat()}{default
+ format} is used. If the \a shareWidget parameter points to a
+ valid QGLWidget, the pbuffer will share its context with \a
+ shareWidget.
+
+ If you intend to bind this pbuffer as a dynamic texture, the width
+ and height components of \c size must be powers of two (e.g., 512
+ x 128).
+
+ \sa size(), format()
+*/
+QGLPixelBuffer::QGLPixelBuffer(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
+ : d_ptr(new QGLPixelBufferPrivate(this))
+{
+ Q_D(QGLPixelBuffer);
+ d->common_init(size, format, shareWidget);
+}
+
+
+/*! \overload
+
+ Constructs an OpenGL pbuffer with the \a width and \a height. If
+ no \a format is specified, the
+ \l{QGLFormat::defaultFormat()}{default format} is used. If the \a
+ shareWidget parameter points to a valid QGLWidget, the pbuffer
+ will share its context with \a shareWidget.
+
+ If you intend to bind this pbuffer as a dynamic texture, the width
+ and height components of \c size must be powers of two (e.g., 512
+ x 128).
+
+ \sa size(), format()
+*/
+QGLPixelBuffer::QGLPixelBuffer(int width, int height, const QGLFormat &format, QGLWidget *shareWidget)
+ : d_ptr(new QGLPixelBufferPrivate(this))
+{
+ Q_D(QGLPixelBuffer);
+ d->common_init(QSize(width, height), format, shareWidget);
+}
+
+
+/*! \fn QGLPixelBuffer::~QGLPixelBuffer()
+
+ Destroys the pbuffer and frees any allocated resources.
+*/
+QGLPixelBuffer::~QGLPixelBuffer()
+{
+ Q_D(QGLPixelBuffer);
+
+ // defined in qpaintengine_opengl.cpp
+ QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (current != d->qctx)
+ makeCurrent();
+ qgl_cleanup_glyph_cache(d->qctx);
+ d->cleanup();
+ delete d->qctx;
+ if (current && current != d->qctx)
+ current->makeCurrent();
+ delete d_ptr;
+}
+
+/*! \fn bool QGLPixelBuffer::makeCurrent()
+
+ Makes this pbuffer the current OpenGL rendering context. Returns
+ true on success; otherwise returns false.
+
+ \sa QGLContext::makeCurrent(), doneCurrent()
+*/
+
+bool QGLPixelBuffer::makeCurrent()
+{
+ Q_D(QGLPixelBuffer);
+ if (d->invalid)
+ return false;
+ d->qctx->makeCurrent();
+ return true;
+}
+
+/*! \fn bool QGLPixelBuffer::doneCurrent()
+
+ Makes no context the current OpenGL context. Returns true on
+ success; otherwise returns false.
+*/
+
+bool QGLPixelBuffer::doneCurrent()
+{
+ Q_D(QGLPixelBuffer);
+ if (d->invalid)
+ return false;
+ d->qctx->doneCurrent();
+ return true;
+}
+
+/*!
+ Generates and binds a 2D GL texture that is the same size as the
+ pbuffer, and returns the texture's ID. This can be used in
+ conjunction with bindToDynamicTexture() and
+ updateDynamicTexture().
+
+ \sa size()
+*/
+
+#if (defined(Q_WS_X11) || defined(Q_WS_WIN)) && !defined(QT_OPENGL_ES)
+GLuint QGLPixelBuffer::generateDynamicTexture() const
+{
+ Q_D(const QGLPixelBuffer);
+ GLuint texture;
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, d->req_size.width(), d->req_size.height(), 0, GL_RGBA, GL_FLOAT, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ return texture;
+}
+#endif
+
+/*! \fn bool QGLPixelBuffer::bindToDynamicTexture(GLuint texture_id)
+
+ Binds the texture specified by \a texture_id to this pbuffer.
+ Returns true on success; otherwise returns false.
+
+ The texture must be of the same size and format as the pbuffer.
+
+ To unbind the texture, call releaseFromDynamicTexture(). While
+ the texture is bound, it is updated automatically when the
+ pbuffer contents change, eliminating the need for additional copy
+ operations.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_opengl_qglpixelbuffer.cpp 0
+
+ \warning This function uses the \c {render_texture} extension,
+ which is currently not supported under X11. An alternative that
+ works on all systems (including X11) is to manually copy the
+ pbuffer contents to a texture using updateDynamicTexture().
+
+ \warning For the bindToDynamicTexture() call to succeed on the
+ Mac OS X, the pbuffer needs a shared context, i.e. the
+ QGLPixelBuffer must be created with a share widget.
+
+ \sa generateDynamicTexture(), releaseFromDynamicTexture()
+*/
+
+/*! \fn void QGLPixelBuffer::releaseFromDynamicTexture()
+
+ Releases the pbuffer from any previously bound texture.
+
+ \sa bindToDynamicTexture()
+*/
+
+/*! \fn bool QGLPixelBuffer::hasOpenGLPbuffers()
+
+ Returns true if the OpenGL \c pbuffer extension is present on
+ this system; otherwise returns false.
+*/
+
+/*!
+ Copies the pbuffer contents into the texture specified with \a
+ texture_id.
+
+ The texture must be of the same size and format as the pbuffer.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_opengl_qglpixelbuffer.cpp 1
+
+ An alternative on Windows and Mac OS X systems that support the
+ \c render_texture extension is to use bindToDynamicTexture() to
+ get dynamic updates of the texture.
+
+ \sa generateDynamicTexture(), bindToDynamicTexture()
+*/
+void QGLPixelBuffer::updateDynamicTexture(GLuint texture_id) const
+{
+ Q_D(const QGLPixelBuffer);
+ if (d->invalid)
+ return;
+ glBindTexture(GL_TEXTURE_2D, texture_id);
+#ifndef QT_OPENGL_ES
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, d->req_size.width(), d->req_size.height(), 0);
+#else
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, d->req_size.width(), d->req_size.height(), 0);
+#endif
+}
+
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+void QGLPixelBuffer::updateDynamicTexture(QMacCompatGLuint texture_id) const
+{
+ updateDynamicTexture(GLuint(texture_id));
+}
+#endif
+
+/*!
+ Returns the size of the pbuffer.
+*/
+QSize QGLPixelBuffer::size() const
+{
+ Q_D(const QGLPixelBuffer);
+ return d->req_size;
+}
+
+/*!
+ Returns the contents of the pbuffer as a QImage.
+*/
+QImage QGLPixelBuffer::toImage() const
+{
+ Q_D(const QGLPixelBuffer);
+ if (d->invalid)
+ return QImage();
+
+ const_cast<QGLPixelBuffer *>(this)->makeCurrent();
+ return qt_gl_read_framebuffer(d->req_size, d->format.alpha(), true);
+}
+
+/*!
+ Returns the native pbuffer handle.
+*/
+Qt::HANDLE QGLPixelBuffer::handle() const
+{
+ Q_D(const QGLPixelBuffer);
+ if (d->invalid)
+ return 0;
+ return (Qt::HANDLE) d->pbuf;
+}
+
+/*!
+ Returns true if this pbuffer is valid; otherwise returns false.
+*/
+bool QGLPixelBuffer::isValid() const
+{
+ Q_D(const QGLPixelBuffer);
+ return !d->invalid;
+}
+
+#if !defined(QT_OPENGL_ES_2)
+Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_paintengine)
+#endif
+
+/*! \reimp */
+QPaintEngine *QGLPixelBuffer::paintEngine() const
+{
+#if !defined(QT_OPENGL_ES_2)
+ return qt_buffer_paintengine();
+#else
+ return 0;
+#endif
+}
+
+extern int qt_defaultDpi();
+
+/*! \reimp */
+int QGLPixelBuffer::metric(PaintDeviceMetric metric) const
+{
+ Q_D(const QGLPixelBuffer);
+
+ float dpmx = qt_defaultDpi()*100./2.54;
+ float dpmy = qt_defaultDpi()*100./2.54;
+ int w = d->req_size.width();
+ int h = d->req_size.height();
+ switch (metric) {
+ case PdmWidth:
+ return w;
+
+ case PdmHeight:
+ return h;
+
+ case PdmWidthMM:
+ return qRound(w * 1000 / dpmx);
+
+ case PdmHeightMM:
+ return qRound(h * 1000 / dpmy);
+
+ case PdmNumColors:
+ return 0;
+
+ case PdmDepth:
+ return 32;//d->depth;
+
+ case PdmDpiX:
+ return (int)(dpmx * 0.0254);
+
+ case PdmDpiY:
+ return (int)(dpmy * 0.0254);
+
+ case PdmPhysicalDpiX:
+ return (int)(dpmx * 0.0254);
+
+ case PdmPhysicalDpiY:
+ return (int)(dpmy * 0.0254);
+
+ default:
+ qWarning("QGLPixelBuffer::metric(), Unhandled metric type: %d\n", metric);
+ break;
+ }
+ return 0;
+}
+
+/*!
+ Generates and binds a 2D GL texture to the current context, based
+ on \a image. The generated texture id is returned and can be used
+ in later glBindTexture() calls.
+
+ The \a target parameter specifies the texture target.
+
+ Equivalent to calling QGLContext::bindTexture().
+
+ \sa deleteTexture()
+*/
+GLuint QGLPixelBuffer::bindTexture(const QImage &image, GLenum target)
+{
+ Q_D(QGLPixelBuffer);
+#ifndef QT_OPENGL_ES
+ return d->qctx->bindTexture(image, target, GLint(GL_RGBA8));
+#else
+ return d->qctx->bindTexture(image, target, GL_RGBA);
+#endif
+}
+
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+/*! \internal */
+GLuint QGLPixelBuffer::bindTexture(const QImage &image, QMacCompatGLenum target)
+{
+ Q_D(QGLPixelBuffer);
+ return d->qctx->bindTexture(image, target, QMacCompatGLint(GL_RGBA8));
+}
+#endif
+
+/*! \overload
+
+ Generates and binds a 2D GL texture based on \a pixmap.
+
+ Equivalent to calling QGLContext::bindTexture().
+
+ \sa deleteTexture()
+*/
+GLuint QGLPixelBuffer::bindTexture(const QPixmap &pixmap, GLenum target)
+{
+ Q_D(QGLPixelBuffer);
+#ifndef QT_OPENGL_ES
+ return d->qctx->bindTexture(pixmap, target, GLint(GL_RGBA8));
+#else
+ return d->qctx->bindTexture(pixmap, target, GL_RGBA);
+#endif
+}
+
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+/*! \internal */
+GLuint QGLPixelBuffer::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target)
+{
+ Q_D(QGLPixelBuffer);
+ return d->qctx->bindTexture(pixmap, target, QMacCompatGLint(GL_RGBA8));
+}
+#endif
+
+/*! \overload
+
+ Reads the DirectDrawSurface (DDS) compressed file \a fileName and
+ generates a 2D GL texture from it.
+
+ Equivalent to calling QGLContext::bindTexture().
+
+ \sa deleteTexture()
+*/
+GLuint QGLPixelBuffer::bindTexture(const QString &fileName)
+{
+ Q_D(QGLPixelBuffer);
+ return d->qctx->bindTexture(fileName);
+}
+
+/*!
+ Removes the texture identified by \a texture_id from the texture cache.
+
+ Equivalent to calling QGLContext::deleteTexture().
+ */
+void QGLPixelBuffer::deleteTexture(GLuint texture_id)
+{
+ Q_D(QGLPixelBuffer);
+ d->qctx->deleteTexture(texture_id);
+}
+
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+/*! \internal */
+void QGLPixelBuffer::deleteTexture(QMacCompatGLuint texture_id)
+{
+ Q_D(QGLPixelBuffer);
+ d->qctx->deleteTexture(texture_id);
+}
+#endif
+
+/*!
+ \since 4.4
+
+ Draws the given texture, \a textureId, to the given target rectangle,
+ \a target, in OpenGL model space. The \a textureTarget should be a 2D
+ texture target.
+
+ Equivalent to the corresponding QGLContext::drawTexture().
+*/
+void QGLPixelBuffer::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
+{
+ Q_D(QGLPixelBuffer);
+ d->qctx->drawTexture(target, textureId, textureTarget);
+}
+
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+/*! \internal */
+void QGLPixelBuffer::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
+{
+ Q_D(QGLPixelBuffer);
+ d->qctx->drawTexture(target, textureId, textureTarget);
+}
+#endif
+
+/*!
+ \since 4.4
+
+ Draws the given texture, \a textureId, at the given \a point in OpenGL model
+ space. The textureTarget parameter should be a 2D texture target.
+
+ Equivalent to the corresponding QGLContext::drawTexture().
+*/
+void QGLPixelBuffer::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
+{
+ Q_D(QGLPixelBuffer);
+ d->qctx->drawTexture(point, textureId, textureTarget);
+}
+
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+/*! \internal */
+void QGLPixelBuffer::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
+{
+ Q_D(QGLPixelBuffer);
+ d->qctx->drawTexture(point, textureId, textureTarget);
+}
+#endif
+
+/*!
+ Returns the format of the pbuffer. The format may be different
+ from the one that was requested.
+*/
+QGLFormat QGLPixelBuffer::format() const
+{
+ Q_D(const QGLPixelBuffer);
+ return d->format;
+}
+
+/*! \fn int QGLPixelBuffer::devType() const
+ \reimp
+*/
+
+QT_END_NAMESPACE