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/qpixmapdata_gl.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    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 have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    4141
    4242#include "qpixmap.h"
     43#include "qglframebufferobject.h"
    4344
    4445#include <private/qpaintengine_raster_p.h>
     
    4849#include <private/qgl_p.h>
    4950#include <private/qdrawhelper_p.h>
     51#include <private/qimage_p.h>
     52
     53#include <private/qpaintengineex_opengl2_p.h>
     54
     55#include <qdesktopwidget.h>
     56#include <qfile.h>
     57#include <qimagereader.h>
    5058
    5159QT_BEGIN_NAMESPACE
     
    5361extern QGLWidget* qt_gl_share_widget();
    5462
    55 class QGLShareContextScope
    56 {
    57 public:
    58     QGLShareContextScope(const QGLContext *ctx)
    59         : m_oldContext(0)
    60         , m_ctx(const_cast<QGLContext *>(ctx))
    61     {
    62         const QGLContext *currentContext = QGLContext::currentContext();
    63         if (currentContext != ctx && !qgl_share_reg()->checkSharing(ctx, currentContext)) {
    64             m_oldContext = const_cast<QGLContext *>(currentContext);
    65             m_ctx->makeCurrent();
    66         }
    67     }
    68 
    69     operator QGLContext *()
    70     {
    71         return m_ctx;
    72     }
    73 
    74     QGLContext *operator->()
    75     {
    76         return m_ctx;
    77     }
    78 
    79     ~QGLShareContextScope()
    80     {
    81         if (m_oldContext)
    82             m_oldContext->makeCurrent();
    83     }
    84 
    85 private:
    86     QGLContext *m_oldContext;
    87     QGLContext *m_ctx;
    88 };
    89 
    90 void qt_gl_convertFromGLImage(QImage *img)
    91 {
    92     const int w = img->width();
    93     const int h = img->height();
    94 
    95     if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
    96         uint *p = (uint*)img->bits();
    97         uint *end = p + w*h;
    98 
    99         while (p < end) {
    100             uint a = *p << 24;
    101             *p = (*p >> 8) | a;
    102             p++;
    103         }
    104 
    105         *img = img->mirrored();
    106     } else {
    107         // mirror image
    108         uint *data = (uint *)img->bits();
    109 
    110         const int mid = h/2;
    111 
    112         for (int y = 0; y < mid; ++y) {
    113             uint *p = data + y * w;
    114             uint *end = p + w;
    115             uint *q = data + (h - y - 1) * w;
    116 
    117             while (p < end)
    118                 qSwap(*p++, *q++);
    119         }
    120     }
    121 }
    122 
     63/*!
     64    \class QGLFramebufferObjectPool
     65    \since 4.6
     66
     67    \brief The QGLFramebufferObject class provides a pool of framebuffer
     68    objects for offscreen rendering purposes.
     69
     70    When requesting an FBO of a given size and format, an FBO of the same
     71    format and a size at least as big as the requested size will be returned.
     72
     73    \internal
     74*/
     75
     76static inline int areaDiff(const QSize &size, const QGLFramebufferObject *fbo)
     77{
     78    return qAbs(size.width() * size.height() - fbo->width() * fbo->height());
     79}
     80
     81extern int qt_next_power_of_two(int v);
     82
     83static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz)
     84{
     85#ifdef QT_OPENGL_ES_2
     86    QSize rounded(qt_next_power_of_two(sz.width()), qt_next_power_of_two(sz.height()));
     87    if (rounded.width() * rounded.height() < 1.20 * sz.width() * sz.height())
     88        return rounded;
     89#endif
     90    return sz;
     91}
     92
     93
     94QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize)
     95{
     96    QGLFramebufferObject *chosen = 0;
     97    QGLFramebufferObject *candidate = 0;
     98    for (int i = 0; !chosen && i < m_fbos.size(); ++i) {
     99        QGLFramebufferObject *fbo = m_fbos.at(i);
     100
     101        if (strictSize) {
     102            if (fbo->size() == requestSize && fbo->format() == requestFormat) {
     103                chosen = fbo;
     104                break;
     105            } else {
     106                continue;
     107            }
     108        }
     109
     110        if (fbo->format() == requestFormat) {
     111            // choose the fbo with a matching format and the closest size
     112            if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo))
     113                candidate = fbo;
     114        }
     115
     116        if (candidate) {
     117            m_fbos.removeOne(candidate);
     118
     119            const QSize fboSize = candidate->size();
     120            QSize sz = fboSize;
     121
     122            if (sz.width() < requestSize.width())
     123                sz.setWidth(qMax(requestSize.width(), qRound(sz.width() * 1.5)));
     124            if (sz.height() < requestSize.height())
     125                sz.setHeight(qMax(requestSize.height(), qRound(sz.height() * 1.5)));
     126
     127            // wasting too much space?
     128            if (sz.width() * sz.height() > requestSize.width() * requestSize.height() * 4)
     129                sz = requestSize;
     130
     131            if (sz != fboSize) {
     132                delete candidate;
     133                candidate = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(sz), requestFormat);
     134            }
     135
     136            chosen = candidate;
     137        }
     138    }
     139
     140    if (!chosen) {
     141        if (strictSize)
     142            chosen = new QGLFramebufferObject(requestSize, requestFormat);
     143        else
     144            chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat);
     145    }
     146
     147    if (!chosen->isValid()) {
     148        delete chosen;
     149        chosen = 0;
     150    }
     151
     152    return chosen;
     153}
     154
     155void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo)
     156{
     157    if (fbo)
     158        m_fbos << fbo;
     159}
     160
     161
     162QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const
     163{
     164    return data->paintEngine();
     165}
     166
     167void QGLPixmapGLPaintDevice::beginPaint()
     168{
     169    if (!data->isValid())
     170        return;
     171
     172    // QGLPaintDevice::beginPaint will store the current binding and replace
     173    // it with m_thisFBO:
     174    m_thisFBO = data->m_renderFbo->handle();
     175    QGLPaintDevice::beginPaint();
     176
     177    Q_ASSERT(data->paintEngine()->type() == QPaintEngine::OpenGL2);
     178
     179    // QPixmap::fill() is deferred until now, where we actually need to do the fill:
     180    if (data->needsFill()) {
     181        const QColor &c = data->fillColor();
     182        float alpha = c.alphaF();
     183        glDisable(GL_SCISSOR_TEST);
     184        glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
     185        glClear(GL_COLOR_BUFFER_BIT);
     186    }
     187    else if (!data->isUninitialized()) {
     188        // If the pixmap (GL Texture) has valid content (it has been
     189        // uploaded from an image or rendered into before), we need to
     190        // copy it from the texture to the render FBO.
     191
     192        glDisable(GL_DEPTH_TEST);
     193        glDisable(GL_SCISSOR_TEST);
     194        glDisable(GL_BLEND);
     195
     196#if !defined(QT_OPENGL_ES_2)
     197        glMatrixMode(GL_MODELVIEW);
     198        glLoadIdentity();
     199
     200        glMatrixMode(GL_PROJECTION);
     201        glLoadIdentity();
     202        glOrtho(0, data->width(), data->height(), 0, -999999, 999999);
     203#endif
     204
     205        glViewport(0, 0, data->width(), data->height());
     206
     207        // Pass false to bind so it doesn't copy the FBO into the texture!
     208        context()->drawTexture(QRect(0, 0, data->width(), data->height()), data->bind(false));
     209    }
     210}
     211
     212void QGLPixmapGLPaintDevice::endPaint()
     213{
     214    if (!data->isValid())
     215        return;
     216
     217    data->copyBackFromRenderFbo(false);
     218
     219    // Base's endPaint will restore the previous FBO binding
     220    QGLPaintDevice::endPaint();
     221
     222    qgl_fbo_pool()->release(data->m_renderFbo);
     223    data->m_renderFbo = 0;
     224}
     225
     226QGLContext* QGLPixmapGLPaintDevice::context() const
     227{
     228    data->ensureCreated();
     229    return data->m_ctx;
     230}
     231
     232QSize QGLPixmapGLPaintDevice::size() const
     233{
     234    return data->size();
     235}
     236
     237void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d)
     238{
     239    data = d;
     240}
    123241
    124242static int qt_gl_pixmap_serial = 0;
     
    126244QGLPixmapData::QGLPixmapData(PixelType type)
    127245    : QPixmapData(type, OpenGLClass)
    128     , m_width(0)
    129     , m_height(0)
    130     , m_texture(0)
     246    , m_renderFbo(0)
     247    , m_engine(0)
     248    , m_ctx(0)
    131249    , m_dirty(false)
     250    , m_hasFillColor(false)
     251    , m_hasAlpha(false)
    132252{
    133253    setSerialNumber(++qt_gl_pixmap_serial);
     254    m_glDevice.setPixmapData(this);
    134255}
    135256
    136257QGLPixmapData::~QGLPixmapData()
    137258{
    138     if (m_texture && qt_gl_share_widget()) {
     259    QGLWidget *shareWidget = qt_gl_share_widget();
     260    if (!shareWidget)
     261        return;
     262
     263    delete m_engine;
     264
     265    if (m_texture.id) {
     266        QGLShareContextScope ctx(shareWidget->context());
     267        glDeleteTextures(1, &m_texture.id);
     268    }
     269}
     270
     271QPixmapData *QGLPixmapData::createCompatiblePixmapData() const
     272{
     273    return new QGLPixmapData(pixelType());
     274}
     275
     276bool QGLPixmapData::isValid() const
     277{
     278    return w > 0 && h > 0;
     279}
     280
     281bool QGLPixmapData::isValidContext(const QGLContext *ctx) const
     282{
     283    if (ctx == m_ctx)
     284        return true;
     285
     286    const QGLContext *share_ctx = qt_gl_share_widget()->context();
     287    return ctx == share_ctx || QGLContext::areSharing(ctx, share_ctx);
     288}
     289
     290void QGLPixmapData::resize(int width, int height)
     291{
     292    if (width == w && height == h)
     293        return;
     294
     295    if (width <= 0 || height <= 0) {
     296        width = 0;
     297        height = 0;
     298    }
     299
     300    w = width;
     301    h = height;
     302    is_null = (w <= 0 || h <= 0);
     303    d = pixelType() == QPixmapData::PixmapType ? 32 : 1;
     304
     305    if (m_texture.id) {
    139306        QGLShareContextScope ctx(qt_gl_share_widget()->context());
    140         glDeleteTextures(1, &m_texture);
    141     }
    142 }
    143 
    144 bool QGLPixmapData::isValid() const
    145 {
    146     return m_width > 0 && m_height > 0;
    147 }
    148 
    149 bool QGLPixmapData::isValidContext(const QGLContext *ctx) const
    150 {
    151     const QGLContext *share_ctx = qt_gl_share_widget()->context();
    152     return ctx == share_ctx || qgl_share_reg()->checkSharing(ctx, share_ctx);
    153 }
    154 
    155 void QGLPixmapData::resize(int width, int height)
    156 {
    157     if (width == m_width && height == m_height)
    158         return;
    159 
    160     m_width = width;
    161     m_height = height;
     307        glDeleteTextures(1, &m_texture.id);
     308        m_texture.id = 0;
     309    }
    162310
    163311    m_source = QImage();
     
    174322
    175323    QGLShareContextScope ctx(qt_gl_share_widget()->context());
    176 
    177     const GLenum format = qt_gl_preferredTextureFormat();
    178     const GLenum target = qt_gl_preferredTextureTarget();
    179 
    180     if (!m_texture)
    181         glGenTextures(1, &m_texture);
    182 
    183     glBindTexture(target, m_texture);
    184 
    185     if (m_source.isNull()) {
    186         glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, format, GL_UNSIGNED_BYTE, 0);
    187     } else {
    188         const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, format);
    189 
    190         glBindTexture(target, m_texture);
    191         glTexImage2D(target, 0, GL_RGBA, m_width, m_height, 0, format,
    192                 GL_UNSIGNED_BYTE, tx.bits());
    193 
    194         m_source = QImage();
    195     }
     324    m_ctx = ctx;
     325
     326    const GLenum internal_format = m_hasAlpha ? GL_RGBA : GL_RGB;
     327#ifdef QT_OPENGL_ES_2
     328    const GLenum external_format = internal_format;
     329#else
     330    const GLenum external_format = qt_gl_preferredTextureFormat();
     331#endif
     332    const GLenum target = GL_TEXTURE_2D;
     333
     334    if (!m_texture.id) {
     335        glGenTextures(1, &m_texture.id);
     336        glBindTexture(target, m_texture.id);
     337        glTexImage2D(target, 0, internal_format, w, h, 0, external_format, GL_UNSIGNED_BYTE, 0);
     338        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     339        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     340    }
     341
     342    if (!m_source.isNull()) {
     343        if (external_format == GL_RGB) {
     344            const QImage tx = m_source.convertToFormat(QImage::Format_RGB888);
     345
     346            glBindTexture(target, m_texture.id);
     347            glTexSubImage2D(target, 0, 0, 0, w, h, external_format,
     348                            GL_UNSIGNED_BYTE, tx.bits());
     349        } else {
     350            const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, external_format);
     351
     352            glBindTexture(target, m_texture.id);
     353            glTexSubImage2D(target, 0, 0, 0, w, h, external_format,
     354                            GL_UNSIGNED_BYTE, tx.bits());
     355        }
     356
     357        if (useFramebufferObjects())
     358            m_source = QImage();
     359    }
     360
     361    m_texture.options &= ~QGLContext::MemoryManagedBindOption;
    196362}
    197363
    198364void QGLPixmapData::fromImage(const QImage &image,
    199                               Qt::ImageConversionFlags)
    200 {
    201     if (image.size() == QSize(m_width, m_height))
     365                              Qt::ImageConversionFlags /*flags*/)
     366{
     367    if (image.size() == QSize(w, h))
    202368        setSerialNumber(++qt_gl_pixmap_serial);
    203369    resize(image.width(), image.height());
    204     m_source = image;
     370
     371    if (pixelType() == BitmapType) {
     372        m_source = image.convertToFormat(QImage::Format_MonoLSB);
     373
     374    } else {
     375        QImage::Format format = QImage::Format_RGB32;
     376        if (qApp->desktop()->depth() == 16)
     377            format = QImage::Format_RGB16;
     378
     379        if (image.hasAlphaChannel() && const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels())
     380            format = QImage::Format_ARGB32_Premultiplied;;
     381
     382        m_source = image.convertToFormat(format);
     383    }
     384
    205385    m_dirty = true;
     386    m_hasFillColor = false;
     387
     388    m_hasAlpha = m_source.hasAlphaChannel();
     389    w = image.width();
     390    h = image.height();
     391    is_null = (w <= 0 || h <= 0);
     392    d = m_source.depth();
     393
     394    if (m_texture.id) {
     395        QGLShareContextScope ctx(qt_gl_share_widget()->context());
     396        glDeleteTextures(1, &m_texture.id);
     397        m_texture.id = 0;
     398    }
     399}
     400
     401bool QGLPixmapData::fromFile(const QString &filename, const char *format,
     402                             Qt::ImageConversionFlags flags)
     403{
     404    if (pixelType() == QPixmapData::BitmapType)
     405        return QPixmapData::fromFile(filename, format, flags);
     406    QFile file(filename);
     407    if (!file.open(QIODevice::ReadOnly))
     408        return false;
     409    QByteArray data = file.peek(64);
     410    bool alpha;
     411    if (m_texture.canBindCompressedTexture
     412            (data.constData(), data.size(), format, &alpha)) {
     413        resize(0, 0);
     414        data = file.readAll();
     415        file.close();
     416        QGLShareContextScope ctx(qt_gl_share_widget()->context());
     417        QSize size = m_texture.bindCompressedTexture
     418            (data.constData(), data.size(), format);
     419        if (!size.isEmpty()) {
     420            w = size.width();
     421            h = size.height();
     422            is_null = false;
     423            d = 32;
     424            m_hasAlpha = alpha;
     425            m_source = QImage();
     426            m_dirty = isValid();
     427            return true;
     428        }
     429        return false;
     430    }
     431    fromImage(QImageReader(&file, format).read(), flags);
     432    return !isNull();
     433}
     434
     435bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format,
     436                             Qt::ImageConversionFlags flags)
     437{
     438    bool alpha;
     439    const char *buf = reinterpret_cast<const char *>(buffer);
     440    if (m_texture.canBindCompressedTexture(buf, int(len), format, &alpha)) {
     441        resize(0, 0);
     442        QGLShareContextScope ctx(qt_gl_share_widget()->context());
     443        QSize size = m_texture.bindCompressedTexture(buf, int(len), format);
     444        if (!size.isEmpty()) {
     445            w = size.width();
     446            h = size.height();
     447            is_null = false;
     448            d = 32;
     449            m_hasAlpha = alpha;
     450            m_source = QImage();
     451            m_dirty = isValid();
     452            return true;
     453        }
     454    }
     455    return QPixmapData::fromData(buffer, len, format, flags);
     456}
     457
     458bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect)
     459{
     460    Q_UNUSED(dx);
     461    Q_UNUSED(dy);
     462    Q_UNUSED(rect);
     463    return false;
     464}
     465
     466void QGLPixmapData::copy(const QPixmapData *data, const QRect &rect)
     467{
     468    if (data->classId() != QPixmapData::OpenGLClass) {
     469        QPixmapData::copy(data, rect);
     470        return;
     471    }
     472
     473    // can be optimized to do a framebuffer blit or similar ...
     474    QPixmapData::copy(data, rect);
    206475}
    207476
     
    211480        return;
    212481
    213     if (!m_source.isNull()) {
    214         m_source.fill(PREMUL(color.rgba()));
     482    bool hasAlpha = color.alpha() != 255;
     483    if (hasAlpha && !m_hasAlpha) {
     484        if (m_texture.id) {
     485            glDeleteTextures(1, &m_texture.id);
     486            m_texture.id = 0;
     487            m_dirty = true;
     488        }
     489        m_hasAlpha = color.alpha() != 255;
     490    }
     491
     492    if (useFramebufferObjects()) {
     493        m_source = QImage();
     494        m_hasFillColor = true;
     495        m_fillColor = color;
    215496    } else {
    216         // ## TODO: improve performance here
    217         QImage img(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
     497
     498        if (m_source.isNull()) {
     499            m_fillColor = color;
     500            m_hasFillColor = true;
     501
     502        } else if (m_source.depth() == 32) {
     503            m_source.fill(PREMUL(color.rgba()));
     504
     505        } else if (m_source.depth() == 1) {
     506            if (color == Qt::color1)
     507                m_source.fill(1);
     508            else
     509                m_source.fill(0);
     510        }
     511    }
     512}
     513
     514bool QGLPixmapData::hasAlphaChannel() const
     515{
     516    return m_hasAlpha;
     517}
     518
     519QImage QGLPixmapData::fillImage(const QColor &color) const
     520{
     521    QImage img;
     522    if (pixelType() == BitmapType) {
     523        img = QImage(w, h, QImage::Format_MonoLSB);
     524
     525        img.setColorCount(2);
     526        img.setColor(0, QColor(Qt::color0).rgba());
     527        img.setColor(1, QColor(Qt::color1).rgba());
     528
     529        if (color == Qt::color1)
     530            img.fill(1);
     531        else
     532            img.fill(0);
     533    } else {
     534        img = QImage(w, h,
     535                m_hasAlpha
     536                ? QImage::Format_ARGB32_Premultiplied
     537                : QImage::Format_RGB32);
    218538        img.fill(PREMUL(color.rgba()));
    219 
    220         fromImage(img, 0);
    221     }
    222 }
    223 
    224 bool QGLPixmapData::hasAlphaChannel() const
    225 {
    226     return true;
    227 }
     539    }
     540    return img;
     541}
     542
     543extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha);
    228544
    229545QImage QGLPixmapData::toImage() const
     
    232548        return QImage();
    233549
    234     if (!m_source.isNull())
     550    if (m_renderFbo) {
     551        copyBackFromRenderFbo(true);
     552    } else if (!m_source.isNull()) {
    235553        return m_source;
    236     else if (m_dirty)
    237         return QImage(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
     554    } else if (m_dirty || m_hasFillColor) {
     555        return fillImage(m_fillColor);
     556    } else {
     557        ensureCreated();
     558    }
     559
     560    QGLShareContextScope ctx(qt_gl_share_widget()->context());
     561    glBindTexture(GL_TEXTURE_2D, m_texture.id);
     562    return qt_gl_read_texture(QSize(w, h), true, true);
     563}
     564
     565struct TextureBuffer
     566{
     567    QGLFramebufferObject *fbo;
     568    QGL2PaintEngineEx *engine;
     569};
     570
     571Q_GLOBAL_STATIC(QGLFramebufferObjectPool, _qgl_fbo_pool)
     572QGLFramebufferObjectPool* qgl_fbo_pool()
     573{
     574    return _qgl_fbo_pool();
     575}
     576
     577void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
     578{
     579    if (!isValid())
     580        return;
     581
     582    m_hasFillColor = false;
     583
     584    const QGLContext *share_ctx = qt_gl_share_widget()->context();
     585    QGLShareContextScope ctx(share_ctx);
    238586
    239587    ensureCreated();
    240588
    241     QGLShareContextScope ctx(qt_gl_share_widget()->context());
    242     QImage img(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
    243 
    244     GLenum format = qt_gl_preferredTextureFormat();
    245     GLenum target = qt_gl_preferredTextureTarget();
    246 
    247     glBindTexture(target, m_texture);
    248 #ifndef QT_OPENGL_ES
    249     glGetTexImage(target, 0, format, GL_UNSIGNED_BYTE, img.bits());
    250 #else
    251     // XXX - cannot download textures this way on OpenGL/ES.
    252 #endif
    253 
    254     qt_gl_convertFromGLImage(&img);
    255 
    256     return img;
     589    if (!ctx->d_ptr->fbo)
     590        glGenFramebuffers(1, &ctx->d_ptr->fbo);
     591
     592    glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo);
     593    glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
     594        GL_TEXTURE_2D, m_texture.id, 0);
     595
     596    const int x0 = 0;
     597    const int x1 = w;
     598    const int y0 = 0;
     599    const int y1 = h;
     600
     601    if (!m_renderFbo->isBound())
     602        glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_renderFbo->handle());
     603
     604    glDisable(GL_SCISSOR_TEST);
     605
     606    glBlitFramebufferEXT(x0, y0, x1, y1,
     607            x0, y0, x1, y1,
     608            GL_COLOR_BUFFER_BIT,
     609            GL_NEAREST);
     610
     611    if (keepCurrentFboBound) {
     612        glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
     613    } else {
     614        glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_renderFbo->handle());
     615        ctx->d_ptr->current_fbo = m_renderFbo->handle();
     616    }
     617}
     618
     619bool QGLPixmapData::useFramebufferObjects()
     620{
     621    return QGLFramebufferObject::hasOpenGLFramebufferObjects()
     622           && QGLFramebufferObject::hasOpenGLFramebufferBlit()
     623           && qt_gl_preferGL2Engine();
    257624}
    258625
     
    262629        return 0;
    263630
    264     m_source = toImage();
     631    if (m_renderFbo)
     632        return m_engine;
     633
     634    if (useFramebufferObjects()) {
     635        extern QGLWidget* qt_gl_share_widget();
     636
     637        if (!QGLContext::currentContext())
     638            qt_gl_share_widget()->makeCurrent();
     639        QGLShareContextScope ctx(qt_gl_share_widget()->context());
     640
     641        QGLFramebufferObjectFormat format;
     642        format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
     643        format.setSamples(4);
     644        format.setInternalTextureFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB));
     645
     646        m_renderFbo = qgl_fbo_pool()->acquire(size(), format);
     647
     648        if (m_renderFbo) {
     649            if (!m_engine)
     650                m_engine = new QGL2PaintEngineEx;
     651            return m_engine;
     652        }
     653
     654        qWarning() << "Failed to create pixmap texture buffer of size " << size() << ", falling back to raster paint engine";
     655    }
     656
    265657    m_dirty = true;
    266 
     658    if (m_source.size() != size())
     659        m_source = QImage(size(), QImage::Format_ARGB32_Premultiplied);
     660    if (m_hasFillColor) {
     661        m_source.fill(PREMUL(m_fillColor.rgba()));
     662        m_hasFillColor = false;
     663    }
    267664    return m_source.paintEngine();
    268665}
    269666
    270 GLuint QGLPixmapData::bind() const
    271 {
    272     ensureCreated();
    273     glBindTexture(qt_gl_preferredTextureTarget(), m_texture);
    274     return m_texture;
    275 }
    276 
    277 GLuint QGLPixmapData::textureId() const
    278 {
    279     ensureCreated();
    280     return m_texture;
     667extern QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format);
     668
     669// If copyBack is true, bind will copy the contents of the render
     670// FBO to the texture (which is not bound to the texture, as it's
     671// a multisample FBO).
     672GLuint QGLPixmapData::bind(bool copyBack) const
     673{
     674    if (m_renderFbo && copyBack) {
     675        copyBackFromRenderFbo(true);
     676    } else {
     677        ensureCreated();
     678    }
     679
     680    GLuint id = m_texture.id;
     681    glBindTexture(GL_TEXTURE_2D, id);
     682
     683    if (m_hasFillColor) {
     684        if (!useFramebufferObjects()) {
     685            m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
     686            m_source.fill(PREMUL(m_fillColor.rgba()));
     687        }
     688
     689        m_hasFillColor = false;
     690
     691        GLenum format = qt_gl_preferredTextureFormat();
     692        QImage tx(w, h, QImage::Format_ARGB32_Premultiplied);
     693        tx.fill(qt_gl_convertToGLFormat(m_fillColor.rgba(), format));
     694        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.bits());
     695    }
     696
     697    return id;
     698}
     699
     700QGLTexture* QGLPixmapData::texture() const
     701{
     702    return &m_texture;
    281703}
    282704
     
    286708int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
    287709{
     710    if (w == 0)
     711        return 0;
     712
    288713    switch (metric) {
    289714    case QPaintDevice::PdmWidth:
    290         return m_width;
     715        return w;
    291716    case QPaintDevice::PdmHeight:
    292         return m_height;
     717        return h;
    293718    case QPaintDevice::PdmNumColors:
    294719        return 0;
    295720    case QPaintDevice::PdmDepth:
    296         return pixelType() == QPixmapData::PixmapType ? 32 : 1;
     721        return d;
    297722    case QPaintDevice::PdmWidthMM:
    298         return qRound(m_width * 25.4 / qt_defaultDpiX());
     723        return qRound(w * 25.4 / qt_defaultDpiX());
    299724    case QPaintDevice::PdmHeightMM:
    300         return qRound(m_height * 25.4 / qt_defaultDpiY());
     725        return qRound(h * 25.4 / qt_defaultDpiY());
    301726    case QPaintDevice::PdmDpiX:
    302727    case QPaintDevice::PdmPhysicalDpiX:
     
    311736}
    312737
     738QGLPaintDevice *QGLPixmapData::glDevice() const
     739{
     740    return &m_glDevice;
     741}
     742
    313743QT_END_NAMESPACE
Note: See TracChangeset for help on using the changeset viewer.