Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/opengl/qglframebufferobject.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information ([email protected])
     4** All rights reserved.
     5** Contact: Nokia Corporation ([email protected])
    56**
    67** This file is part of the QtOpenGL module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     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.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you
     37** @nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    4141
    4242#include "qglframebufferobject.h"
     43
    4344
    4445#include <qdebug.h>
    4546#include <private/qgl_p.h>
     47
     48
     49
     50
     51
    4652#include <private/qpaintengine_opengl_p.h>
     53
     54
    4755#include <qglframebufferobject.h>
    4856#include <qlibrary.h>
    4957#include <qimage.h>
    5058
     59
     60
     61
     62
    5163QT_BEGIN_NAMESPACE
    5264
    5365extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
    5466
    55 #define QGL_FUNC_CONTEXT QGLContext *ctx = d_ptr->ctx;
    56 
     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}
    5775#define QT_CHECK_GLERROR()                                \
    5876{                                                         \
     
    6381    }                                                     \
    6482}
    65 
    66 class QGLFramebufferObjectPrivate
    67 {
    68 public:
    69     QGLFramebufferObjectPrivate() : depth_stencil_buffer(0), valid(false), bound(false), ctx(0) {}
    70     ~QGLFramebufferObjectPrivate() {}
    71 
    72     void init(const QSize& sz, QGLFramebufferObject::Attachment attachment,
    73               GLenum internal_format, GLenum texture_target);
    74     bool checkFramebufferStatus() const;
    75     GLuint texture;
    76     GLuint fbo;
    77     GLuint depth_stencil_buffer;
    78     GLenum target;
    79     QSize size;
    80     uint valid : 1;
    81     uint bound : 1;
    82     QGLFramebufferObject::Attachment fbo_attachment;
    83     QGLContext *ctx; // for Windows extension ptrs
    84 };
     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*/
     116void 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
     138QGLFramebufferObjectFormat::QGLFramebufferObjectFormat()
     139{
     140    d = new QGLFramebufferObjectFormatPrivate;
     141}
     142
     143/*!
     144    Constructs a copy of \a other.
     145*/
     146
     147QGLFramebufferObjectFormat::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
     157QGLFramebufferObjectFormat &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*/
     171QGLFramebufferObjectFormat::~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*/
     190void 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*/
     203int 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*/
     213void 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*/
     225QGLFramebufferObject::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*/
     236void 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*/
     249GLenum 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*/
     261void 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*/
     275GLenum QGLFramebufferObjectFormat::internalTextureFormat() const
     276{
     277    return d->internal_format;
     278}
     279
     280#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
     281/*! \internal */
     282void QGLFramebufferObjectFormat::setTextureTarget(QMacCompatGLenum target)
     283{
     284    detach();
     285    d->target = target;
     286}
     287
     288/*! \internal */
     289void 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*/
     300bool 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*/
     312bool QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& other) const
     313{
     314    return !(*this == other);
     315}
     316
     317void 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
     334QGLContext *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}
    85344
    86345bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
    87346{
    88     GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
     347    QGL_FUNCP_CONTEXT;
     348    if (!ctx)
     349        return false;   // Context no longer exists.
     350    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
    89351    switch(status) {
    90352    case GL_NO_ERROR:
     
    118380        qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer.");
    119381        break;
     382
     383
     384
    120385    default:
    121386        qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status;
     
    125390}
    126391
    127 void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::Attachment attachment,
    128                                        GLenum texture_target, GLenum internal_format)
    129 {
    130     ctx = const_cast<QGLContext *>(QGLContext::currentContext());
     392void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
     393                                       QGLFramebufferObject::Attachment attachment,
     394                                       GLenum texture_target, GLenum internal_format, GLint samples)
     395{
     396    QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
     397    fbo_guard.setContext(ctx);
     398
    131399    bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
    132400    if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
     
    137405    // texture dimensions
    138406
    139     while (glGetError() != GL_NO_ERROR) {} // reset error state
    140     glGenFramebuffersEXT(1, &fbo);
    141     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
     407    QT_RESET_GLERROR(); // reset error state
     408    GLuint fbo = 0;
     409    glGenFramebuffers(1, &fbo);
     410    glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
     411    fbo_guard.setId(fbo);
     412
     413    glDevice.setFBO(q, attachment);
    142414
    143415    QT_CHECK_GLERROR();
    144416    // init texture
    145     glGenTextures(1, &texture);
    146     glBindTexture(target, texture);
    147     glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
    148                  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
     417    if (samples == 0) {
     418        glGenTextures(1, &texture);
     419        glBindTexture(target, texture);
     420        glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
     421                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    149422#ifndef QT_OPENGL_ES
    150     glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    151     glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    152     glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    153     glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     423    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     424    glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     425    glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     426    glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    154427#else
    155     glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    156     glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    157     glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    158     glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    159 #endif
    160     glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
    161                               target, texture, 0);
    162 
    163     QT_CHECK_GLERROR();
    164     valid = checkFramebufferStatus();
     428        glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     429        glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     430        glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     431        glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     432#endif
     433        glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
     434                target, texture, 0);
     435
     436        QT_CHECK_GLERROR();
     437        valid = checkFramebufferStatus();
     438        glBindTexture(target, 0);
     439
     440        color_buffer = 0;
     441    } else {
     442        GLint maxSamples;
     443        glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
     444
     445        samples = qBound(1, int(samples), int(maxSamples));
     446
     447        glGenRenderbuffers(1, &color_buffer);
     448        glBindRenderbuffer(GL_RENDERBUFFER_EXT, color_buffer);
     449        if (glRenderbufferStorageMultisampleEXT) {
     450            glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
     451                internal_format, size.width(), size.height());
     452        } else {
     453            samples = 0;
     454            glRenderbufferStorage(GL_RENDERBUFFER_EXT, internal_format,
     455                size.width(), size.height());
     456        }
     457
     458        glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
     459                                     GL_RENDERBUFFER_EXT, color_buffer);
     460
     461        QT_CHECK_GLERROR();
     462        valid = checkFramebufferStatus();
     463
     464        if (valid)
     465            glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &samples);
     466    }
    165467
    166468    if (attachment == QGLFramebufferObject::CombinedDepthStencil
    167469        && (QGLExtensions::glExtensions & QGLExtensions::PackedDepthStencil)) {
    168470        // depth and stencil buffer needs another extension
    169         glGenRenderbuffersEXT(1, &depth_stencil_buffer);
    170         Q_ASSERT(!glIsRenderbufferEXT(depth_stencil_buffer));
    171         glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
    172         Q_ASSERT(glIsRenderbufferEXT(depth_stencil_buffer));
    173         glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
     471        glGenRenderbuffers(1, &depth_stencil_buffer);
     472        Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
     473        glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
     474        Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
     475        if (samples != 0 && glRenderbufferStorageMultisampleEXT)
     476            glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
     477                GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
     478        else
     479            glRenderbufferStorage(GL_RENDERBUFFER_EXT,
     480                GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
     481
    174482        GLint i = 0;
    175         glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
    176         glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
     483        glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
     484        glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
    177485                                     GL_RENDERBUFFER_EXT, depth_stencil_buffer);
    178         glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
     486        glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
    179487                                     GL_RENDERBUFFER_EXT, depth_stencil_buffer);
    180488        fbo_attachment = QGLFramebufferObject::CombinedDepthStencil;
     489
    181490        valid = checkFramebufferStatus();
    182491        if (!valid)
    183             glDeleteRenderbuffersEXT(1, &depth_stencil_buffer);
     492            glDeleteRenderbuffers(1, &depth_stencil_buffer);
    184493    } else if (attachment == QGLFramebufferObject::Depth
    185494               || attachment == QGLFramebufferObject::CombinedDepthStencil)
    186495    {
    187         glGenRenderbuffersEXT(1, &depth_stencil_buffer);
    188         Q_ASSERT(!glIsRenderbufferEXT(depth_stencil_buffer));
    189         glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
    190         Q_ASSERT(glIsRenderbufferEXT(depth_stencil_buffer));
     496        glGenRenderbuffers(1, &depth_stencil_buffer);
     497        Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer));
     498        glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer);
     499        Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer));
     500        if (samples != 0 && glRenderbufferStorageMultisampleEXT) {
    191501#ifdef QT_OPENGL_ES
    192502#define GL_DEPTH_COMPONENT16 0x81A5
    193         glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height());
     503            glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
     504                GL_DEPTH_COMPONENT16, size.width(), size.height());
    194505#else
    195         glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height());
    196 #endif
     506            glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
     507                GL_DEPTH_COMPONENT, size.width(), size.height());
     508#endif
     509        } else {
     510#ifdef QT_OPENGL_ES
     511#define GL_DEPTH_COMPONENT16 0x81A5
     512            glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, size.width(), size.height());
     513#else
     514            glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height());
     515#endif
     516        }
    197517        GLint i = 0;
    198         glGetRenderbufferParameterivEXT(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
    199         glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
     518        glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i);
     519        glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
    200520                                     GL_RENDERBUFFER_EXT, depth_stencil_buffer);
    201521        fbo_attachment = QGLFramebufferObject::Depth;
    202522        valid = checkFramebufferStatus();
    203523        if (!valid)
    204             glDeleteRenderbuffersEXT(1, &depth_stencil_buffer);
     524            glDeleteRenderbuffers(1, &depth_stencil_buffer);
    205525    } else {
    206526        fbo_attachment = QGLFramebufferObject::NoAttachment;
    207527    }
    208528
    209     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
     529    glBindFramebuffer);
    210530    if (!valid) {
    211         glDeleteTextures(1, &texture);
    212         glDeleteFramebuffersEXT(1, &fbo);
     531        if (color_buffer)
     532            glDeleteRenderbuffers(1, &color_buffer);
     533        else
     534            glDeleteTextures(1, &texture);
     535        glDeleteFramebuffers(1, &fbo);
     536        fbo_guard.setId(0);
    213537    }
    214538    QT_CHECK_GLERROR();
     539
     540
     541
     542
     543
    215544}
    216545
     
    220549    \since 4.2
    221550
    222     \ingroup multimedia
     551    \ingroup
    223552
    224553    The QGLFramebufferObject class encapsulates an OpenGL framebuffer
     
    260589    \endlist
    261590
    262     Note that primitives drawn to a QGLFramebufferObject with QPainter
    263     will only be antialiased if the QPainter::HighQualityAntialiasing
    264     render hint is set. This is because there is currently no support
    265     for the \c{GL_EXT_framebuffer_multisample} extension, which is
    266     required to do multisample based antialiasing. Also note that the
    267     QPainter::HighQualityAntialiasing render hint requires the
    268     \c{GL_ARB_fragment_program} extension to work in OpenGL.
     591    When using a QPainter to paint to a QGLFramebufferObject you should take
     592    care that the QGLFramebufferObject is created with the CombinedDepthStencil
     593    attachment for QPainter to be able to render correctly.
     594    Note that you need to create a QGLFramebufferObject with more than one
     595    sample per pixel for primitives to be antialiased when drawing using a
     596    QPainter. To create a multisample framebuffer object you should use one of
     597    the constructors that take a QGLFramebufferObject parameter, and set the
     598    QGLFramebufferObject::samples() property to a non-zero value.
     599
     600    When painting to a QGLFramebufferObject using QPainter, the state of
     601    the current GL context will be altered by the paint engine to reflect
     602    its needs.  Applications should not rely upon the GL state being reset
     603    to its original conditions, particularly the current shader program,
     604    GL viewport, texture units, and drawing modes.
     605
     606    For multisample framebuffer objects a color render buffer is created,
     607    otherwise a texture with the specified texture target is created.
     608    The color render buffer or texture will have the specified internal
     609    format, and will be bound to the \c GL_COLOR_ATTACHMENT0
     610    attachment in the framebuffer object.
     611
     612    If you want to use a framebuffer object with multisampling enabled
     613    as a texture, you first need to copy from it to a regular framebuffer
     614    object using QGLContext::blitFramebuffer().
    269615
    270616    \sa {Framebuffer Object Example}
     
    308654    can be toggled using one of the overloaded constructors.
    309655
    310     The default internal texture format is \c GL_RGBA8.
     656    The default internal texture format is \c GL_RGBA8 for desktop
     657    OpenGL, and \c GL_RGBA for OpenGL/ES.
    311658
    312659    It is important that you have a current GL context set when
     
    317664*/
    318665
    319 #ifndef QT_OPENGL_ES
    320 #define DEFAULT_FORMAT GL_RGBA8
    321 #else
    322 #define DEFAULT_FORMAT GL_RGBA
    323 #endif
    324 
    325666QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
    326667    : d_ptr(new QGLFramebufferObjectPrivate)
    327668{
    328669    Q_D(QGLFramebufferObject);
    329     d->init(size, NoAttachment, target, DEFAULT_FORMAT);
     670    d->init(size, NoAttachment, target, DEFAULT_FORMAT);
    330671}
    331672
     
    336677{
    337678    Q_D(QGLFramebufferObject);
    338     d->init(size, NoAttachment, target, DEFAULT_FORMAT);
     679    d->init(size, NoAttachment, target, DEFAULT_FORMAT);
    339680}
    340681#endif
     
    351692{
    352693    Q_D(QGLFramebufferObject);
    353     d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
     694    d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
     695}
     696
     697/*! \overload
     698
     699    Constructs an OpenGL framebuffer object of the given \a size based on the
     700    supplied \a format.
     701*/
     702
     703QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format)
     704    : d_ptr(new QGLFramebufferObjectPrivate)
     705{
     706    Q_D(QGLFramebufferObject);
     707    d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
     708            format.samples());
     709}
     710
     711/*! \overload
     712
     713    Constructs an OpenGL framebuffer object of the given \a width and \a height
     714    based on the supplied \a format.
     715*/
     716
     717QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format)
     718    : d_ptr(new QGLFramebufferObjectPrivate)
     719{
     720    Q_D(QGLFramebufferObject);
     721    d->init(this, QSize(width, height), format.attachment(), format.textureTarget(),
     722            format.internalTextureFormat(), format.samples());
    354723}
    355724
     
    360729{
    361730    Q_D(QGLFramebufferObject);
    362     d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
     731    d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
    363732}
    364733#endif
     
    372741    configuration, \a target the texture target and \a internal_format
    373742    the internal texture format. The default texture target is \c
    374     GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8.
     743    GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
     744    for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
    375745
    376746    \sa size(), texture(), attachment()
     
    381751{
    382752    Q_D(QGLFramebufferObject);
    383     d->init(QSize(width, height), attachment, target, internal_format);
     753    d->init(QSize(width, height), attachment, target, internal_format);
    384754}
    385755
     
    391761{
    392762    Q_D(QGLFramebufferObject);
    393     d->init(QSize(width, height), attachment, target, internal_format);
     763    d->init(QSize(width, height), attachment, target, internal_format);
    394764}
    395765#endif
     
    403773    configuration, \a target the texture target and \a internal_format
    404774    the internal texture format. The default texture target is \c
    405     GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8.
     775    GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
     776    for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
    406777
    407778    \sa size(), texture(), attachment()
     
    412783{
    413784    Q_D(QGLFramebufferObject);
    414     d->init(size, attachment, target, internal_format);
     785    d->init(size, attachment, target, internal_format);
    415786}
    416787
     
    422793{
    423794    Q_D(QGLFramebufferObject);
    424     d->init(size, attachment, target, internal_format);
     795    d->init(size, attachment, target, internal_format);
    425796}
    426797#endif
     
    436807    QGL_FUNC_CONTEXT;
    437808
    438     if (isValid()
    439         && (d->ctx == QGLContext::currentContext()
    440             || qgl_share_reg()->checkSharing(d->ctx, QGLContext::currentContext())))
    441     {
    442         glDeleteTextures(1, &d->texture);
     809    delete d->engine;
     810
     811    if (isValid() && ctx) {
     812        QGLShareContextScope scope(ctx);
     813        if (d->texture)
     814            glDeleteTextures(1, &d->texture);
     815        if (d->color_buffer)
     816            glDeleteRenderbuffers(1, &d->color_buffer);
    443817        if (d->depth_stencil_buffer)
    444             glDeleteRenderbuffersEXT(1, &d->depth_stencil_buffer);
    445         glDeleteFramebuffersEXT(1, &d->fbo);
    446     }
    447     delete d_ptr;
     818            glDeleteRenderbuffers(1, &d->depth_stencil_buffer);
     819        );
     820   
     821   
    448822}
    449823
     
    455829    The framebuffer can become invalid if the initialization process
    456830    fails, the user attaches an invalid buffer to the framebuffer
    457     object, or a non-power of 2 width/height is specified as the
     831    object, or a non-power of width/height is specified as the
    458832    texture size if the texture target is \c{GL_TEXTURE_2D}.
     833
     834
     835
     836
     837
     838
     839
     840
    459841*/
    460842bool QGLFramebufferObject::isValid() const
    461843{
    462844    Q_D(const QGLFramebufferObject);
    463     return d->valid;
     845    return d->valid;
    464846}
    465847
     
    470852    framebuffer to this framebuffer object.
    471853    Returns true upon success, false otherwise.
     854
     855
    472856*/
    473857bool QGLFramebufferObject::bind()
     
    477861    Q_D(QGLFramebufferObject);
    478862    QGL_FUNC_CONTEXT;
    479     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, d->fbo);
    480     d->bound = d->valid = d->checkFramebufferStatus();
     863    if (!ctx)
     864        return false;   // Context no longer exists.
     865    const QGLContext *current = QGLContext::currentContext();
     866#ifdef QT_DEBUG
     867    if (!current ||
     868        QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
     869    {
     870        qWarning("QGLFramebufferObject::bind() called from incompatible context");
     871    }
     872#endif
     873    glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo());
     874    d->valid = d->checkFramebufferStatus();
     875    if (d->valid && current)
     876        current->d_ptr->current_fbo = d->fbo();
    481877    return d->valid;
    482878}
     
    488884    framebuffer.
    489885    Returns true upon success, false otherwise.
     886
     887
    490888*/
    491889bool QGLFramebufferObject::release()
     
    493891    if (!isValid())
    494892        return false;
    495     Q_D(QGLFramebufferObject);
    496893    QGL_FUNC_CONTEXT;
    497     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
    498     d->valid = d->checkFramebufferStatus();
    499     d->bound = false;
    500     return d->valid;
     894    if (!ctx)
     895        return false;   // Context no longer exists.
     896
     897    const QGLContext *current = QGLContext::currentContext();
     898
     899#ifdef QT_DEBUG
     900    if (!current ||
     901        QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
     902    {
     903        qWarning("QGLFramebufferObject::release() called from incompatible context");
     904    }
     905#endif
     906
     907    if (current) {
     908        current->d_ptr->current_fbo = current->d_ptr->default_fbo;
     909        glBindFramebuffer(GL_FRAMEBUFFER_EXT, current->d_ptr->default_fbo);
     910    }
     911
     912    return true;
    501913}
    502914
     
    507919    rendering target in this framebuffer object. This texture id can
    508920    be bound as a normal texture in your own GL code.
     921
     922
     923
    509924*/
    510925GLuint QGLFramebufferObject::texture() const
     
    524939    Q_D(const QGLFramebufferObject);
    525940    return d->size;
     941
     942
     943
     944
     945
     946
     947
     948
     949
    526950}
    527951
     
    537961        return QImage();
    538962
    539     const_cast<QGLFramebufferObject *>(this)->bind();
    540     QImage image = qt_gl_read_framebuffer(d->size, d->ctx->format().alpha(), true);
    541     const_cast<QGLFramebufferObject *>(this)->release();
     963    // qt_gl_read_framebuffer doesn't work on a multisample FBO
     964    if (format().samples() != 0) {
     965        QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat());
     966
     967        QRect rect(QPoint(0, 0), size());
     968        blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect);
     969
     970        return temp.toImage();
     971    }
     972
     973    bool wasBound = isBound();
     974    if (!wasBound)
     975        const_cast<QGLFramebufferObject *>(this)->bind();
     976    QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true);
     977    if (!wasBound)
     978        const_cast<QGLFramebufferObject *>(this)->release();
    542979
    543980    return image;
    544981}
    545982
    546 #if !defined(QT_OPENGL_ES_2)
    547 Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_paintengine)
     983#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
     984Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine)
     985#endif
     986
     987#ifndef QT_OPENGL_ES_2
     988Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine)
    548989#endif
    549990
     
    551992QPaintEngine *QGLFramebufferObject::paintEngine() const
    552993{
     994
     995
     996
     997
     998
     999
     1000
     1001
     1002
     1003
     1004
     1005
     1006
     1007
     1008
     1009
     1010
     1011
     1012
    5531013#if !defined(QT_OPENGL_ES_2)
    554     return qt_buffer_paintengine();
    555 #else
    556     return 0;
     1014    QPaintEngine *engine = qt_buffer_engine();
     1015    if (engine->isActive() && engine->paintDevice() != this) {
     1016        d->engine = new QOpenGLPaintEngine;
     1017        return d->engine;
     1018    }
     1019    return engine;
    5571020#endif
    5581021}
     
    5661029bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
    5671030{
    568     QGLWidget dmy; // needed to detect and init the QGLExtensions object
     1031    QGL
    5691032    return (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
    5701033}
     
    5831046void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
    5841047{
    585     Q_D(QGLFramebufferObject);
    586     d->ctx->drawTexture(target, textureId, textureTarget);
     1048    const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
    5871049}
    5881050
     
    5911053void QGLFramebufferObject::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
    5921054{
    593     Q_D(QGLFramebufferObject);
    594     d->ctx->drawTexture(target, textureId, textureTarget);
     1055    const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
    5951056}
    5961057#endif
     
    6081069void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
    6091070{
    610     Q_D(QGLFramebufferObject);
    611     d->ctx->drawTexture(point, textureId, textureTarget);
     1071    const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
    6121072}
    6131073
     
    6161076void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
    6171077{
    618     Q_D(QGLFramebufferObject);
    619     d->ctx->drawTexture(point, textureId, textureTarget);
    620 }
    621 #endif
    622 
    623 extern int qt_defaultDpi();
     1078    t);
     1079}
     1080#endif
     1081
     1082extern int qt_defaultDpiX();
     1083extern int qt_defaultDpi();
    6241084
    6251085/*! \reimp */
     
    6281088    Q_D(const QGLFramebufferObject);
    6291089
    630     float dpmx = qt_defaultDpi()*100./2.54;
    631     float dpmy = qt_defaultDpi()*100./2.54;
     1090    float dpmx = qt_defaultDpi()*100./2.54;
     1091    float dpmy = qt_defaultDpi()*100./2.54;
    6321092    int w = d->size.width();
    6331093    int h = d->size.height();
     
    6521112
    6531113    case PdmDpiX:
    654         return (int)(dpmx * 0.0254);
     1114        return (dpmx * 0.0254);
    6551115
    6561116    case PdmDpiY:
    657         return (int)(dpmy * 0.0254);
     1117        return (dpmy * 0.0254);
    6581118
    6591119    case PdmPhysicalDpiX:
    660         return (int)(dpmx * 0.0254);
     1120        return (dpmx * 0.0254);
    6611121
    6621122    case PdmPhysicalDpiY:
    663         return (int)(dpmy * 0.0254);
     1123        return (dpmy * 0.0254);
    6641124
    6651125    default:
     
    6821142{
    6831143    Q_D(const QGLFramebufferObject);
    684     return d->fbo;
     1144    return d->fbo;
    6851145}
    6861146
    6871147/*! \fn int QGLFramebufferObject::devType() const
    688 
    689     \reimp
     1148    \internal
    6901149*/
    6911150
     
    7141173{
    7151174    Q_D(const QGLFramebufferObject);
    716     return d->bound;
     1175    const QGLContext *current = QGLContext::currentContext();
     1176    return current ? current->d_ptr->current_fbo == d->fbo() : false;
     1177}
     1178
     1179/*!
     1180    \fn bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
     1181
     1182    \since 4.6
     1183
     1184    Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension
     1185    is present on this system; otherwise returns false.
     1186
     1187    \sa blitFramebuffer()
     1188*/
     1189bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
     1190{
     1191    QGLExtensions::init();
     1192    return (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit);
     1193}
     1194
     1195/*!
     1196    \since 4.6
     1197
     1198    Blits from the \a sourceRect rectangle in the \a source framebuffer
     1199    object to the \a targetRect rectangle in the \a target framebuffer object.
     1200
     1201    If \a source or \a target is 0, the default framebuffer will be used
     1202    instead of a framebuffer object as source or target respectively.
     1203
     1204    The \a buffers parameter should be a mask consisting of any combination of
     1205    \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and
     1206    \c GL_STENCIL_BUFFER_BIT.  Any buffer type that is not present both
     1207    in the source and target buffers is ignored.
     1208
     1209    The \a sourceRect and \a targetRect rectangles may have different sizes;
     1210    in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or
     1211    \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to
     1212    \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest
     1213    interpolation should be used when scaling is performed.
     1214
     1215    If \a source equals \a target a copy is performed within the same buffer.
     1216    Results are undefined if the source and target rectangles overlap and
     1217    have different sizes. The sizes must also be the same if any of the
     1218    framebuffer objects are multisample framebuffers.
     1219
     1220    Note that the scissor test will restrict the blit area if enabled.
     1221
     1222    This function will have no effect unless hasOpenGLFramebufferBlit() returns
     1223    true.
     1224
     1225    \sa hasOpenGLFramebufferBlit()
     1226*/
     1227void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect,
     1228                                           QGLFramebufferObject *source, const QRect &sourceRect,
     1229                                           GLbitfield buffers,
     1230                                           GLenum filter)
     1231{
     1232    if (!(QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit))
     1233        return;
     1234
     1235    const QGLContext *ctx = QGLContext::currentContext();
     1236    if (!ctx)
     1237        return;
     1238
     1239    const int height = ctx->device()->height();
     1240
     1241    const int sh = source ? source->height() : height;
     1242    const int th = target ? target->height() : height;
     1243
     1244    const int sx0 = sourceRect.left();
     1245    const int sx1 = sourceRect.left() + sourceRect.width();
     1246    const int sy0 = sh - (sourceRect.top() + sourceRect.height());
     1247    const int sy1 = sh - sourceRect.top();
     1248
     1249    const int tx0 = targetRect.left();
     1250    const int tx1 = targetRect.left() + targetRect.width();
     1251    const int ty0 = th - (targetRect.top() + targetRect.height());
     1252    const int ty1 = th - targetRect.top();
     1253
     1254    glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, source ? source->handle() : 0);
     1255    glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, target ? target->handle() : 0);
     1256
     1257    glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
     1258                         tx0, ty0, tx1, ty1,
     1259                         buffers, filter);
     1260
     1261    glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
    7171262}
    7181263
Note: See TracChangeset for help on using the changeset viewer.