/****************************************************************************+ −
**+ −
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).+ −
** All rights reserved.+ −
** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying+ −
** this package.+ −
**+ −
** 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.1, included in the file LGPL_EXCEPTION.txt in this package.+ −
**+ −
** If you have questions regarding the use of this file, please contact+ −
** Nokia at qt-info@nokia.com.+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
** $QT_END_LICENSE$+ −
**+ −
****************************************************************************/+ −
+ −
/*!+ −
\class QGLPixelBuffer+ −
\brief The QGLPixelBuffer class encapsulates an OpenGL pbuffer.+ −
\since 4.1+ −
+ −
\ingroup painting-3D+ −
+ −
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 <QtCore/qglobal.h>+ −
+ −
#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)+ −
#include <private/qpaintengineex_opengl2_p.h>+ −
#endif+ −
+ −
#include <qglpixelbuffer.h>+ −
#include <private/qglpixelbuffer_p.h>+ −
#include <qimage.h>+ −
+ −
#ifndef 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);+ −
+ −
+ −
QGLContext* QGLPBufferGLPaintDevice::context() const+ −
{+ −
return pbuf->d_func()->qctx;+ −
}+ −
+ −
void QGLPBufferGLPaintDevice::endPaint() {+ −
glFlush();+ −
QGLPaintDevice::endPaint();+ −
}+ −
+ −
void QGLPBufferGLPaintDevice::setPBuffer(QGLPixelBuffer* pb)+ −
{+ −
pbuf = pb;+ −
}+ −
+ −
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);+ −
shareWidget->d_func()->glcx->d_func()->sharing = true;+ −
}+ −
+ −
glDevice.setPBuffer(q);+ −
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;+ −
qctx->d_func()->eglSurface = pbuf;+ −
#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();+ −
}+ −
+ −
/*! \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_1) && !defined(QT_OPENGL_ES_1_CL)+ −
Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine)+ −
#endif+ −
+ −
#ifndef QT_OPENGL_ES_2+ −
Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine)+ −
#endif+ −
+ −
/*! \reimp */+ −
QPaintEngine *QGLPixelBuffer::paintEngine() const+ −
{+ −
#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL)+ −
return qt_buffer_engine();+ −
#elif defined(QT_OPENGL_ES_2)+ −
return qt_buffer_2_engine();+ −
#else+ −
if (qt_gl_preferGL2Engine())+ −
return qt_buffer_2_engine();+ −
else+ −
return qt_buffer_engine();+ −
#endif+ −
}+ −
+ −
extern int qt_defaultDpiX();+ −
extern int qt_defaultDpiY();+ −
+ −
/*! \reimp */+ −
int QGLPixelBuffer::metric(PaintDeviceMetric metric) const+ −
{+ −
Q_D(const QGLPixelBuffer);+ −
+ −
float dpmx = qt_defaultDpiX()*100./2.54;+ −
float dpmy = qt_defaultDpiY()*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 qRound(dpmx * 0.0254);+ −
+ −
case PdmDpiY:+ −
return qRound(dpmy * 0.0254);+ −
+ −
case PdmPhysicalDpiX:+ −
return qRound(dpmx * 0.0254);+ −
+ −
case PdmPhysicalDpiY:+ −
return qRound(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+ −
\internal+ −
*/+ −
+ −
QT_END_NAMESPACE+ −