util/src/opengl/qglframebufferobject.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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     GLenum format = f->format().internalTextureFormat();
       
   334     reqAlpha = (format != GL_RGB
       
   335 #ifndef QT_OPENGL_ES
       
   336                 && format != GL_RGB5 && format != GL_RGB8
       
   337 #endif
       
   338     );
       
   339 }
       
   340 
       
   341 QGLContext *QGLFBOGLPaintDevice::context() const
       
   342 {
       
   343     QGLContext *fboContext = const_cast<QGLContext *>(fbo->d_ptr->fbo_guard.context());
       
   344     QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
       
   345 
       
   346     if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext))
       
   347         return currentContext;
       
   348     else
       
   349         return fboContext;
       
   350 }
       
   351 
       
   352 bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
       
   353 {
       
   354     QGL_FUNCP_CONTEXT;
       
   355     if (!ctx)
       
   356         return false;   // Context no longer exists.
       
   357     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
       
   358     switch(status) {
       
   359     case GL_NO_ERROR:
       
   360     case GL_FRAMEBUFFER_COMPLETE_EXT:
       
   361         return true;
       
   362         break;
       
   363     case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
       
   364         qDebug("QGLFramebufferObject: Unsupported framebuffer format.");
       
   365         break;
       
   366     case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
       
   367         qDebug("QGLFramebufferObject: Framebuffer incomplete attachment.");
       
   368         break;
       
   369     case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
       
   370         qDebug("QGLFramebufferObject: Framebuffer incomplete, missing attachment.");
       
   371         break;
       
   372 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
       
   373     case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
       
   374         qDebug("QGLFramebufferObject: Framebuffer incomplete, duplicate attachment.");
       
   375         break;
       
   376 #endif
       
   377     case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
       
   378         qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions.");
       
   379         break;
       
   380     case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
       
   381         qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same format.");
       
   382         break;
       
   383     case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
       
   384         qDebug("QGLFramebufferObject: Framebuffer incomplete, missing draw buffer.");
       
   385         break;
       
   386     case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
       
   387         qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer.");
       
   388         break;
       
   389     case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
       
   390         qDebug("QGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel.");
       
   391         break;
       
   392     default:
       
   393         qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status;
       
   394         break;
       
   395     }
       
   396     return false;
       
   397 }
       
   398 
       
   399 void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
       
   400                                        QGLFramebufferObject::Attachment attachment,
       
   401                                        GLenum texture_target, GLenum internal_format, GLint samples)
       
   402 {
       
   403     QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
       
   404     fbo_guard.setContext(ctx);
       
   405 
       
   406     bool ext_detected = (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
       
   407     if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
       
   408         return;
       
   409 
       
   410     size = sz;
       
   411     target = texture_target;
       
   412     // texture dimensions
       
   413 
       
   414     QT_RESET_GLERROR(); // reset error state
       
   415     GLuint fbo = 0;
       
   416     glGenFramebuffers(1, &fbo);
       
   417     glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
       
   418     fbo_guard.setId(fbo);
       
   419 
       
   420     glDevice.setFBO(q, attachment);
       
   421 
       
   422     QT_CHECK_GLERROR();
       
   423     // init texture
       
   424     if (samples == 0) {
       
   425         glGenTextures(1, &texture);
       
   426         glBindTexture(target, texture);
       
   427         glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
       
   428                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
       
   429 #ifndef QT_OPENGL_ES
       
   430         glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
       
   431         glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
       
   432         glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
       
   433         glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
       
   434 #else
       
   435         glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
       
   436         glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
       
   437         glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
       
   438         glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
       
   439 #endif
       
   440         glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
       
   441                 target, texture, 0);
       
   442 
       
   443         QT_CHECK_GLERROR();
       
   444         valid = checkFramebufferStatus();
       
   445         glBindTexture(target, 0);
       
   446 
       
   447         color_buffer = 0;
       
   448     } else {
       
   449         GLint maxSamples;
       
   450         glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
       
   451 
       
   452         samples = qBound(1, int(samples), int(maxSamples));
       
   453 
       
   454         glGenRenderbuffers(1, &color_buffer);
       
   455         glBindRenderbuffer(GL_RENDERBUFFER_EXT, color_buffer);
       
   456         if (glRenderbufferStorageMultisampleEXT) {
       
   457             glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
       
   458                 internal_format, size.width(), size.height());
       
   459         } else {
       
   460             samples = 0;
       
   461             glRenderbufferStorage(GL_RENDERBUFFER_EXT, internal_format,
       
   462                 size.width(), size.height());
       
   463         }
       
   464 
       
   465         glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
       
   466                                      GL_RENDERBUFFER_EXT, color_buffer);
       
   467 
       
   468         QT_CHECK_GLERROR();
       
   469         valid = checkFramebufferStatus();
       
   470 
       
   471         if (valid)
       
   472             glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &samples);
       
   473     }
       
   474 
       
   475     if (attachment == QGLFramebufferObject::CombinedDepthStencil
       
   476         && (QGLExtensions::glExtensions() & QGLExtensions::PackedDepthStencil)) {
       
   477         // depth and stencil buffer needs another extension
       
   478         glGenRenderbuffers(1, &depth_stencil_buffer);
       
   479         Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
       
   480         glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
       
   481         Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
       
   482         if (samples != 0 && glRenderbufferStorageMultisampleEXT)
       
   483             glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
       
   484                 GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
       
   485         else
       
   486             glRenderbufferStorage(GL_RENDERBUFFER_EXT,
       
   487                 GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
       
   488 
       
   489         GLint i = 0;
       
   490         glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
       
   491         glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
       
   492                                      GL_RENDERBUFFER_EXT, depth_stencil_buffer);
       
   493         glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
       
   494                                      GL_RENDERBUFFER_EXT, depth_stencil_buffer);
       
   495         fbo_attachment = QGLFramebufferObject::CombinedDepthStencil;
       
   496 
       
   497         valid = checkFramebufferStatus();
       
   498         if (!valid)
       
   499             glDeleteRenderbuffers(1, &depth_stencil_buffer);
       
   500     } else if (attachment == QGLFramebufferObject::Depth
       
   501                || attachment == QGLFramebufferObject::CombinedDepthStencil)
       
   502     {
       
   503         glGenRenderbuffers(1, &depth_stencil_buffer);
       
   504         Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
       
   505         glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
       
   506         Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
       
   507         if (samples != 0 && glRenderbufferStorageMultisampleEXT) {
       
   508 #ifdef QT_OPENGL_ES
       
   509 #define GL_DEPTH_COMPONENT16 0x81A5
       
   510             glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
       
   511                 GL_DEPTH_COMPONENT16, size.width(), size.height());
       
   512 #else
       
   513             glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
       
   514                 GL_DEPTH_COMPONENT, size.width(), size.height());
       
   515 #endif
       
   516         } else {
       
   517 #ifdef QT_OPENGL_ES
       
   518 #define GL_DEPTH_COMPONENT16 0x81A5
       
   519             glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height());
       
   520 #else
       
   521             glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height());
       
   522 #endif
       
   523         }
       
   524         GLint i = 0;
       
   525         glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
       
   526         glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
       
   527                                      GL_RENDERBUFFER_EXT, depth_stencil_buffer);
       
   528         fbo_attachment = QGLFramebufferObject::Depth;
       
   529         valid = checkFramebufferStatus();
       
   530         if (!valid)
       
   531             glDeleteRenderbuffers(1, &depth_stencil_buffer);
       
   532     } else {
       
   533         fbo_attachment = QGLFramebufferObject::NoAttachment;
       
   534     }
       
   535 
       
   536     glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
       
   537     if (!valid) {
       
   538         if (color_buffer)
       
   539             glDeleteRenderbuffers(1, &color_buffer);
       
   540         else
       
   541             glDeleteTextures(1, &texture);
       
   542         glDeleteFramebuffers(1, &fbo);
       
   543         fbo_guard.setId(0);
       
   544     }
       
   545     QT_CHECK_GLERROR();
       
   546 
       
   547     format.setTextureTarget(target);
       
   548     format.setSamples(int(samples));
       
   549     format.setAttachment(fbo_attachment);
       
   550     format.setInternalTextureFormat(internal_format);
       
   551 }
       
   552 
       
   553 /*!
       
   554     \class QGLFramebufferObject
       
   555     \brief The QGLFramebufferObject class encapsulates an OpenGL framebuffer object.
       
   556     \since 4.2
       
   557 
       
   558     \ingroup painting-3D
       
   559 
       
   560     The QGLFramebufferObject class encapsulates an OpenGL framebuffer
       
   561     object, defined by the \c{GL_EXT_framebuffer_object} extension. In
       
   562     addition it provides a rendering surface that can be painted on
       
   563     with a QPainter, rendered to using native GL calls, or both. This
       
   564     surface can be bound and used as a regular texture in your own GL
       
   565     drawing code.  By default, the QGLFramebufferObject class
       
   566     generates a 2D GL texture (using the \c{GL_TEXTURE_2D} target),
       
   567     which is used as the internal rendering target.
       
   568 
       
   569     \bold{It is important to have a current GL context when creating a
       
   570     QGLFramebufferObject, otherwise initialization will fail.}
       
   571 
       
   572     OpenGL framebuffer objects and pbuffers (see
       
   573     \l{QGLPixelBuffer}{QGLPixelBuffer}) can both be used to render to
       
   574     offscreen surfaces, but there are a number of advantages with
       
   575     using framebuffer objects instead of pbuffers:
       
   576 
       
   577     \list 1
       
   578     \o A framebuffer object does not require a separate rendering
       
   579     context, so no context switching will occur when switching
       
   580     rendering targets. There is an overhead involved in switching
       
   581     targets, but in general it is cheaper than a context switch to a
       
   582     pbuffer.
       
   583 
       
   584     \o Rendering to dynamic textures (i.e. render-to-texture
       
   585     functionality) works on all platforms. No need to do explicit copy
       
   586     calls from a render buffer into a texture, as was necessary on
       
   587     systems that did not support the \c{render_texture} extension.
       
   588 
       
   589     \o It is possible to attach several rendering buffers (or texture
       
   590     objects) to the same framebuffer object, and render to all of them
       
   591     without doing a context switch.
       
   592 
       
   593     \o The OpenGL framebuffer extension is a pure GL extension with no
       
   594     system dependant WGL, CGL, or GLX parts. This makes using
       
   595     framebuffer objects more portable.
       
   596     \endlist
       
   597 
       
   598     When using a QPainter to paint to a QGLFramebufferObject you should take
       
   599     care that the QGLFramebufferObject is created with the CombinedDepthStencil
       
   600     attachment for QPainter to be able to render correctly.
       
   601     Note that you need to create a QGLFramebufferObject with more than one
       
   602     sample per pixel for primitives to be antialiased when drawing using a
       
   603     QPainter. To create a multisample framebuffer object you should use one of
       
   604     the constructors that take a QGLFramebufferObject parameter, and set the
       
   605     QGLFramebufferObject::samples() property to a non-zero value.
       
   606 
       
   607     When painting to a QGLFramebufferObject using QPainter, the state of
       
   608     the current GL context will be altered by the paint engine to reflect
       
   609     its needs.  Applications should not rely upon the GL state being reset
       
   610     to its original conditions, particularly the current shader program,
       
   611     GL viewport, texture units, and drawing modes.
       
   612 
       
   613     For multisample framebuffer objects a color render buffer is created,
       
   614     otherwise a texture with the specified texture target is created.
       
   615     The color render buffer or texture will have the specified internal
       
   616     format, and will be bound to the \c GL_COLOR_ATTACHMENT0
       
   617     attachment in the framebuffer object.
       
   618 
       
   619     If you want to use a framebuffer object with multisampling enabled
       
   620     as a texture, you first need to copy from it to a regular framebuffer
       
   621     object using QGLContext::blitFramebuffer().
       
   622 
       
   623     \sa {Framebuffer Object Example}
       
   624 */
       
   625 
       
   626 
       
   627 /*!
       
   628     \enum QGLFramebufferObject::Attachment
       
   629     \since 4.3
       
   630 
       
   631     This enum type is used to configure the depth and stencil buffers
       
   632     attached to the framebuffer object when it is created.
       
   633 
       
   634     \value NoAttachment         No attachment is added to the framebuffer object. Note that the
       
   635                                 OpenGL depth and stencil tests won't work when rendering to a
       
   636                                 framebuffer object without any depth or stencil buffers.
       
   637                                 This is the default value.
       
   638 
       
   639     \value CombinedDepthStencil If the \c GL_EXT_packed_depth_stencil extension is present,
       
   640                                 a combined depth and stencil buffer is attached.
       
   641                                 If the extension is not present, only a depth buffer is attached.
       
   642 
       
   643     \value Depth                A depth buffer is attached to the framebuffer object.
       
   644 
       
   645     \sa attachment()
       
   646 */
       
   647 
       
   648 
       
   649 /*! \fn QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
       
   650 
       
   651     Constructs an OpenGL framebuffer object and binds a 2D GL texture
       
   652     to the buffer of the size \a size. The texture is bound to the
       
   653     \c GL_COLOR_ATTACHMENT0 target in the framebuffer object.
       
   654 
       
   655     The \a target parameter is used to specify the GL texture
       
   656     target. The default target is \c GL_TEXTURE_2D. Keep in mind that
       
   657     \c GL_TEXTURE_2D textures must have a power of 2 width and height
       
   658     (e.g. 256x512), unless you are using OpenGL 2.0 or higher.
       
   659 
       
   660     By default, no depth and stencil buffers are attached. This behavior
       
   661     can be toggled using one of the overloaded constructors.
       
   662 
       
   663     The default internal texture format is \c GL_RGBA8 for desktop
       
   664     OpenGL, and \c GL_RGBA for OpenGL/ES.
       
   665 
       
   666     It is important that you have a current GL context set when
       
   667     creating the QGLFramebufferObject, otherwise the initialization
       
   668     will fail.
       
   669 
       
   670     \sa size(), texture(), attachment()
       
   671 */
       
   672 
       
   673 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
       
   674     : d_ptr(new QGLFramebufferObjectPrivate)
       
   675 {
       
   676     Q_D(QGLFramebufferObject);
       
   677     d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
       
   678 }
       
   679 
       
   680 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
   681 /*! \internal */
       
   682 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, QMacCompatGLenum target)
       
   683     : d_ptr(new QGLFramebufferObjectPrivate)
       
   684 {
       
   685     Q_D(QGLFramebufferObject);
       
   686     d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
       
   687 }
       
   688 #endif
       
   689 
       
   690 /*! \overload
       
   691 
       
   692     Constructs an OpenGL framebuffer object and binds a 2D GL texture
       
   693     to the buffer of the given \a width and \a height.
       
   694 
       
   695     \sa size(), texture()
       
   696 */
       
   697 QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target)
       
   698     : d_ptr(new QGLFramebufferObjectPrivate)
       
   699 {
       
   700     Q_D(QGLFramebufferObject);
       
   701     d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
       
   702 }
       
   703 
       
   704 /*! \overload
       
   705 
       
   706     Constructs an OpenGL framebuffer object of the given \a size based on the
       
   707     supplied \a format.
       
   708 */
       
   709 
       
   710 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format)
       
   711     : d_ptr(new QGLFramebufferObjectPrivate)
       
   712 {
       
   713     Q_D(QGLFramebufferObject);
       
   714     d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
       
   715             format.samples());
       
   716 }
       
   717 
       
   718 /*! \overload
       
   719 
       
   720     Constructs an OpenGL framebuffer object of the given \a width and \a height
       
   721     based on the supplied \a format.
       
   722 */
       
   723 
       
   724 QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format)
       
   725     : d_ptr(new QGLFramebufferObjectPrivate)
       
   726 {
       
   727     Q_D(QGLFramebufferObject);
       
   728     d->init(this, QSize(width, height), format.attachment(), format.textureTarget(),
       
   729             format.internalTextureFormat(), format.samples());
       
   730 }
       
   731 
       
   732 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
   733 /*! \internal */
       
   734 QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLenum target)
       
   735     : d_ptr(new QGLFramebufferObjectPrivate)
       
   736 {
       
   737     Q_D(QGLFramebufferObject);
       
   738     d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
       
   739 }
       
   740 #endif
       
   741 
       
   742 /*! \overload
       
   743 
       
   744     Constructs an OpenGL framebuffer object and binds a texture to the
       
   745     buffer of the given \a width and \a height.
       
   746 
       
   747     The \a attachment parameter describes the depth/stencil buffer
       
   748     configuration, \a target the texture target and \a internal_format
       
   749     the internal texture format. The default texture target is \c
       
   750     GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
       
   751     for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
       
   752 
       
   753     \sa size(), texture(), attachment()
       
   754 */
       
   755 QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
       
   756                                            GLenum target, GLenum internal_format)
       
   757     : d_ptr(new QGLFramebufferObjectPrivate)
       
   758 {
       
   759     Q_D(QGLFramebufferObject);
       
   760     d->init(this, QSize(width, height), attachment, target, internal_format);
       
   761 }
       
   762 
       
   763 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
   764 /*! \internal */
       
   765 QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
       
   766                                            QMacCompatGLenum target, QMacCompatGLenum internal_format)
       
   767     : d_ptr(new QGLFramebufferObjectPrivate)
       
   768 {
       
   769     Q_D(QGLFramebufferObject);
       
   770     d->init(this, QSize(width, height), attachment, target, internal_format);
       
   771 }
       
   772 #endif
       
   773 
       
   774 /*! \overload
       
   775 
       
   776     Constructs an OpenGL framebuffer object and binds a texture to the
       
   777     buffer of the given \a size.
       
   778 
       
   779     The \a attachment parameter describes the depth/stencil buffer
       
   780     configuration, \a target the texture target and \a internal_format
       
   781     the internal texture format. The default texture target is \c
       
   782     GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
       
   783     for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
       
   784 
       
   785     \sa size(), texture(), attachment()
       
   786 */
       
   787 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
       
   788                                            GLenum target, GLenum internal_format)
       
   789     : d_ptr(new QGLFramebufferObjectPrivate)
       
   790 {
       
   791     Q_D(QGLFramebufferObject);
       
   792     d->init(this, size, attachment, target, internal_format);
       
   793 }
       
   794 
       
   795 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
   796 /*! \internal */
       
   797 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
       
   798                                            QMacCompatGLenum target, QMacCompatGLenum internal_format)
       
   799     : d_ptr(new QGLFramebufferObjectPrivate)
       
   800 {
       
   801     Q_D(QGLFramebufferObject);
       
   802     d->init(this, size, attachment, target, internal_format);
       
   803 }
       
   804 #endif
       
   805 
       
   806 /*!
       
   807     \fn QGLFramebufferObject::~QGLFramebufferObject()
       
   808 
       
   809     Destroys the framebuffer object and frees any allocated resources.
       
   810 */
       
   811 QGLFramebufferObject::~QGLFramebufferObject()
       
   812 {
       
   813     Q_D(QGLFramebufferObject);
       
   814     QGL_FUNC_CONTEXT;
       
   815 
       
   816     delete d->engine;
       
   817 
       
   818     if (isValid() && ctx) {
       
   819         QGLShareContextScope scope(ctx);
       
   820         if (d->texture)
       
   821             glDeleteTextures(1, &d->texture);
       
   822         if (d->color_buffer)
       
   823             glDeleteRenderbuffers(1, &d->color_buffer);
       
   824         if (d->depth_stencil_buffer)
       
   825             glDeleteRenderbuffers(1, &d->depth_stencil_buffer);
       
   826         GLuint fbo = d->fbo();
       
   827         glDeleteFramebuffers(1, &fbo);
       
   828     }
       
   829 }
       
   830 
       
   831 /*!
       
   832     \fn bool QGLFramebufferObject::isValid() const
       
   833 
       
   834     Returns true if the framebuffer object is valid.
       
   835 
       
   836     The framebuffer can become invalid if the initialization process
       
   837     fails, the user attaches an invalid buffer to the framebuffer
       
   838     object, or a non-power of two width/height is specified as the
       
   839     texture size if the texture target is \c{GL_TEXTURE_2D}.
       
   840     The non-power of two limitation does not apply if the OpenGL version
       
   841     is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension
       
   842     is present.
       
   843 
       
   844     The framebuffer can also become invalid if the QGLContext that
       
   845     the framebuffer was created within is destroyed and there are
       
   846     no other shared contexts that can take over ownership of the
       
   847     framebuffer.
       
   848 */
       
   849 bool QGLFramebufferObject::isValid() const
       
   850 {
       
   851     Q_D(const QGLFramebufferObject);
       
   852     return d->valid && d->fbo_guard.context();
       
   853 }
       
   854 
       
   855 /*!
       
   856     \fn bool QGLFramebufferObject::bind()
       
   857 
       
   858     Switches rendering from the default, windowing system provided
       
   859     framebuffer to this framebuffer object.
       
   860     Returns true upon success, false otherwise.
       
   861 
       
   862     \sa release()
       
   863 */
       
   864 bool QGLFramebufferObject::bind()
       
   865 {
       
   866     if (!isValid())
       
   867 	return false;
       
   868     Q_D(QGLFramebufferObject);
       
   869     QGL_FUNC_CONTEXT;
       
   870     if (!ctx)
       
   871         return false;   // Context no longer exists.
       
   872     const QGLContext *current = QGLContext::currentContext();
       
   873 #ifdef QT_DEBUG
       
   874     if (!current ||
       
   875         QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
       
   876     {
       
   877         qWarning("QGLFramebufferObject::bind() called from incompatible context");
       
   878     }
       
   879 #endif
       
   880     glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo());
       
   881     d->valid = d->checkFramebufferStatus();
       
   882     if (d->valid && current)
       
   883         current->d_ptr->current_fbo = d->fbo();
       
   884     return d->valid;
       
   885 }
       
   886 
       
   887 /*!
       
   888     \fn bool QGLFramebufferObject::release()
       
   889 
       
   890     Switches rendering back to the default, windowing system provided
       
   891     framebuffer.
       
   892     Returns true upon success, false otherwise.
       
   893 
       
   894     \sa bind()
       
   895 */
       
   896 bool QGLFramebufferObject::release()
       
   897 {
       
   898     if (!isValid())
       
   899 	return false;
       
   900     QGL_FUNC_CONTEXT;
       
   901     if (!ctx)
       
   902         return false;   // Context no longer exists.
       
   903 
       
   904     const QGLContext *current = QGLContext::currentContext();
       
   905 
       
   906 #ifdef QT_DEBUG
       
   907     if (!current ||
       
   908         QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
       
   909     {
       
   910         qWarning("QGLFramebufferObject::release() called from incompatible context");
       
   911     }
       
   912 #endif
       
   913 
       
   914     if (current) {
       
   915         current->d_ptr->current_fbo = current->d_ptr->default_fbo;
       
   916         glBindFramebuffer(GL_FRAMEBUFFER_EXT, current->d_ptr->default_fbo);
       
   917     }
       
   918 
       
   919     return true;
       
   920 }
       
   921 
       
   922 /*!
       
   923     \fn GLuint QGLFramebufferObject::texture() const
       
   924 
       
   925     Returns the texture id for the texture attached as the default
       
   926     rendering target in this framebuffer object. This texture id can
       
   927     be bound as a normal texture in your own GL code.
       
   928 
       
   929     If a multisample framebuffer object is used then the value returned
       
   930     from this function will be invalid.
       
   931 */
       
   932 GLuint QGLFramebufferObject::texture() const
       
   933 {
       
   934     Q_D(const QGLFramebufferObject);
       
   935     return d->texture;
       
   936 }
       
   937 
       
   938 /*!
       
   939     \fn QSize QGLFramebufferObject::size() const
       
   940 
       
   941     Returns the size of the texture attached to this framebuffer
       
   942     object.
       
   943 */
       
   944 QSize QGLFramebufferObject::size() const
       
   945 {
       
   946     Q_D(const QGLFramebufferObject);
       
   947     return d->size;
       
   948 }
       
   949 
       
   950 /*!
       
   951     Returns the format of this framebuffer object.
       
   952 */
       
   953 QGLFramebufferObjectFormat QGLFramebufferObject::format() const
       
   954 {
       
   955     Q_D(const QGLFramebufferObject);
       
   956     return d->format;
       
   957 }
       
   958 
       
   959 /*!
       
   960     \fn QImage QGLFramebufferObject::toImage() const
       
   961 
       
   962     Returns the contents of this framebuffer object as a QImage.
       
   963 */
       
   964 QImage QGLFramebufferObject::toImage() const
       
   965 {
       
   966     Q_D(const QGLFramebufferObject);
       
   967     if (!d->valid)
       
   968         return QImage();
       
   969 
       
   970     // qt_gl_read_framebuffer doesn't work on a multisample FBO
       
   971     if (format().samples() != 0) {
       
   972         QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat());
       
   973 
       
   974         QRect rect(QPoint(0, 0), size());
       
   975         blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect);
       
   976 
       
   977         return temp.toImage();
       
   978     }
       
   979 
       
   980     bool wasBound = isBound();
       
   981     if (!wasBound)
       
   982         const_cast<QGLFramebufferObject *>(this)->bind();
       
   983     QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true);
       
   984     if (!wasBound)
       
   985         const_cast<QGLFramebufferObject *>(this)->release();
       
   986 
       
   987     return image;
       
   988 }
       
   989 
       
   990 #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
       
   991 Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine)
       
   992 #endif
       
   993 
       
   994 #ifndef QT_OPENGL_ES_2
       
   995 Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine)
       
   996 #endif
       
   997 
       
   998 /*! \reimp */
       
   999 QPaintEngine *QGLFramebufferObject::paintEngine() const
       
  1000 {
       
  1001     Q_D(const QGLFramebufferObject);
       
  1002     if (d->engine)
       
  1003         return d->engine;
       
  1004 
       
  1005 #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
       
  1006 #if !defined (QT_OPENGL_ES_2)
       
  1007     if (qt_gl_preferGL2Engine()) {
       
  1008 #endif
       
  1009         QPaintEngine *engine = qt_buffer_2_engine();
       
  1010         if (engine->isActive() && engine->paintDevice() != this) {
       
  1011             d->engine = new QGL2PaintEngineEx;
       
  1012             return d->engine;
       
  1013         }
       
  1014         return engine;
       
  1015 #if !defined (QT_OPENGL_ES_2)
       
  1016     }
       
  1017 #endif
       
  1018 #endif
       
  1019 
       
  1020 #if !defined(QT_OPENGL_ES_2)
       
  1021     QPaintEngine *engine = qt_buffer_engine();
       
  1022     if (engine->isActive() && engine->paintDevice() != this) {
       
  1023         d->engine = new QOpenGLPaintEngine;
       
  1024         return d->engine;
       
  1025     }
       
  1026     return engine;
       
  1027 #endif
       
  1028 }
       
  1029 
       
  1030 /*!
       
  1031     \fn bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
       
  1032 
       
  1033     Returns true if the OpenGL \c{GL_EXT_framebuffer_object} extension
       
  1034     is present on this system; otherwise returns false.
       
  1035 */
       
  1036 bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
       
  1037 {
       
  1038     return (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
       
  1039 }
       
  1040 
       
  1041 /*!
       
  1042     \since 4.4
       
  1043 
       
  1044     Draws the given texture, \a textureId, to the given target rectangle,
       
  1045     \a target, in OpenGL model space. The \a textureTarget should be a 2D
       
  1046     texture target.
       
  1047 
       
  1048     The framebuffer object should be bound when calling this function.
       
  1049 
       
  1050     Equivalent to the corresponding QGLContext::drawTexture().
       
  1051 */
       
  1052 void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
       
  1053 {
       
  1054     const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
       
  1055 }
       
  1056 
       
  1057 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
  1058 /*! \internal */
       
  1059 void QGLFramebufferObject::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
       
  1060 {
       
  1061     const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
       
  1062 }
       
  1063 #endif
       
  1064 
       
  1065 /*!
       
  1066     \since 4.4
       
  1067 
       
  1068     Draws the given texture, \a textureId, at the given \a point in OpenGL
       
  1069     model space. The \a textureTarget should be a 2D texture target.
       
  1070 
       
  1071     The framebuffer object should be bound when calling this function.
       
  1072 
       
  1073     Equivalent to the corresponding QGLContext::drawTexture().
       
  1074 */
       
  1075 void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
       
  1076 {
       
  1077     const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
       
  1078 }
       
  1079 
       
  1080 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
       
  1081 /*! \internal */
       
  1082 void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
       
  1083 {
       
  1084     const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
       
  1085 }
       
  1086 #endif
       
  1087 
       
  1088 extern int qt_defaultDpiX();
       
  1089 extern int qt_defaultDpiY();
       
  1090 
       
  1091 /*! \reimp */
       
  1092 int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
       
  1093 {
       
  1094     Q_D(const QGLFramebufferObject);
       
  1095 
       
  1096     float dpmx = qt_defaultDpiX()*100./2.54;
       
  1097     float dpmy = qt_defaultDpiY()*100./2.54;
       
  1098     int w = d->size.width();
       
  1099     int h = d->size.height();
       
  1100     switch (metric) {
       
  1101     case PdmWidth:
       
  1102         return w;
       
  1103 
       
  1104     case PdmHeight:
       
  1105         return h;
       
  1106 
       
  1107     case PdmWidthMM:
       
  1108         return qRound(w * 1000 / dpmx);
       
  1109 
       
  1110     case PdmHeightMM:
       
  1111         return qRound(h * 1000 / dpmy);
       
  1112 
       
  1113     case PdmNumColors:
       
  1114         return 0;
       
  1115 
       
  1116     case PdmDepth:
       
  1117         return 32;//d->depth;
       
  1118 
       
  1119     case PdmDpiX:
       
  1120         return qRound(dpmx * 0.0254);
       
  1121 
       
  1122     case PdmDpiY:
       
  1123         return qRound(dpmy * 0.0254);
       
  1124 
       
  1125     case PdmPhysicalDpiX:
       
  1126         return qRound(dpmx * 0.0254);
       
  1127 
       
  1128     case PdmPhysicalDpiY:
       
  1129         return qRound(dpmy * 0.0254);
       
  1130 
       
  1131     default:
       
  1132         qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric);
       
  1133         break;
       
  1134     }
       
  1135     return 0;
       
  1136 }
       
  1137 
       
  1138 /*!
       
  1139     \fn GLuint QGLFramebufferObject::handle() const
       
  1140 
       
  1141     Returns the GL framebuffer object handle for this framebuffer
       
  1142     object (returned by the \c{glGenFrameBuffersEXT()} function). This
       
  1143     handle can be used to attach new images or buffers to the
       
  1144     framebuffer. The user is responsible for cleaning up and
       
  1145     destroying these objects.
       
  1146 */
       
  1147 GLuint QGLFramebufferObject::handle() const
       
  1148 {
       
  1149     Q_D(const QGLFramebufferObject);
       
  1150     return d->fbo();
       
  1151 }
       
  1152 
       
  1153 /*! \fn int QGLFramebufferObject::devType() const
       
  1154     \internal
       
  1155 */
       
  1156 
       
  1157 
       
  1158 /*!
       
  1159     Returns the status of the depth and stencil buffers attached to
       
  1160     this framebuffer object.
       
  1161 */
       
  1162 
       
  1163 QGLFramebufferObject::Attachment QGLFramebufferObject::attachment() const
       
  1164 {
       
  1165     Q_D(const QGLFramebufferObject);
       
  1166     if (d->valid)
       
  1167         return d->fbo_attachment;
       
  1168     return NoAttachment;
       
  1169 }
       
  1170 
       
  1171 /*!
       
  1172     \since 4.5
       
  1173 
       
  1174     Returns true if the framebuffer object is currently bound to a context,
       
  1175     otherwise false is returned.
       
  1176 */
       
  1177 
       
  1178 bool QGLFramebufferObject::isBound() const
       
  1179 {
       
  1180     Q_D(const QGLFramebufferObject);
       
  1181     const QGLContext *current = QGLContext::currentContext();
       
  1182     return current ? current->d_ptr->current_fbo == d->fbo() : false;
       
  1183 }
       
  1184 
       
  1185 /*!
       
  1186     \fn bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
       
  1187 
       
  1188     \since 4.6
       
  1189 
       
  1190     Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension
       
  1191     is present on this system; otherwise returns false.
       
  1192 
       
  1193     \sa blitFramebuffer()
       
  1194 */
       
  1195 bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
       
  1196 {
       
  1197     return (QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit);
       
  1198 }
       
  1199 
       
  1200 /*!
       
  1201     \since 4.6
       
  1202 
       
  1203     Blits from the \a sourceRect rectangle in the \a source framebuffer
       
  1204     object to the \a targetRect rectangle in the \a target framebuffer object.
       
  1205 
       
  1206     If \a source or \a target is 0, the default framebuffer will be used
       
  1207     instead of a framebuffer object as source or target respectively.
       
  1208 
       
  1209     The \a buffers parameter should be a mask consisting of any combination of
       
  1210     \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and
       
  1211     \c GL_STENCIL_BUFFER_BIT.  Any buffer type that is not present both
       
  1212     in the source and target buffers is ignored.
       
  1213 
       
  1214     The \a sourceRect and \a targetRect rectangles may have different sizes;
       
  1215     in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or
       
  1216     \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to
       
  1217     \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest
       
  1218     interpolation should be used when scaling is performed.
       
  1219 
       
  1220     If \a source equals \a target a copy is performed within the same buffer.
       
  1221     Results are undefined if the source and target rectangles overlap and
       
  1222     have different sizes. The sizes must also be the same if any of the
       
  1223     framebuffer objects are multisample framebuffers.
       
  1224 
       
  1225     Note that the scissor test will restrict the blit area if enabled.
       
  1226 
       
  1227     This function will have no effect unless hasOpenGLFramebufferBlit() returns
       
  1228     true.
       
  1229 
       
  1230     \sa hasOpenGLFramebufferBlit()
       
  1231 */
       
  1232 void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect,
       
  1233                                            QGLFramebufferObject *source, const QRect &sourceRect,
       
  1234                                            GLbitfield buffers,
       
  1235                                            GLenum filter)
       
  1236 {
       
  1237     if (!(QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit))
       
  1238         return;
       
  1239 
       
  1240     const QGLContext *ctx = QGLContext::currentContext();
       
  1241     if (!ctx)
       
  1242         return;
       
  1243 
       
  1244     const int height = ctx->device()->height();
       
  1245 
       
  1246     const int sh = source ? source->height() : height;
       
  1247     const int th = target ? target->height() : height;
       
  1248 
       
  1249     const int sx0 = sourceRect.left();
       
  1250     const int sx1 = sourceRect.left() + sourceRect.width();
       
  1251     const int sy0 = sh - (sourceRect.top() + sourceRect.height());
       
  1252     const int sy1 = sh - sourceRect.top();
       
  1253 
       
  1254     const int tx0 = targetRect.left();
       
  1255     const int tx1 = targetRect.left() + targetRect.width();
       
  1256     const int ty0 = th - (targetRect.top() + targetRect.height());
       
  1257     const int ty1 = th - targetRect.top();
       
  1258 
       
  1259     glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, source ? source->handle() : 0);
       
  1260     glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, target ? target->handle() : 0);
       
  1261 
       
  1262     glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
       
  1263                          tx0, ty0, tx1, ty1,
       
  1264                          buffers, filter);
       
  1265 
       
  1266     glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
       
  1267 }
       
  1268 
       
  1269 QT_END_NAMESPACE