src/opengl/qglframebufferobject.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 #include "qglframebufferobject.h"
       
    43 #include "qglframebufferobject_p.h"
       
    44 
       
    45 #include <qdebug.h>
       
    46 #include <private/qgl_p.h>
       
    47 #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
       
    48 #include <private/qpaintengineex_opengl2_p.h>
       
    49 #endif
       
    50 
       
    51 #ifndef QT_OPENGL_ES_2
       
    52 #include <private/qpaintengine_opengl_p.h>
       
    53 #endif
       
    54 
       
    55 #include <qglframebufferobject.h>
       
    56 #include <qlibrary.h>
       
    57 #include <qimage.h>
       
    58 
       
    59 #ifdef QT_OPENGL_ES_1_CL
       
    60 #include "qgl_cl_p.h"
       
    61 #endif
       
    62 
       
    63 QT_BEGIN_NAMESPACE
       
    64 
       
    65 extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
       
    66 
       
    67 #define QGL_FUNC_CONTEXT const QGLContext *ctx = d_ptr->fbo_guard.context();
       
    68 #define QGL_FUNCP_CONTEXT const QGLContext *ctx = fbo_guard.context();
       
    69 
       
    70 #ifndef QT_NO_DEBUG
       
    71 #define QT_RESET_GLERROR()                                \
       
    72 {                                                         \
       
    73     while (glGetError() != GL_NO_ERROR) {}                \
       
    74 }
       
    75 #define QT_CHECK_GLERROR()                                \
       
    76 {                                                         \
       
    77     GLenum err = glGetError();                            \
       
    78     if (err != GL_NO_ERROR) {                             \
       
    79         qDebug("[%s line %d] GL Error: %d",               \
       
    80                __FILE__, __LINE__, (int)err);             \
       
    81     }                                                     \
       
    82 }
       
    83 #else
       
    84 #define QT_RESET_GLERROR() {}
       
    85 #define QT_CHECK_GLERROR() {}
       
    86 #endif
       
    87 
       
    88 /*!
       
    89     \class QGLFramebufferObjectFormat
       
    90     \brief The QGLFramebufferObjectFormat class specifies the format of an OpenGL
       
    91     framebuffer object.
       
    92 
       
    93     \since 4.6
       
    94 
       
    95     \ingroup painting-3D
       
    96 
       
    97     A framebuffer object has several characteristics:
       
    98     \list
       
    99     \i \link setSamples() Number of samples per pixels.\endlink
       
   100     \i \link setAttachment() Depth and/or stencil attachments.\endlink
       
   101     \i \link setTextureTarget() Texture target.\endlink
       
   102     \i \link setInternalTextureFormat() Internal texture format.\endlink
       
   103     \endlist
       
   104 
       
   105     Note that the desired attachments or number of samples per pixels might not
       
   106     be supported by the hardware driver. Call QGLFramebufferObject::format()
       
   107     after creating a QGLFramebufferObject to find the exact format that was
       
   108     used to create the frame buffer object.
       
   109 
       
   110     \sa QGLFramebufferObject
       
   111 */
       
   112 
       
   113 /*!
       
   114     \internal
       
   115 */
       
   116 void QGLFramebufferObjectFormat::detach()
       
   117 {
       
   118     if (d->ref != 1) {
       
   119         QGLFramebufferObjectFormatPrivate *newd
       
   120             = new QGLFramebufferObjectFormatPrivate(d);
       
   121         if (!d->ref.deref())
       
   122             delete d;
       
   123         d = newd;
       
   124     }
       
   125 }
       
   126 
       
   127 /*!
       
   128     Creates a QGLFramebufferObjectFormat object for specifying
       
   129     the format of an OpenGL framebuffer object.
       
   130 
       
   131     By default the format specifies a non-multisample framebuffer object with no
       
   132     attachments, texture target \c GL_TEXTURE_2D, and internal format \c GL_RGBA8.
       
   133     On OpenGL/ES systems, the default internal format is \c GL_RGBA.
       
   134 
       
   135     \sa samples(), attachment(), target(), internalTextureFormat()
       
   136 */
       
   137 
       
   138 QGLFramebufferObjectFormat::QGLFramebufferObjectFormat()
       
   139 {
       
   140     d = new QGLFramebufferObjectFormatPrivate;
       
   141 }
       
   142 
       
   143 /*!
       
   144     Constructs a copy of \a other.
       
   145 */
       
   146 
       
   147 QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other)
       
   148 {
       
   149     d = other.d;
       
   150     d->ref.ref();
       
   151 }
       
   152 
       
   153 /*!
       
   154     Assigns \a other to this object.
       
   155 */
       
   156 
       
   157 QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFramebufferObjectFormat &other)
       
   158 {
       
   159     if (d != other.d) {
       
   160         other.d->ref.ref();
       
   161         if (!d->ref.deref())
       
   162             delete d;
       
   163         d = other.d;
       
   164     }
       
   165     return *this;
       
   166 }
       
   167 
       
   168 /*!
       
   169     Destroys the QGLFramebufferObjectFormat.
       
   170 */
       
   171 QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat()
       
   172 {
       
   173     if (!d->ref.deref())
       
   174         delete d;
       
   175 }
       
   176 
       
   177 /*!
       
   178     Sets the number of samples per pixel for a multisample framebuffer object
       
   179     to \a samples.  The default sample count of 0 represents a regular
       
   180     non-multisample framebuffer object.
       
   181 
       
   182     If the desired amount of samples per pixel is not supported by the hardware
       
   183     then the maximum number of samples per pixel will be used. Note that
       
   184     multisample framebuffer objects can not be bound as textures. Also, the
       
   185     \c{GL_EXT_framebuffer_multisample} extension is required to create a
       
   186     framebuffer with more than one sample per pixel.
       
   187 
       
   188     \sa samples()
       
   189 */
       
   190 void QGLFramebufferObjectFormat::setSamples(int samples)
       
   191 {
       
   192     detach();
       
   193     d->samples = samples;
       
   194 }
       
   195 
       
   196 /*!
       
   197     Returns the number of samples per pixel if a framebuffer object
       
   198     is a multisample framebuffer object. Otherwise, returns 0.
       
   199     The default value is 0.
       
   200 
       
   201     \sa setSamples()
       
   202 */
       
   203 int QGLFramebufferObjectFormat::samples() const
       
   204 {
       
   205     return d->samples;
       
   206 }
       
   207 
       
   208 /*!
       
   209     Sets the attachment configuration of a framebuffer object to \a attachment.
       
   210 
       
   211     \sa attachment()
       
   212 */
       
   213 void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment attachment)
       
   214 {
       
   215     detach();
       
   216     d->attachment = attachment;
       
   217 }
       
   218 
       
   219 /*!
       
   220     Returns the configuration of the depth and stencil buffers attached to
       
   221     a framebuffer object.  The default is QGLFramebufferObject::NoAttachment.
       
   222 
       
   223     \sa setAttachment()
       
   224 */
       
   225 QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const
       
   226 {
       
   227     return d->attachment;
       
   228 }
       
   229 
       
   230 /*!
       
   231     Sets the texture target of the texture attached to a framebuffer object to
       
   232     \a target. Ignored for multisample framebuffer objects.
       
   233 
       
   234     \sa textureTarget(), samples()
       
   235 */
       
   236 void QGLFramebufferObjectFormat::setTextureTarget(GLenum target)
       
   237 {
       
   238     detach();
       
   239     d->target = target;
       
   240 }
       
   241 
       
   242 /*!
       
   243     Returns the texture target of the texture attached to a framebuffer object.
       
   244     Ignored for multisample framebuffer objects.  The default is
       
   245     \c GL_TEXTURE_2D.
       
   246 
       
   247     \sa setTextureTarget(), samples()
       
   248 */
       
   249 GLenum QGLFramebufferObjectFormat::textureTarget() const
       
   250 {
       
   251     return d->target;
       
   252 }
       
   253 
       
   254 /*!
       
   255     Sets the internal format of a framebuffer object's texture or
       
   256     multisample framebuffer object's color buffer to
       
   257     \a internalTextureFormat.
       
   258 
       
   259     \sa internalTextureFormat()
       
   260 */
       
   261 void QGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat)
       
   262 {
       
   263     detach();
       
   264     d->internal_format = internalTextureFormat;
       
   265 }
       
   266 
       
   267 /*!
       
   268     Returns the internal format of a framebuffer object's texture or
       
   269     multisample framebuffer object's color buffer.  The default is
       
   270     \c GL_RGBA8 on desktop OpenGL systems, and \c GL_RGBA on
       
   271     OpenGL/ES systems.
       
   272 
       
   273     \sa setInternalTextureFormat()
       
   274 */
       
   275 GLenum QGLFramebufferObjectFormat::internalTextureFormat() const
       
   276 {
       
   277     return d->internal_format;
       
   278 }
       
   279 
       
   280 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
   281 /*! \internal */
       
   282 void QGLFramebufferObjectFormat::setTextureTarget(QMacCompatGLenum target)
       
   283 {
       
   284     detach();
       
   285     d->target = target;
       
   286 }
       
   287 
       
   288 /*! \internal */
       
   289 void QGLFramebufferObjectFormat::setInternalTextureFormat(QMacCompatGLenum internalTextureFormat)
       
   290 {
       
   291     detach();
       
   292     d->internal_format = internalTextureFormat;
       
   293 }
       
   294 #endif
       
   295 
       
   296 /*!
       
   297     Returns true if all the options of this framebuffer object format
       
   298     are the same as \a other; otherwise returns false.
       
   299 */
       
   300 bool QGLFramebufferObjectFormat::operator==(const QGLFramebufferObjectFormat& other) const
       
   301 {
       
   302     if (d == other.d)
       
   303         return true;
       
   304     else
       
   305         return d->equals(other.d);
       
   306 }
       
   307 
       
   308 /*!
       
   309     Returns false if all the options of this framebuffer object format
       
   310     are the same as \a other; otherwise returns true.
       
   311 */
       
   312 bool QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& other) const
       
   313 {
       
   314     return !(*this == other);
       
   315 }
       
   316 
       
   317 void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f,
       
   318                                  QGLFramebufferObject::Attachment attachment)
       
   319 {
       
   320     fbo = f;
       
   321     m_thisFBO = fbo->d_func()->fbo(); // This shouldn't be needed
       
   322 
       
   323     // The context that the fbo was created in may not have depth
       
   324     // and stencil buffers, but the fbo itself might.
       
   325     fboFormat = QGLContext::currentContext()->format();
       
   326     if (attachment == QGLFramebufferObject::CombinedDepthStencil) {
       
   327         fboFormat.setDepth(true);
       
   328         fboFormat.setStencil(true);
       
   329     } else if (attachment == QGLFramebufferObject::Depth) {
       
   330         fboFormat.setDepth(true);
       
   331     }
       
   332 }
       
   333 
       
   334 QGLContext *QGLFBOGLPaintDevice::context() const
       
   335 {
       
   336     QGLContext *fboContext = const_cast<QGLContext *>(fbo->d_ptr->fbo_guard.context());
       
   337     QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
       
   338 
       
   339     if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext))
       
   340         return currentContext;
       
   341     else
       
   342         return fboContext;
       
   343 }
       
   344 
       
   345 void QGLFBOGLPaintDevice::ensureActiveTarget()
       
   346 {
       
   347     if (QGLContext::currentContext() != context())
       
   348         context()->makeCurrent();
       
   349 
       
   350     QGLContext* ctx = const_cast<QGLContext*>(QGLContext::currentContext());
       
   351     Q_ASSERT(ctx);
       
   352     const GLuint fboId = fbo->d_func()->fbo();
       
   353     if (ctx->d_func()->current_fbo != fboId) {
       
   354         ctx->d_func()->current_fbo = fboId;
       
   355         glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
       
   356     }
       
   357 }
       
   358 
       
   359 void QGLFBOGLPaintDevice::beginPaint()
       
   360 {
       
   361     if (QGLContext::currentContext() != context())
       
   362         context()->makeCurrent();
       
   363 
       
   364     // We let QFBO track the previously bound FBO rather than doing it
       
   365     // ourselves here. This has the advantage that begin/release & bind/end
       
   366     // work as expected.
       
   367     wasBound = fbo->isBound();
       
   368     if (!wasBound)
       
   369         fbo->bind();
       
   370 }
       
   371 
       
   372 void QGLFBOGLPaintDevice::endPaint()
       
   373 {
       
   374     if (!wasBound)
       
   375         fbo->release();
       
   376 }
       
   377 
       
   378 bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
       
   379 {
       
   380     QGL_FUNCP_CONTEXT;
       
   381     if (!ctx)
       
   382         return false;   // Context no longer exists.
       
   383     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
       
   384     switch(status) {
       
   385     case GL_NO_ERROR:
       
   386     case GL_FRAMEBUFFER_COMPLETE_EXT:
       
   387         return true;
       
   388         break;
       
   389     case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
       
   390         qDebug("QGLFramebufferObject: Unsupported framebuffer format.");
       
   391         break;
       
   392     case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
       
   393         qDebug("QGLFramebufferObject: Framebuffer incomplete attachment.");
       
   394         break;
       
   395     case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
       
   396         qDebug("QGLFramebufferObject: Framebuffer incomplete, missing attachment.");
       
   397         break;
       
   398 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
       
   399     case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
       
   400         qDebug("QGLFramebufferObject: Framebuffer incomplete, duplicate attachment.");
       
   401         break;
       
   402 #endif
       
   403     case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
       
   404         qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions.");
       
   405         break;
       
   406     case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
       
   407         qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same format.");
       
   408         break;
       
   409     case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
       
   410         qDebug("QGLFramebufferObject: Framebuffer incomplete, missing draw buffer.");
       
   411         break;
       
   412     case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
       
   413         qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer.");
       
   414         break;
       
   415     case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
       
   416         qDebug("QGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel.");
       
   417         break;
       
   418     default:
       
   419         qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status;
       
   420         break;
       
   421     }
       
   422     return false;
       
   423 }
       
   424 
       
   425 void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
       
   426                                        QGLFramebufferObject::Attachment attachment,
       
   427                                        GLenum texture_target, GLenum internal_format, GLint samples)
       
   428 {
       
   429     QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
       
   430     fbo_guard.setContext(ctx);
       
   431 
       
   432     bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
       
   433     if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
       
   434         return;
       
   435 
       
   436     size = sz;
       
   437     target = texture_target;
       
   438     // texture dimensions
       
   439 
       
   440     QT_RESET_GLERROR(); // reset error state
       
   441     GLuint fbo = 0;
       
   442     glGenFramebuffers(1, &fbo);
       
   443     glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
       
   444     fbo_guard.setId(fbo);
       
   445 
       
   446     glDevice.setFBO(q, attachment);
       
   447 
       
   448     QT_CHECK_GLERROR();
       
   449     // init texture
       
   450     if (samples == 0) {
       
   451         glGenTextures(1, &texture);
       
   452         glBindTexture(target, texture);
       
   453         glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
       
   454                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
       
   455 #ifndef QT_OPENGL_ES
       
   456         glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
       
   457         glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
       
   458         glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
       
   459         glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
       
   460 #else
       
   461         glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
       
   462         glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
       
   463         glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
       
   464         glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
       
   465 #endif
       
   466         glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
       
   467                 target, texture, 0);
       
   468 
       
   469         QT_CHECK_GLERROR();
       
   470         valid = checkFramebufferStatus();
       
   471         glBindTexture(target, 0);
       
   472 
       
   473         color_buffer = 0;
       
   474     } else {
       
   475         GLint maxSamples;
       
   476         glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
       
   477 
       
   478         samples = qBound(1, int(samples), int(maxSamples));
       
   479 
       
   480         glGenRenderbuffers(1, &color_buffer);
       
   481         glBindRenderbuffer(GL_RENDERBUFFER_EXT, color_buffer);
       
   482         if (glRenderbufferStorageMultisampleEXT) {
       
   483             glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
       
   484                 internal_format, size.width(), size.height());
       
   485         } else {
       
   486             samples = 0;
       
   487             glRenderbufferStorage(GL_RENDERBUFFER_EXT, internal_format,
       
   488                 size.width(), size.height());
       
   489         }
       
   490 
       
   491         glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
       
   492                                      GL_RENDERBUFFER_EXT, color_buffer);
       
   493 
       
   494         QT_CHECK_GLERROR();
       
   495         valid = checkFramebufferStatus();
       
   496 
       
   497         if (valid)
       
   498             glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &samples);
       
   499     }
       
   500 
       
   501     if (attachment == QGLFramebufferObject::CombinedDepthStencil
       
   502         && (QGLExtensions::glExtensions & QGLExtensions::PackedDepthStencil)) {
       
   503         // depth and stencil buffer needs another extension
       
   504         glGenRenderbuffers(1, &depth_stencil_buffer);
       
   505         Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
       
   506         glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
       
   507         Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
       
   508         if (samples != 0 && glRenderbufferStorageMultisampleEXT)
       
   509             glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
       
   510                 GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
       
   511         else
       
   512             glRenderbufferStorage(GL_RENDERBUFFER_EXT,
       
   513                 GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
       
   514 
       
   515         GLint i = 0;
       
   516         glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
       
   517         glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
       
   518                                      GL_RENDERBUFFER_EXT, depth_stencil_buffer);
       
   519         glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
       
   520                                      GL_RENDERBUFFER_EXT, depth_stencil_buffer);
       
   521         fbo_attachment = QGLFramebufferObject::CombinedDepthStencil;
       
   522 
       
   523         valid = checkFramebufferStatus();
       
   524         if (!valid)
       
   525             glDeleteRenderbuffers(1, &depth_stencil_buffer);
       
   526     } else if (attachment == QGLFramebufferObject::Depth
       
   527                || attachment == QGLFramebufferObject::CombinedDepthStencil)
       
   528     {
       
   529         glGenRenderbuffers(1, &depth_stencil_buffer);
       
   530         Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
       
   531         glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
       
   532         Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
       
   533         if (samples != 0 && glRenderbufferStorageMultisampleEXT) {
       
   534 #ifdef QT_OPENGL_ES
       
   535 #define GL_DEPTH_COMPONENT16 0x81A5
       
   536             glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
       
   537                 GL_DEPTH_COMPONENT16, size.width(), size.height());
       
   538 #else
       
   539             glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
       
   540                 GL_DEPTH_COMPONENT, size.width(), size.height());
       
   541 #endif
       
   542         } else {
       
   543 #ifdef QT_OPENGL_ES
       
   544 #define GL_DEPTH_COMPONENT16 0x81A5
       
   545             glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height());
       
   546 #else
       
   547             glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height());
       
   548 #endif
       
   549         }
       
   550         GLint i = 0;
       
   551         glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
       
   552         glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
       
   553                                      GL_RENDERBUFFER_EXT, depth_stencil_buffer);
       
   554         fbo_attachment = QGLFramebufferObject::Depth;
       
   555         valid = checkFramebufferStatus();
       
   556         if (!valid)
       
   557             glDeleteRenderbuffers(1, &depth_stencil_buffer);
       
   558     } else {
       
   559         fbo_attachment = QGLFramebufferObject::NoAttachment;
       
   560     }
       
   561 
       
   562     glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
       
   563     if (!valid) {
       
   564         if (color_buffer)
       
   565             glDeleteRenderbuffers(1, &color_buffer);
       
   566         else
       
   567             glDeleteTextures(1, &texture);
       
   568         glDeleteFramebuffers(1, &fbo);
       
   569         fbo_guard.setId(0);
       
   570     }
       
   571     QT_CHECK_GLERROR();
       
   572 
       
   573     format.setTextureTarget(target);
       
   574     format.setSamples(int(samples));
       
   575     format.setAttachment(fbo_attachment);
       
   576     format.setInternalTextureFormat(internal_format);
       
   577 }
       
   578 
       
   579 /*!
       
   580     \class QGLFramebufferObject
       
   581     \brief The QGLFramebufferObject class encapsulates an OpenGL framebuffer object.
       
   582     \since 4.2
       
   583 
       
   584     \ingroup painting-3D
       
   585 
       
   586     The QGLFramebufferObject class encapsulates an OpenGL framebuffer
       
   587     object, defined by the \c{GL_EXT_framebuffer_object} extension. In
       
   588     addition it provides a rendering surface that can be painted on
       
   589     with a QPainter, rendered to using native GL calls, or both. This
       
   590     surface can be bound and used as a regular texture in your own GL
       
   591     drawing code.  By default, the QGLFramebufferObject class
       
   592     generates a 2D GL texture (using the \c{GL_TEXTURE_2D} target),
       
   593     which is used as the internal rendering target.
       
   594 
       
   595     \bold{It is important to have a current GL context when creating a
       
   596     QGLFramebufferObject, otherwise initialization will fail.}
       
   597 
       
   598     OpenGL framebuffer objects and pbuffers (see
       
   599     \l{QGLPixelBuffer}{QGLPixelBuffer}) can both be used to render to
       
   600     offscreen surfaces, but there are a number of advantages with
       
   601     using framebuffer objects instead of pbuffers:
       
   602 
       
   603     \list 1
       
   604     \o A framebuffer object does not require a separate rendering
       
   605     context, so no context switching will occur when switching
       
   606     rendering targets. There is an overhead involved in switching
       
   607     targets, but in general it is cheaper than a context switch to a
       
   608     pbuffer.
       
   609 
       
   610     \o Rendering to dynamic textures (i.e. render-to-texture
       
   611     functionality) works on all platforms. No need to do explicit copy
       
   612     calls from a render buffer into a texture, as was necessary on
       
   613     systems that did not support the \c{render_texture} extension.
       
   614 
       
   615     \o It is possible to attach several rendering buffers (or texture
       
   616     objects) to the same framebuffer object, and render to all of them
       
   617     without doing a context switch.
       
   618 
       
   619     \o The OpenGL framebuffer extension is a pure GL extension with no
       
   620     system dependant WGL, CGL, or GLX parts. This makes using
       
   621     framebuffer objects more portable.
       
   622     \endlist
       
   623 
       
   624     When using a QPainter to paint to a QGLFramebufferObject you should take
       
   625     care that the QGLFramebufferObject is created with the CombinedDepthStencil
       
   626     attachment for QPainter to be able to render correctly.
       
   627     Note that you need to create a QGLFramebufferObject with more than one
       
   628     sample per pixel for primitives to be antialiased when drawing using a
       
   629     QPainter. To create a multisample framebuffer object you should use one of
       
   630     the constructors that take a QGLFramebufferObject parameter, and set the
       
   631     QGLFramebufferObject::samples() property to a non-zero value.
       
   632 
       
   633     For multisample framebuffer objects a color render buffer is created,
       
   634     otherwise a texture with the specified texture target is created.
       
   635     The color render buffer or texture will have the specified internal
       
   636     format, and will be bound to the \c GL_COLOR_ATTACHMENT0
       
   637     attachment in the framebuffer object.
       
   638 
       
   639     If you want to use a framebuffer object with multisampling enabled
       
   640     as a texture, you first need to copy from it to a regular framebuffer
       
   641     object using QGLContext::blitFramebuffer().
       
   642 
       
   643     \sa {Framebuffer Object Example}
       
   644 */
       
   645 
       
   646 
       
   647 /*!
       
   648     \enum QGLFramebufferObject::Attachment
       
   649     \since 4.3
       
   650 
       
   651     This enum type is used to configure the depth and stencil buffers
       
   652     attached to the framebuffer object when it is created.
       
   653 
       
   654     \value NoAttachment         No attachment is added to the framebuffer object. Note that the
       
   655                                 OpenGL depth and stencil tests won't work when rendering to a
       
   656                                 framebuffer object without any depth or stencil buffers.
       
   657                                 This is the default value.
       
   658 
       
   659     \value CombinedDepthStencil If the \c GL_EXT_packed_depth_stencil extension is present,
       
   660                                 a combined depth and stencil buffer is attached.
       
   661                                 If the extension is not present, only a depth buffer is attached.
       
   662 
       
   663     \value Depth                A depth buffer is attached to the framebuffer object.
       
   664 
       
   665     \sa attachment()
       
   666 */
       
   667 
       
   668 
       
   669 /*! \fn QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
       
   670 
       
   671     Constructs an OpenGL framebuffer object and binds a 2D GL texture
       
   672     to the buffer of the size \a size. The texture is bound to the
       
   673     \c GL_COLOR_ATTACHMENT0 target in the framebuffer object.
       
   674 
       
   675     The \a target parameter is used to specify the GL texture
       
   676     target. The default target is \c GL_TEXTURE_2D. Keep in mind that
       
   677     \c GL_TEXTURE_2D textures must have a power of 2 width and height
       
   678     (e.g. 256x512), unless you are using OpenGL 2.0 or higher.
       
   679 
       
   680     By default, no depth and stencil buffers are attached. This behavior
       
   681     can be toggled using one of the overloaded constructors.
       
   682 
       
   683     The default internal texture format is \c GL_RGBA8 for desktop
       
   684     OpenGL, and \c GL_RGBA for OpenGL/ES.
       
   685 
       
   686     It is important that you have a current GL context set when
       
   687     creating the QGLFramebufferObject, otherwise the initialization
       
   688     will fail.
       
   689 
       
   690     \sa size(), texture(), attachment()
       
   691 */
       
   692 
       
   693 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
       
   694     : d_ptr(new QGLFramebufferObjectPrivate)
       
   695 {
       
   696     Q_D(QGLFramebufferObject);
       
   697     d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
       
   698 }
       
   699 
       
   700 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
   701 /*! \internal */
       
   702 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, QMacCompatGLenum target)
       
   703     : d_ptr(new QGLFramebufferObjectPrivate)
       
   704 {
       
   705     Q_D(QGLFramebufferObject);
       
   706     d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
       
   707 }
       
   708 #endif
       
   709 
       
   710 /*! \overload
       
   711 
       
   712     Constructs an OpenGL framebuffer object and binds a 2D GL texture
       
   713     to the buffer of the given \a width and \a height.
       
   714 
       
   715     \sa size(), texture()
       
   716 */
       
   717 QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target)
       
   718     : d_ptr(new QGLFramebufferObjectPrivate)
       
   719 {
       
   720     Q_D(QGLFramebufferObject);
       
   721     d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
       
   722 }
       
   723 
       
   724 /*! \overload
       
   725 
       
   726     Constructs an OpenGL framebuffer object of the given \a size based on the
       
   727     supplied \a format.
       
   728 */
       
   729 
       
   730 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format)
       
   731     : d_ptr(new QGLFramebufferObjectPrivate)
       
   732 {
       
   733     Q_D(QGLFramebufferObject);
       
   734     d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
       
   735             format.samples());
       
   736 }
       
   737 
       
   738 /*! \overload
       
   739 
       
   740     Constructs an OpenGL framebuffer object of the given \a width and \a height
       
   741     based on the supplied \a format.
       
   742 */
       
   743 
       
   744 QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format)
       
   745     : d_ptr(new QGLFramebufferObjectPrivate)
       
   746 {
       
   747     Q_D(QGLFramebufferObject);
       
   748     d->init(this, QSize(width, height), format.attachment(), format.textureTarget(),
       
   749             format.internalTextureFormat(), format.samples());
       
   750 }
       
   751 
       
   752 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
   753 /*! \internal */
       
   754 QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLenum target)
       
   755     : d_ptr(new QGLFramebufferObjectPrivate)
       
   756 {
       
   757     Q_D(QGLFramebufferObject);
       
   758     d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
       
   759 }
       
   760 #endif
       
   761 
       
   762 /*! \overload
       
   763 
       
   764     Constructs an OpenGL framebuffer object and binds a texture to the
       
   765     buffer of the given \a width and \a height.
       
   766 
       
   767     The \a attachment parameter describes the depth/stencil buffer
       
   768     configuration, \a target the texture target and \a internal_format
       
   769     the internal texture format. The default texture target is \c
       
   770     GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
       
   771     for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
       
   772 
       
   773     \sa size(), texture(), attachment()
       
   774 */
       
   775 QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
       
   776                                            GLenum target, GLenum internal_format)
       
   777     : d_ptr(new QGLFramebufferObjectPrivate)
       
   778 {
       
   779     Q_D(QGLFramebufferObject);
       
   780     d->init(this, QSize(width, height), attachment, target, internal_format);
       
   781 }
       
   782 
       
   783 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
   784 /*! \internal */
       
   785 QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
       
   786                                            QMacCompatGLenum target, QMacCompatGLenum internal_format)
       
   787     : d_ptr(new QGLFramebufferObjectPrivate)
       
   788 {
       
   789     Q_D(QGLFramebufferObject);
       
   790     d->init(this, QSize(width, height), attachment, target, internal_format);
       
   791 }
       
   792 #endif
       
   793 
       
   794 /*! \overload
       
   795 
       
   796     Constructs an OpenGL framebuffer object and binds a texture to the
       
   797     buffer of the given \a size.
       
   798 
       
   799     The \a attachment parameter describes the depth/stencil buffer
       
   800     configuration, \a target the texture target and \a internal_format
       
   801     the internal texture format. The default texture target is \c
       
   802     GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
       
   803     for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
       
   804 
       
   805     \sa size(), texture(), attachment()
       
   806 */
       
   807 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
       
   808                                            GLenum target, GLenum internal_format)
       
   809     : d_ptr(new QGLFramebufferObjectPrivate)
       
   810 {
       
   811     Q_D(QGLFramebufferObject);
       
   812     d->init(this, size, attachment, target, internal_format);
       
   813 }
       
   814 
       
   815 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
   816 /*! \internal */
       
   817 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
       
   818                                            QMacCompatGLenum target, QMacCompatGLenum internal_format)
       
   819     : d_ptr(new QGLFramebufferObjectPrivate)
       
   820 {
       
   821     Q_D(QGLFramebufferObject);
       
   822     d->init(this, size, attachment, target, internal_format);
       
   823 }
       
   824 #endif
       
   825 
       
   826 /*!
       
   827     \fn QGLFramebufferObject::~QGLFramebufferObject()
       
   828 
       
   829     Destroys the framebuffer object and frees any allocated resources.
       
   830 */
       
   831 QGLFramebufferObject::~QGLFramebufferObject()
       
   832 {
       
   833     Q_D(QGLFramebufferObject);
       
   834     QGL_FUNC_CONTEXT;
       
   835 
       
   836     delete d->engine;
       
   837 
       
   838     if (isValid() && ctx) {
       
   839         QGLShareContextScope scope(ctx);
       
   840         if (d->texture)
       
   841             glDeleteTextures(1, &d->texture);
       
   842         if (d->color_buffer)
       
   843             glDeleteRenderbuffers(1, &d->color_buffer);
       
   844         if (d->depth_stencil_buffer)
       
   845             glDeleteRenderbuffers(1, &d->depth_stencil_buffer);
       
   846         GLuint fbo = d->fbo();
       
   847         glDeleteFramebuffers(1, &fbo);
       
   848     }
       
   849 }
       
   850 
       
   851 /*!
       
   852     \fn bool QGLFramebufferObject::isValid() const
       
   853 
       
   854     Returns true if the framebuffer object is valid.
       
   855 
       
   856     The framebuffer can become invalid if the initialization process
       
   857     fails, the user attaches an invalid buffer to the framebuffer
       
   858     object, or a non-power of two width/height is specified as the
       
   859     texture size if the texture target is \c{GL_TEXTURE_2D}.
       
   860     The non-power of two limitation does not apply if the OpenGL version
       
   861     is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension
       
   862     is present.
       
   863 
       
   864     The framebuffer can also become invalid if the QGLContext that
       
   865     the framebuffer was created within is destroyed and there are
       
   866     no other shared contexts that can take over ownership of the
       
   867     framebuffer.
       
   868 */
       
   869 bool QGLFramebufferObject::isValid() const
       
   870 {
       
   871     Q_D(const QGLFramebufferObject);
       
   872     return d->valid && d->fbo_guard.context();
       
   873 }
       
   874 
       
   875 /*!
       
   876     \fn bool QGLFramebufferObject::bind()
       
   877 
       
   878     Switches rendering from the default, windowing system provided
       
   879     framebuffer to this framebuffer object.
       
   880     Returns true upon success, false otherwise.
       
   881 
       
   882     Since 4.6: if another QGLFramebufferObject instance was already bound
       
   883     to the current context, then its handle() will be remembered and
       
   884     automatically restored when release() is called.  This allows multiple
       
   885     framebuffer rendering targets to be stacked up.  It is important that
       
   886     release() is called on the stacked framebuffer objects in the reverse
       
   887     order of the calls to bind().
       
   888 
       
   889     \sa release()
       
   890 */
       
   891 bool QGLFramebufferObject::bind()
       
   892 {
       
   893     if (!isValid())
       
   894 	return false;
       
   895     Q_D(QGLFramebufferObject);
       
   896     QGL_FUNC_CONTEXT;
       
   897     if (!ctx)
       
   898         return false;   // Context no longer exists.
       
   899     glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo());
       
   900     d->valid = d->checkFramebufferStatus();
       
   901     const QGLContext *context = QGLContext::currentContext();
       
   902     if (d->valid && context) {
       
   903         Q_ASSERT(QGLContextPrivate::contextGroup(context) == QGLContextPrivate::contextGroup(ctx));
       
   904         // Save the previous setting to automatically restore in release().
       
   905         if (context->d_ptr->current_fbo != d->fbo()) {
       
   906             d->previous_fbo = context->d_ptr->current_fbo;
       
   907             context->d_ptr->current_fbo = d->fbo();
       
   908         }
       
   909     }
       
   910     return d->valid;
       
   911 }
       
   912 
       
   913 /*!
       
   914     \fn bool QGLFramebufferObject::release()
       
   915 
       
   916     Switches rendering back to the default, windowing system provided
       
   917     framebuffer.
       
   918     Returns true upon success, false otherwise.
       
   919 
       
   920     Since 4.6: if another QGLFramebufferObject instance was already bound
       
   921     to the current context when bind() was called, then this function will
       
   922     automatically re-bind it to the current context.
       
   923 
       
   924     \sa bind()
       
   925 */
       
   926 bool QGLFramebufferObject::release()
       
   927 {
       
   928     if (!isValid())
       
   929 	return false;
       
   930     Q_D(QGLFramebufferObject);
       
   931     QGL_FUNC_CONTEXT;
       
   932     if (!ctx)
       
   933         return false;   // Context no longer exists.
       
   934 
       
   935     const QGLContext *context = QGLContext::currentContext();
       
   936     if (context) {
       
   937         Q_ASSERT(QGLContextPrivate::contextGroup(context) == QGLContextPrivate::contextGroup(ctx));
       
   938         // Restore the previous setting for stacked framebuffer objects.
       
   939         if (d->previous_fbo != context->d_ptr->current_fbo) {
       
   940             context->d_ptr->current_fbo = d->previous_fbo;
       
   941             glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->previous_fbo);
       
   942         }
       
   943         d->previous_fbo = 0;
       
   944     }
       
   945 
       
   946     return true;
       
   947 }
       
   948 
       
   949 /*!
       
   950     \fn GLuint QGLFramebufferObject::texture() const
       
   951 
       
   952     Returns the texture id for the texture attached as the default
       
   953     rendering target in this framebuffer object. This texture id can
       
   954     be bound as a normal texture in your own GL code.
       
   955 
       
   956     If a multisample framebuffer object is used then the value returned
       
   957     from this function will be invalid.
       
   958 */
       
   959 GLuint QGLFramebufferObject::texture() const
       
   960 {
       
   961     Q_D(const QGLFramebufferObject);
       
   962     return d->texture;
       
   963 }
       
   964 
       
   965 /*!
       
   966     \fn QSize QGLFramebufferObject::size() const
       
   967 
       
   968     Returns the size of the texture attached to this framebuffer
       
   969     object.
       
   970 */
       
   971 QSize QGLFramebufferObject::size() const
       
   972 {
       
   973     Q_D(const QGLFramebufferObject);
       
   974     return d->size;
       
   975 }
       
   976 
       
   977 /*!
       
   978     Returns the format of this framebuffer object.
       
   979 */
       
   980 QGLFramebufferObjectFormat QGLFramebufferObject::format() const
       
   981 {
       
   982     Q_D(const QGLFramebufferObject);
       
   983     return d->format;
       
   984 }
       
   985 
       
   986 /*!
       
   987     \fn QImage QGLFramebufferObject::toImage() const
       
   988 
       
   989     Returns the contents of this framebuffer object as a QImage.
       
   990 */
       
   991 QImage QGLFramebufferObject::toImage() const
       
   992 {
       
   993     Q_D(const QGLFramebufferObject);
       
   994     if (!d->valid)
       
   995         return QImage();
       
   996 
       
   997     // qt_gl_read_framebuffer doesn't work on a multisample FBO
       
   998     if (format().samples() != 0) {
       
   999         QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat());
       
  1000 
       
  1001         QRect rect(QPoint(0, 0), size());
       
  1002         blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect);
       
  1003 
       
  1004         return temp.toImage();
       
  1005     }
       
  1006 
       
  1007     bool wasBound = isBound();
       
  1008     if (!wasBound)
       
  1009         const_cast<QGLFramebufferObject *>(this)->bind();
       
  1010     QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true);
       
  1011     if (!wasBound)
       
  1012         const_cast<QGLFramebufferObject *>(this)->release();
       
  1013 
       
  1014     return image;
       
  1015 }
       
  1016 
       
  1017 #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
       
  1018 Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine)
       
  1019 #endif
       
  1020 
       
  1021 #ifndef QT_OPENGL_ES_2
       
  1022 Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine)
       
  1023 #endif
       
  1024 
       
  1025 /*! \reimp */
       
  1026 QPaintEngine *QGLFramebufferObject::paintEngine() const
       
  1027 {
       
  1028     Q_D(const QGLFramebufferObject);
       
  1029     if (d->engine)
       
  1030         return d->engine;
       
  1031 
       
  1032 #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
       
  1033 #if !defined (QT_OPENGL_ES_2)
       
  1034     if (qt_gl_preferGL2Engine()) {
       
  1035 #endif
       
  1036         QPaintEngine *engine = qt_buffer_2_engine();
       
  1037         if (engine->isActive() && engine->paintDevice() != this) {
       
  1038             d->engine = new QGL2PaintEngineEx;
       
  1039             return d->engine;
       
  1040         }
       
  1041         return engine;
       
  1042 #if !defined (QT_OPENGL_ES_2)
       
  1043     }
       
  1044 #endif
       
  1045 #endif
       
  1046 
       
  1047 #if !defined(QT_OPENGL_ES_2)
       
  1048     QPaintEngine *engine = qt_buffer_engine();
       
  1049     if (engine->isActive() && engine->paintDevice() != this) {
       
  1050         d->engine = new QOpenGLPaintEngine;
       
  1051         return d->engine;
       
  1052     }
       
  1053     return engine;
       
  1054 #endif
       
  1055 }
       
  1056 
       
  1057 /*!
       
  1058     \fn bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
       
  1059 
       
  1060     Returns true if the OpenGL \c{GL_EXT_framebuffer_object} extension
       
  1061     is present on this system; otherwise returns false.
       
  1062 */
       
  1063 bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
       
  1064 {
       
  1065     QGLExtensions::init();
       
  1066     return (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
       
  1067 }
       
  1068 
       
  1069 /*!
       
  1070     \since 4.4
       
  1071 
       
  1072     Draws the given texture, \a textureId, to the given target rectangle,
       
  1073     \a target, in OpenGL model space. The \a textureTarget should be a 2D
       
  1074     texture target.
       
  1075 
       
  1076     The framebuffer object should be bound when calling this function.
       
  1077 
       
  1078     Equivalent to the corresponding QGLContext::drawTexture().
       
  1079 */
       
  1080 void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
       
  1081 {
       
  1082     const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
       
  1083 }
       
  1084 
       
  1085 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
  1086 /*! \internal */
       
  1087 void QGLFramebufferObject::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
       
  1088 {
       
  1089     const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
       
  1090 }
       
  1091 #endif
       
  1092 
       
  1093 /*!
       
  1094     \since 4.4
       
  1095 
       
  1096     Draws the given texture, \a textureId, at the given \a point in OpenGL
       
  1097     model space. The \a textureTarget should be a 2D texture target.
       
  1098 
       
  1099     The framebuffer object should be bound when calling this function.
       
  1100 
       
  1101     Equivalent to the corresponding QGLContext::drawTexture().
       
  1102 */
       
  1103 void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
       
  1104 {
       
  1105     const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
       
  1106 }
       
  1107 
       
  1108 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
  1109 /*! \internal */
       
  1110 void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
       
  1111 {
       
  1112     const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
       
  1113 }
       
  1114 #endif
       
  1115 
       
  1116 extern int qt_defaultDpiX();
       
  1117 extern int qt_defaultDpiY();
       
  1118 
       
  1119 /*! \reimp */
       
  1120 int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
       
  1121 {
       
  1122     Q_D(const QGLFramebufferObject);
       
  1123 
       
  1124     float dpmx = qt_defaultDpiX()*100./2.54;
       
  1125     float dpmy = qt_defaultDpiY()*100./2.54;
       
  1126     int w = d->size.width();
       
  1127     int h = d->size.height();
       
  1128     switch (metric) {
       
  1129     case PdmWidth:
       
  1130         return w;
       
  1131 
       
  1132     case PdmHeight:
       
  1133         return h;
       
  1134 
       
  1135     case PdmWidthMM:
       
  1136         return qRound(w * 1000 / dpmx);
       
  1137 
       
  1138     case PdmHeightMM:
       
  1139         return qRound(h * 1000 / dpmy);
       
  1140 
       
  1141     case PdmNumColors:
       
  1142         return 0;
       
  1143 
       
  1144     case PdmDepth:
       
  1145         return 32;//d->depth;
       
  1146 
       
  1147     case PdmDpiX:
       
  1148         return qRound(dpmx * 0.0254);
       
  1149 
       
  1150     case PdmDpiY:
       
  1151         return qRound(dpmy * 0.0254);
       
  1152 
       
  1153     case PdmPhysicalDpiX:
       
  1154         return qRound(dpmx * 0.0254);
       
  1155 
       
  1156     case PdmPhysicalDpiY:
       
  1157         return qRound(dpmy * 0.0254);
       
  1158 
       
  1159     default:
       
  1160         qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric);
       
  1161         break;
       
  1162     }
       
  1163     return 0;
       
  1164 }
       
  1165 
       
  1166 /*!
       
  1167     \fn GLuint QGLFramebufferObject::handle() const
       
  1168 
       
  1169     Returns the GL framebuffer object handle for this framebuffer
       
  1170     object (returned by the \c{glGenFrameBuffersEXT()} function). This
       
  1171     handle can be used to attach new images or buffers to the
       
  1172     framebuffer. The user is responsible for cleaning up and
       
  1173     destroying these objects.
       
  1174 */
       
  1175 GLuint QGLFramebufferObject::handle() const
       
  1176 {
       
  1177     Q_D(const QGLFramebufferObject);
       
  1178     return d->fbo();
       
  1179 }
       
  1180 
       
  1181 /*! \fn int QGLFramebufferObject::devType() const
       
  1182     \internal
       
  1183 */
       
  1184 
       
  1185 
       
  1186 /*!
       
  1187     Returns the status of the depth and stencil buffers attached to
       
  1188     this framebuffer object.
       
  1189 */
       
  1190 
       
  1191 QGLFramebufferObject::Attachment QGLFramebufferObject::attachment() const
       
  1192 {
       
  1193     Q_D(const QGLFramebufferObject);
       
  1194     if (d->valid)
       
  1195         return d->fbo_attachment;
       
  1196     return NoAttachment;
       
  1197 }
       
  1198 
       
  1199 /*!
       
  1200     \since 4.5
       
  1201 
       
  1202     Returns true if the framebuffer object is currently bound to a context,
       
  1203     otherwise false is returned.
       
  1204 */
       
  1205 
       
  1206 bool QGLFramebufferObject::isBound() const
       
  1207 {
       
  1208     Q_D(const QGLFramebufferObject);
       
  1209     const QGLContext *current = QGLContext::currentContext();
       
  1210     return current ? current->d_ptr->current_fbo == d->fbo() : false;
       
  1211 }
       
  1212 
       
  1213 /*!
       
  1214     \fn bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
       
  1215 
       
  1216     \since 4.6
       
  1217 
       
  1218     Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension
       
  1219     is present on this system; otherwise returns false.
       
  1220 
       
  1221     \sa blitFramebuffer()
       
  1222 */
       
  1223 bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
       
  1224 {
       
  1225     QGLExtensions::init();
       
  1226     return (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit);
       
  1227 }
       
  1228 
       
  1229 /*!
       
  1230     \since 4.6
       
  1231 
       
  1232     Blits from the \a sourceRect rectangle in the \a source framebuffer
       
  1233     object to the \a targetRect rectangle in the \a target framebuffer object.
       
  1234 
       
  1235     If \a source or \a target is 0, the default framebuffer will be used
       
  1236     instead of a framebuffer object as source or target respectively.
       
  1237 
       
  1238     The \a buffers parameter should be a mask consisting of any combination of
       
  1239     \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and
       
  1240     \c GL_STENCIL_BUFFER_BIT.  Any buffer type that is not present both
       
  1241     in the source and target buffers is ignored.
       
  1242 
       
  1243     The \a sourceRect and \a targetRect rectangles may have different sizes;
       
  1244     in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or
       
  1245     \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to
       
  1246     \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest
       
  1247     interpolation should be used when scaling is performed.
       
  1248 
       
  1249     If \a source equals \a target a copy is performed within the same buffer.
       
  1250     Results are undefined if the source and target rectangles overlap and
       
  1251     have different sizes. The sizes must also be the same if any of the
       
  1252     framebuffer objects are multisample framebuffers.
       
  1253 
       
  1254     Note that the scissor test will restrict the blit area if enabled.
       
  1255 
       
  1256     This function will have no effect unless hasOpenGLFramebufferBlit() returns
       
  1257     true.
       
  1258 
       
  1259     \sa hasOpenGLFramebufferBlit()
       
  1260 */
       
  1261 void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect,
       
  1262                                            QGLFramebufferObject *source, const QRect &sourceRect,
       
  1263                                            GLbitfield buffers,
       
  1264                                            GLenum filter)
       
  1265 {
       
  1266     if (!(QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit))
       
  1267         return;
       
  1268 
       
  1269     const QGLContext *ctx = QGLContext::currentContext();
       
  1270     if (!ctx)
       
  1271         return;
       
  1272 
       
  1273     const int height = ctx->device()->height();
       
  1274 
       
  1275     const int sh = source ? source->height() : height;
       
  1276     const int th = target ? target->height() : height;
       
  1277 
       
  1278     const int sx0 = sourceRect.left();
       
  1279     const int sx1 = sourceRect.left() + sourceRect.width();
       
  1280     const int sy0 = sh - (sourceRect.top() + sourceRect.height());
       
  1281     const int sy1 = sh - sourceRect.top();
       
  1282 
       
  1283     const int tx0 = targetRect.left();
       
  1284     const int tx1 = targetRect.left() + targetRect.width();
       
  1285     const int ty0 = th - (targetRect.top() + targetRect.height());
       
  1286     const int ty1 = th - targetRect.top();
       
  1287 
       
  1288     glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, source ? source->handle() : 0);
       
  1289     glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, target ? target->handle() : 0);
       
  1290 
       
  1291     glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
       
  1292                          tx0, ty0, tx1, ty1,
       
  1293                          buffers, filter);
       
  1294 
       
  1295     glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
       
  1296 }
       
  1297 
       
  1298 QT_END_NAMESPACE