Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6565// #define QT_OPENGL_CACHE_AS_VBOS
    6666
     67#include "qglgradientcache_p.h"
    6768#include "qpaintengineex_opengl2_p.h"
    6869
     
    7879#include <private/qpixmapdata_gl_p.h>
    7980#include <private/qdatabuffer_p.h>
    80 
    81 #include "qglgradientcache_p.h"
     81#include <private/qstatictext_p.h>
     82#include <private/qtriangulator_p.h>
     83
    8284#include "qglengineshadermanager_p.h"
    8385#include "qgl2pexvertexarray_p.h"
     
    8991QT_BEGIN_NAMESPACE
    9092
    91 //#define QT_GL_NO_SCISSOR_TEST
     93#if defined(Q_OS_SYMBIAN)
     94#define QT_GL_NO_SCISSOR_TEST
     95#endif
     96
    9297#if defined(Q_WS_WIN)
    9398extern Q_GUI_EXPORT bool qt_cleartype_enabled;
    9499#endif
    95100
    96 extern QImage qt_imageForBrush(int brushStyle, bool invert);
     101#ifdef Q_WS_MAC
     102extern bool qt_applefontsmoothing_enabled;
     103#endif
     104
     105Q_DECL_IMPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
    97106
    98107////////////////////////////////// Private Methods //////////////////////////////////////////
     
    107116        e->data = 0;
    108117        e->engine = 0;
     118    }
     119
     120    if (elementIndicesVBOId != 0) {
     121        glDeleteBuffers(1, &elementIndicesVBOId);
     122        elementIndicesVBOId = 0;
    109123    }
    110124}
     
    150164
    151165    currentBrush = brush;
     166    if (!currentBrushPixmap.isNull())
     167        currentBrushPixmap = QPixmap();
    152168    brushUniformsDirty = true; // All brushes have at least one uniform
    153169
     
    208224    }
    209225    else if (style == Qt::TexturePattern) {
    210         const QPixmap& texPixmap = currentBrush.texture();
     226        currentBrushPixmap = currentBrush.texture();
     227
     228        int max_texture_size = ctx->d_func()->maxTextureSize();
     229        if (currentBrushPixmap.width() > max_texture_size || currentBrushPixmap.height() > max_texture_size)
     230            currentBrushPixmap = currentBrushPixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio);
    211231
    212232        glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
    213         QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
     233        QGLTexture *tex = ctx->d_func()->bindTexture(currentBrushPixmap, GL_TEXTURE_2D, GL_RGBA,
     234                                                     QGLContext::InternalBindOption |
     235                                                     QGLContext::CanFlipNativePixmapBindOption);
    214236        updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
    215237        textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1;
     
    366388        dy = ceilf(dy - 0.5f);
    367389    }
    368 
     390#ifndef Q_OS_SYMBIAN
    369391    if (addOffset) {
    370392        dx += 0.49f;
    371393        dy += 0.49f;
    372394    }
    373 
     395#endif
    374396    pmvMatrix[0][0] = (wfactor * transform.m11())  - transform.m13();
    375397    pmvMatrix[1][0] = (wfactor * transform.m21())  - transform.m23();
     
    389411
    390412    matrixDirty = false;
     413    matrixUniformDirty = true;
    391414
    392415    // Set the PMV matrix attribute. As we use an attributes rather than uniforms, we only
     
    507530    d->transferMode(BrushDrawingMode);
    508531
     532    d->nativePaintingActive = true;
     533
    509534    QGLContext *ctx = d->ctx;
    510535    glUseProgram(0);
     
    522547    float mv_matrix[4][4] =
    523548    {
    524         { mtx.m11(), mtx.m12(),     0, mtx.m13() },
    525         { mtx.m21(), mtx.m22(),     0, mtx.m23() },
    526         {         0,         0,     1,         0 },
    527         {  mtx.dx(),  mtx.dy(),     0, mtx.m33() }
     549        { float(mtx.m11()), float(mtx.m12()),     0, float(mtx.m13()) },
     550        { float(mtx.m21()), float(mtx.m22()),     0, float(mtx.m23()) },
     551        {                0,                0,     1,                0 },
     552        {  float(mtx.dx()),  float(mtx.dy()),     0, float(mtx.m33()) }
    528553    };
    529554
     
    562587    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    563588    glStencilFunc(GL_ALWAYS, 0, 0xff);
    564     glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
    565     glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
    566     glDisableVertexAttribArray(QT_OPACITY_ATTR);
     589    ctx->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false);
     590    ctx->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, false);
     591    ctx->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
    567592#ifndef QT_OPENGL_ES_2
    568593    glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // color may have been changed by glVertexAttrib()
     
    574599    Q_D(QGL2PaintEngineEx);
    575600    d->needsSync = true;
     601    d->nativePaintingActive = false;
     602}
     603
     604void QGL2PaintEngineEx::invalidateState()
     605{
     606    Q_D(QGL2PaintEngineEx);
     607    d->needsSync = true;
     608}
     609
     610bool QGL2PaintEngineEx::isNativePaintingActive() const {
     611    Q_D(const QGL2PaintEngineEx);
     612    return d->nativePaintingActive;
    576613}
    577614
     
    586623
    587624    if (newMode == TextDrawingMode) {
    588         setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
    589         setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
     625        shaderManager->setHasComplexGeometry(true);
     626    } else {
     627        shaderManager->setHasComplexGeometry(false);
    590628    }
    591629
     
    612650#ifdef QT_OPENGL_CACHE_AS_VBOS
    613651    GLuint vbo;
     652    GLuint ibo;
    614653#else
    615654    float *vertices;
     655    void *indices;
    616656#endif
    617657    int vertexCount;
     658    int indexCount;
    618659    GLenum primitiveType;
    619660    qreal iscale;
     
    626667    Q_ASSERT(engine->type() == QPaintEngine::OpenGL2);
    627668    static_cast<QGL2PaintEngineEx *>(engine)->d_func()->unusedVBOSToClean << c->vbo;
     669    if (c->ibo)
     670        d->unusedIBOSToClean << c->ibo;
    628671#else
    629672    Q_UNUSED(engine);
    630673    qFree(c->vertices);
     674    qFree(c->indices);
    631675#endif
    632676    delete c;
     
    669713            QVectorPath::CacheEntry *data = path.lookupCacheData(q);
    670714            QGL2PEVectorPathCache *cache;
     715
     716            bool updateCache = false;
    671717
    672718            if (data) {
     
    679725                        glDeleteBuffers(1, &cache->vbo);
    680726                        cache->vbo = 0;
     727                        Q_ASSERT(cache->ibo == 0);
    681728#else
    682729                        qFree(cache->vertices);
    683 #endif
    684                         cache->vertexCount = 0;
     730                        Q_ASSERT(cache->indices == 0);
     731#endif
     732                        updateCache = true;
    685733                    }
    686734                }
    687735            } else {
    688736                cache = new QGL2PEVectorPathCache;
    689                 cache->vertexCount = 0;
    690737                data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath);
     738                updateCache = true;
    691739            }
    692740
    693741            // Flatten the path at the current scale factor and fill it into the cache struct.
    694             if (!cache->vertexCount) {
     742            if (updateCache) {
    695743                vertexCoordinateArray.clear();
    696744                vertexCoordinateArray.addPath(path, inverseScale, false);
     
    698746                int floatSizeInBytes = vertexCount * 2 * sizeof(float);
    699747                cache->vertexCount = vertexCount;
     748                cache->indexCount = 0;
    700749                cache->primitiveType = GL_TRIANGLE_FAN;
    701750                cache->iscale = inverseScale;
     
    704753                glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
    705754                glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW);
     755                cache->ibo = 0;
    706756#else
    707757                cache->vertices = (float *) qMalloc(floatSizeInBytes);
    708758                memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
     759                cache->indices = 0;
    709760#endif
    710761            }
     
    722773      //        printf(" - Marking path as cachable...\n");
    723774            // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable
    724             // ### Remove before release...
    725             static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty();
    726             if (do_vectorpath_cache)
    727                 path.makeCacheable();
     775            path.makeCacheable();
    728776            vertexCoordinateArray.clear();
    729777            vertexCoordinateArray.addPath(path, inverseScale, false);
     
    733781
    734782    } else {
    735         // The path is too complicated & needs the stencil technique
    736         vertexCoordinateArray.clear();
    737         vertexCoordinateArray.addPath(path, inverseScale, false);
    738 
    739         fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
    740 
    741         glStencilMask(0xff);
    742         glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
    743 
    744         if (q->state()->clipTestEnabled) {
    745             // Pass when high bit is set, replace stencil value with current clip
    746             glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT);
    747         } else if (path.hasWindingFill()) {
    748             // Pass when any bit is set, replace stencil value with 0
    749             glStencilFunc(GL_NOTEQUAL, 0, 0xff);
     783        bool useCache = path.isCacheable();
     784        if (useCache) {
     785            QRectF bbox = path.controlPointRect();
     786            // If the path doesn't fit within these limits, it is possible that the triangulation will fail.
     787            useCache &= (bbox.left() > -0x8000 * inverseScale)
     788                     && (bbox.right() < 0x8000 * inverseScale)
     789                     && (bbox.top() > -0x8000 * inverseScale)
     790                     && (bbox.bottom() < 0x8000 * inverseScale);
     791        }
     792
     793        if (useCache) {
     794            QVectorPath::CacheEntry *data = path.lookupCacheData(q);
     795            QGL2PEVectorPathCache *cache;
     796
     797            bool updateCache = false;
     798
     799            if (data) {
     800                cache = (QGL2PEVectorPathCache *) data->data;
     801                // Check if scale factor is exceeded for curved paths and generate curves if so...
     802                if (path.isCurved()) {
     803                    qreal scaleFactor = cache->iscale / inverseScale;
     804                    if (scaleFactor < 0.5 || scaleFactor > 2.0) {
     805#ifdef QT_OPENGL_CACHE_AS_VBOS
     806                        glDeleteBuffers(1, &cache->vbo);
     807                        glDeleteBuffers(1, &cache->ibo);
     808#else
     809                        qFree(cache->vertices);
     810                        qFree(cache->indices);
     811#endif
     812                        updateCache = true;
     813                    }
     814                }
     815            } else {
     816                cache = new QGL2PEVectorPathCache;
     817                data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath);
     818                updateCache = true;
     819            }
     820
     821            // Flatten the path at the current scale factor and fill it into the cache struct.
     822            if (updateCache) {
     823                QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale));
     824                cache->vertexCount = polys.vertices.size() / 2;
     825                cache->indexCount = polys.indices.size();
     826                cache->primitiveType = GL_TRIANGLES;
     827                cache->iscale = inverseScale;
     828#ifdef QT_OPENGL_CACHE_AS_VBOS
     829                glGenBuffers(1, &cache->vbo);
     830                glGenBuffers(1, &cache->ibo);
     831                glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
     832                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo);
     833
     834                if (QGLExtensions::glExtensions() & QGLExtensions::ElementIndexUint)
     835                    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quint32) * polys.indices.size(), polys.indices.data(), GL_STATIC_DRAW);
     836                else
     837                    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quint16) * polys.indices.size(), polys.indices.data(), GL_STATIC_DRAW);
     838
     839                QVarLengthArray<float> vertices(polys.vertices.size());
     840                for (int i = 0; i < polys.vertices.size(); ++i)
     841                    vertices[i] = float(inverseScale * polys.vertices.at(i));
     842                glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
     843#else
     844                cache->vertices = (float *) qMalloc(sizeof(float) * polys.vertices.size());
     845                if (QGLExtensions::glExtensions() & QGLExtensions::ElementIndexUint) {
     846                    cache->indices = (quint32 *) qMalloc(sizeof(quint32) * polys.indices.size());
     847                    memcpy(cache->indices, polys.indices.data(), sizeof(quint32) * polys.indices.size());
     848                } else {
     849                    cache->indices = (quint16 *) qMalloc(sizeof(quint16) * polys.indices.size());
     850                    memcpy(cache->indices, polys.indices.data(), sizeof(quint16) * polys.indices.size());
     851                }
     852                for (int i = 0; i < polys.vertices.size(); ++i)
     853                    cache->vertices[i] = float(inverseScale * polys.vertices.at(i));
     854#endif
     855            }
     856
     857            prepareForDraw(currentBrush.isOpaque());
     858#ifdef QT_OPENGL_CACHE_AS_VBOS
     859            glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
     860            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo);
     861            setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0);
     862            if (QGLExtensions::glExtensions() & QGLExtensions::ElementIndexUint)
     863                glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0);
     864            else
     865                glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, 0);
     866            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
     867            glBindBuffer(GL_ARRAY_BUFFER, 0);
     868#else
     869            setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices);
     870            if (QGLExtensions::glExtensions() & QGLExtensions::ElementIndexUint)
     871                glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, (qint32 *)cache->indices);
     872            else
     873                glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, (qint16 *)cache->indices);
     874#endif
     875
    750876        } else {
    751             // Pass when high bit is set, replace stencil value with 0
    752             glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
    753         }
    754         prepareForDraw(currentBrush.isOpaque());
    755 
    756         // Stencil the brush onto the dest buffer
    757         composite(vertexCoordinateArray.boundingRect());
    758         glStencilMask(0);
    759         updateClipScissorTest();
     877      //        printf(" - Marking path as cachable...\n");
     878            // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable
     879            path.makeCacheable();
     880
     881            // The path is too complicated & needs the stencil technique
     882            vertexCoordinateArray.clear();
     883            vertexCoordinateArray.addPath(path, inverseScale, false);
     884
     885            fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
     886
     887            glStencilMask(0xff);
     888            glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
     889
     890            if (q->state()->clipTestEnabled) {
     891                // Pass when high bit is set, replace stencil value with current clip
     892                glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT);
     893            } else if (path.hasWindingFill()) {
     894                // Pass when any bit is set, replace stencil value with 0
     895                glStencilFunc(GL_NOTEQUAL, 0, 0xff);
     896            } else {
     897                // Pass when high bit is set, replace stencil value with 0
     898                glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
     899            }
     900            prepareForDraw(currentBrush.isOpaque());
     901
     902            // Stencil the brush onto the dest buffer
     903            composite(vertexCoordinateArray.boundingRect());
     904            glStencilMask(0);
     905            updateClipScissorTest();
     906        }
    760907    }
    761908}
     
    9391086        brushUniformsDirty = true;
    9401087        opacityUniformDirty = true;
     1088        matrixUniformDirty = true;
    9411089    }
    9421090
     
    9471095        shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity);
    9481096        opacityUniformDirty = false;
     1097    }
     1098
     1099    if (matrixUniformDirty && shaderManager->hasComplexGeometry()) {
     1100        shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Matrix),
     1101                                                         pmvMatrix);
     1102        matrixUniformDirty = false;
    9491103    }
    9501104
     
    10011155}
    10021156
    1003 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
     1157extern Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
    10041158
    10051159
     
    10491203    updateMatrix();
    10501204
     1205    QRectF clip = q->state()->matrix.inverted().mapRect(q->state()->clipEnabled
     1206                                                        ? q->state()->rectangleClip
     1207                                                        : QRectF(0, 0, width, height));
     1208
    10511209    if (penStyle == Qt::SolidLine) {
    1052         stroker.process(path, pen);
     1210        stroker.process(path, pen, clip);
    10531211
    10541212    } else { // Some sort of dash
    1055         dasher.process(path, pen);
     1213        dasher.process(path, pen, clip);
    10561214
    10571215        QVectorPath dashStroke(dasher.points(),
    10581216                               dasher.elementCount(),
    10591217                               dasher.elementTypes());
    1060         stroker.process(dashStroke, pen);
    1061     }
     1218        stroker.process(dashStroke, pen, clip);
     1219    }
     1220
     1221    if (!stroker.vertexCount())
     1222        return;
    10621223
    10631224    if (opaque) {
     
    11511312
    11521313
     1314static const QRectF scaleRect(const QRectF &r, qreal sx, qreal sy)
     1315{
     1316    return QRectF(r.x() * sx, r.y() * sy, r.width() * sx, r.height() * sy);
     1317}
     1318
    11531319void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, const QRectF & src)
    11541320{
    11551321    Q_D(QGL2PaintEngineEx);
     1322    QGLContext *ctx = d->ctx;
     1323
     1324    int max_texture_size = ctx->d_func()->maxTextureSize();
     1325    if (pixmap.width() > max_texture_size || pixmap.height() > max_texture_size) {
     1326        QPixmap scaled = pixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio);
     1327
     1328        const qreal sx = scaled.width() / qreal(pixmap.width());
     1329        const qreal sy = scaled.height() / qreal(pixmap.height());
     1330
     1331        drawPixmap(dest, scaled, scaleRect(src, sx, sy));
     1332        return;
     1333    }
     1334
    11561335    ensureActive();
    11571336    d->transferMode(ImageDrawingMode);
    11581337
    1159     QGLContext *ctx = d->ctx;
    11601338    glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
    11611339    QGLTexture *texture =
     
    11691347
    11701348    bool isBitmap = pixmap.isQBitmap();
    1171     bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel();
     1349    bool isOpaque = !isBitmap && !pixmap.hasAlpha();
    11721350
    11731351    d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
     
    11801358{
    11811359    Q_D(QGL2PaintEngineEx);
     1360    QGLContext *ctx = d->ctx;
     1361
     1362    int max_texture_size = ctx->d_func()->maxTextureSize();
     1363    if (image.width() > max_texture_size || image.height() > max_texture_size) {
     1364        QImage scaled = image.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio);
     1365
     1366        const qreal sx = scaled.width() / qreal(image.width());
     1367        const qreal sy = scaled.height() / qreal(image.height());
     1368
     1369        drawImage(dest, scaled, scaleRect(src, sx, sy));
     1370        return;
     1371    }
     1372
    11821373    ensureActive();
    11831374    d->transferMode(ImageDrawingMode);
    11841375
    1185     QGLContext *ctx = d->ctx;
    11861376    glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
     1377
    11871378    QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
    11881379    GLuint id = texture->id;
     
    11931384}
    11941385
    1195 void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src)
     1386void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem)
    11961387{
    11971388    Q_D(QGL2PaintEngineEx);
     1389
     1390    ensureActive();
     1391
     1392    QFontEngineGlyphCache::Type glyphType = textItem->fontEngine()->glyphFormat >= 0
     1393                                            ? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat)
     1394                                            : d->glyphCacheType;
     1395    if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
     1396        if (d->device->alphaRequested() || state()->matrix.type() > QTransform::TxTranslate
     1397            || (state()->composition_mode != QPainter::CompositionMode_Source
     1398            && state()->composition_mode != QPainter::CompositionMode_SourceOver))
     1399        {
     1400            glyphType = QFontEngineGlyphCache::Raster_A8;
     1401        }
     1402    }
     1403
     1404    d->drawCachedGlyphs(glyphType, textItem);
     1405}
     1406
     1407bool QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src)
     1408{
     1409    Q_D(QGL2PaintEngineEx);
     1410    if (!d->shaderManager)
     1411        return false;
     1412
    11981413    ensureActive();
    11991414    d->transferMode(ImageDrawingMode);
     
    12101425                           state()->renderHints & QPainter::SmoothPixmapTransform, textureId);
    12111426    d->drawTexture(dest, srcRect, size, false);
     1427    return true;
    12121428}
    12131429
     
    12461462
    12471463    if (drawCached) {
    1248         d->drawCachedGlyphs(p, glyphType, ti);
     1464        QVarLengthArray<QFixedPoint> positions;
     1465        QVarLengthArray<glyph_t> glyphs;
     1466        QTransform matrix = QTransform::fromTranslate(p.x(), p.y());
     1467        ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
     1468
     1469        {
     1470            QStaticTextItem staticTextItem;
     1471            staticTextItem.chars = const_cast<QChar *>(ti.chars);
     1472            staticTextItem.setFontEngine(ti.fontEngine);
     1473            staticTextItem.glyphs = glyphs.data();
     1474            staticTextItem.numChars = ti.num_chars;
     1475            staticTextItem.numGlyphs = glyphs.size();
     1476            staticTextItem.glyphPositions = positions.data();
     1477
     1478            d->drawCachedGlyphs(glyphType, &staticTextItem);
     1479        }
    12491480        return;
    12501481    }
     
    12531484}
    12541485
    1255 void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType,
    1256                                                 const QTextItemInt &ti)
     1486namespace {
     1487
     1488    class QOpenGLStaticTextUserData: public QStaticTextUserData
     1489    {
     1490    public:
     1491        QOpenGLStaticTextUserData()
     1492            : QStaticTextUserData(OpenGLUserData), cacheSize(0, 0)
     1493        {
     1494        }
     1495
     1496        ~QOpenGLStaticTextUserData()
     1497        {
     1498        }
     1499
     1500        QSize cacheSize;
     1501        QGL2PEXVertexArray vertexCoordinateArray;
     1502        QGL2PEXVertexArray textureCoordinateArray;
     1503        QFontEngineGlyphCache::Type glyphType;
     1504    };
     1505
     1506}
     1507
     1508// #define QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO
     1509
     1510void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType,
     1511                                                QStaticTextItem *staticTextItem)
    12571512{
    12581513    Q_Q(QGL2PaintEngineEx);
    12591514
    1260     QVarLengthArray<QFixedPoint> positions;
    1261     QVarLengthArray<glyph_t> glyphs;
    1262     QTransform matrix = QTransform::fromTranslate(p.x(), p.y());
    1263     ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
     1515    QOpenGL2PaintEngineState *s = q->state();
     1516
     1517    bool recreateVertexArrays = false;
    12641518
    12651519    QGLTextureGlyphCache *cache =
    1266             (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform());
    1267 
     1520        (QGLTextureGlyphCache *) staticTextItem->fontEngine()->glyphCache(ctx, glyphType, QTransform());
    12681521    if (!cache || cache->cacheType() != glyphType) {
    12691522        cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform());
    1270         ti.fontEngine->setGlyphCache(ctx, cache);
    1271     }
    1272 
    1273     cache->setPaintEnginePrivate(this);
    1274     cache->populate(ti, glyphs, positions);
     1523        staticTextItem->fontEngine()->setGlyphCache(ctx, cache);
     1524        recreateVertexArrays = true;
     1525    } else if (cache->context() == 0) { // Old context has been destroyed, new context has same ptr value
     1526        cache->setContext(ctx);
     1527    }
     1528
     1529    if (staticTextItem->userDataNeedsUpdate) {
     1530        recreateVertexArrays = true;
     1531    } else if (staticTextItem->userData() == 0) {
     1532        recreateVertexArrays = true;
     1533    } else if (staticTextItem->userData()->type != QStaticTextUserData::OpenGLUserData) {
     1534        recreateVertexArrays = true;
     1535    } else {
     1536        QOpenGLStaticTextUserData *userData = static_cast<QOpenGLStaticTextUserData *>(staticTextItem->userData());
     1537        if (userData->glyphType != glyphType)
     1538            recreateVertexArrays = true;
     1539    }
     1540
     1541    // We only need to update the cache with new glyphs if we are actually going to recreate the vertex arrays.
     1542    // If the cache size has changed, we do need to regenerate the vertices, but we don't need to repopulate the
     1543    // cache so this text is performed before we test if the cache size has changed.
     1544    if (recreateVertexArrays) {
     1545        cache->setPaintEnginePrivate(this);
     1546        if (!cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs,
     1547                             staticTextItem->glyphs, staticTextItem->glyphPositions)) {
     1548            // No space in cache. We need to clear the cache and try again
     1549            cache->clear();
     1550            cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs,
     1551                            staticTextItem->glyphs, staticTextItem->glyphPositions);
     1552        }
     1553    }
    12751554
    12761555    if (cache->width() == 0 || cache->height() == 0)
     
    12841563    GLfloat dy = 1.0 / cache->height();
    12851564
    1286     vertexCoordinateArray.clear();
    1287     textureCoordinateArray.clear();
    1288 
    1289     for (int i=0; i<glyphs.size(); ++i) {
    1290         const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]);
    1291         int x = positions[i].x.toInt() + c.baseLineX - margin;
    1292         int y = positions[i].y.toInt() - c.baseLineY - margin;
    1293 
    1294         vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h));
    1295         textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
    1296     }
    1297 
    1298     setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
    1299     setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
     1565    // Use global arrays by default
     1566    QGL2PEXVertexArray *vertexCoordinates = &vertexCoordinateArray;
     1567    QGL2PEXVertexArray *textureCoordinates = &textureCoordinateArray;
     1568
     1569    if (staticTextItem->useBackendOptimizations) {
     1570        QOpenGLStaticTextUserData *userData = 0;
     1571
     1572        if (staticTextItem->userData() == 0
     1573            || staticTextItem->userData()->type != QStaticTextUserData::OpenGLUserData) {
     1574
     1575            userData = new QOpenGLStaticTextUserData();
     1576            staticTextItem->setUserData(userData);
     1577
     1578        } else {
     1579            userData = static_cast<QOpenGLStaticTextUserData*>(staticTextItem->userData());
     1580        }
     1581
     1582        userData->glyphType = glyphType;
     1583
     1584        // Use cache if backend optimizations is turned on
     1585        vertexCoordinates = &userData->vertexCoordinateArray;
     1586        textureCoordinates = &userData->textureCoordinateArray;
     1587
     1588        QSize size(cache->width(), cache->height());
     1589        if (userData->cacheSize != size) {
     1590            recreateVertexArrays = true;
     1591            userData->cacheSize = size;
     1592        }
     1593    }
     1594
     1595
     1596    if (recreateVertexArrays) {
     1597        vertexCoordinates->clear();
     1598        textureCoordinates->clear();
     1599
     1600        for (int i=0; i<staticTextItem->numGlyphs; ++i) {
     1601            const QTextureGlyphCache::Coord &c = cache->coords.value(staticTextItem->glyphs[i]);
     1602            int x = staticTextItem->glyphPositions[i].x.toInt() + c.baseLineX - margin;
     1603            int y = staticTextItem->glyphPositions[i].y.toInt() - c.baseLineY - margin;
     1604
     1605            vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h));
     1606            textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
     1607        }
     1608
     1609        staticTextItem->userDataNeedsUpdate = false;
     1610    }
     1611
     1612    if (elementIndices.size() < staticTextItem->numGlyphs*6) {
     1613        Q_ASSERT(elementIndices.size() % 6 == 0);
     1614        int j = elementIndices.size() / 6 * 4;
     1615        while (j < staticTextItem->numGlyphs*4) {
     1616            elementIndices.append(j + 0);
     1617            elementIndices.append(j + 0);
     1618            elementIndices.append(j + 1);
     1619            elementIndices.append(j + 2);
     1620            elementIndices.append(j + 3);
     1621            elementIndices.append(j + 3);
     1622
     1623            j += 4;
     1624        }
     1625
     1626#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
     1627        if (elementIndicesVBOId == 0)
     1628            glGenBuffers(1, &elementIndicesVBOId);
     1629
     1630        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId);
     1631        glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementIndices.size() * sizeof(GLushort),
     1632                     elementIndices.constData(), GL_STATIC_DRAW);
     1633#endif
     1634    } else {
     1635#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
     1636        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId);
     1637#endif
     1638    }
     1639
     1640    setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data());
     1641    setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data());
    13001642
    13011643    if (addOffset) {
     
    13631705            updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
    13641706
    1365             shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
    1366             glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
     1707#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
     1708            glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, 0);
     1709#else
     1710            glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data());
     1711#endif
    13671712
    13681713            shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2);
     
    13891734    //### TODO: Gamma correction
    13901735
    1391     glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
    1392     glBindTexture(GL_TEXTURE_2D, cache->texture());
    1393     updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
    1394 
    1395     shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
    1396     glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
    1397 }
    1398 
    1399 void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
     1736    QGLTextureGlyphCache::FilterMode filterMode = (s->matrix.type() > QTransform::TxTranslate)?QGLTextureGlyphCache::Linear:QGLTextureGlyphCache::Nearest;
     1737    if (lastMaskTextureUsed != cache->texture() || cache->filterMode() != filterMode) {
     1738
     1739        glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
     1740        if (lastMaskTextureUsed != cache->texture()) {
     1741            glBindTexture(GL_TEXTURE_2D, cache->texture());
     1742            lastMaskTextureUsed = cache->texture();
     1743        }
     1744
     1745        if (cache->filterMode() != filterMode) {
     1746            if (filterMode == QGLTextureGlyphCache::Linear) {
     1747                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     1748                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     1749            } else {
     1750                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     1751                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     1752            }
     1753            cache->setFilterMode(filterMode);
     1754        }
     1755    }
     1756
     1757#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
     1758    glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, 0);
     1759    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
     1760#else
     1761    glDrawElements(GL_TRIANGLE_STRIP, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data());
     1762#endif
     1763}
     1764
     1765void QGL2PaintEngineEx::drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap,
     1766                                            QPainter::PixmapFragmentHints hints)
    14001767{
    14011768    Q_D(QGL2PaintEngineEx);
    14021769    // Use fallback for extended composition modes.
    14031770    if (state()->composition_mode > QPainter::CompositionMode_Plus) {
    1404         QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints);
     1771        QPaintEngineEx::drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
    14051772        return;
    14061773    }
    14071774
    14081775    ensureActive();
    1409     d->drawPixmaps(drawingData, dataCount, pixmap, hints);
    1410 }
    1411 
    1412 
    1413 void QGL2PaintEngineExPrivate::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
     1776    int max_texture_size = d->ctx->d_func()->maxTextureSize();
     1777    if (pixmap.width() > max_texture_size || pixmap.height() > max_texture_size) {
     1778        QPixmap scaled = pixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio);
     1779        d->drawPixmapFragments(fragments, fragmentCount, scaled, hints);
     1780    } else {
     1781        d->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
     1782    }
     1783}
     1784
     1785
     1786void QGL2PaintEngineExPrivate::drawPixmapFragments(const QPainter::PixmapFragment *fragments,
     1787                                                   int fragmentCount, const QPixmap &pixmap,
     1788                                                   QPainter::PixmapFragmentHints hints)
    14141789{
    14151790    GLfloat dx = 1.0f / pixmap.size().width();
     
    14321807    bool allOpaque = true;
    14331808
    1434     for (int i = 0; i < dataCount; ++i) {
     1809    for (int i = 0; i < fragmentCount; ++i) {
    14351810        qreal s = 0;
    14361811        qreal c = 1;
    1437         if (drawingData[i].rotation != 0) {
    1438             s = qFastSin(drawingData[i].rotation * Q_PI / 180);
    1439             c = qFastCos(drawingData[i].rotation * Q_PI / 180);
    1440         }
    1441 
    1442         qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width();
    1443         qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height();
     1812        if (fragments[i].rotation != 0) {
     1813            s = qFastSin(fragments[i].rotation * Q_PI / 180);
     1814            c = qFastCos(fragments[i].rotation * Q_PI / 180);
     1815        }
     1816
     1817        qreal right = 0.5 * fragments[i].scaleX * fragments[i].width;
     1818        qreal bottom = 0.5 * fragments[i].scaleY * fragments[i].height;
    14441819        QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c);
    14451820        QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c);
    14461821
    1447         vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
    1448         vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y());
    1449         vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
    1450         vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
    1451         vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y());
    1452         vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
    1453 
    1454         QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy,
    1455                     drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy);
    1456 
    1457         textureCoordinateArray.lineToArray(src.right, src.bottom);
    1458         textureCoordinateArray.lineToArray(src.right, src.top);
    1459         textureCoordinateArray.lineToArray(src.left, src.top);
    1460         textureCoordinateArray.lineToArray(src.left, src.top);
    1461         textureCoordinateArray.lineToArray(src.left, src.bottom);
    1462         textureCoordinateArray.lineToArray(src.right, src.bottom);
    1463 
    1464         qreal opacity = drawingData[i].opacity * q->state()->opacity;
     1822        vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y);
     1823        vertexCoordinateArray.addVertex(-bottomLeft.x + fragments[i].x, -bottomLeft.y + fragments[i].y);
     1824        vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y);
     1825        vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y);
     1826        vertexCoordinateArray.addVertex(bottomLeft.x + fragments[i].x, bottomLeft.y + fragments[i].y);
     1827        vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y);
     1828
     1829        QGLRect src(fragments[i].sourceLeft * dx, fragments[i].sourceTop * dy,
     1830                    (fragments[i].sourceLeft + fragments[i].width) * dx,
     1831                    (fragments[i].sourceTop + fragments[i].height) * dy);
     1832
     1833        textureCoordinateArray.addVertex(src.right, src.bottom);
     1834        textureCoordinateArray.addVertex(src.right, src.top);
     1835        textureCoordinateArray.addVertex(src.left, src.top);
     1836        textureCoordinateArray.addVertex(src.left, src.top);
     1837        textureCoordinateArray.addVertex(src.left, src.bottom);
     1838        textureCoordinateArray.addVertex(src.right, src.bottom);
     1839
     1840        qreal opacity = fragments[i].opacity * q->state()->opacity;
    14651841        opacityArray << opacity << opacity << opacity << opacity << opacity << opacity;
    14661842        allOpaque &= (opacity >= 0.99f);
     
    14751851        // Flip texture y-coordinate.
    14761852        QGLPoint *data = textureCoordinateArray.data();
    1477         for (int i = 0; i < 6 * dataCount; ++i)
     1853        for (int i = 0; i < 6 * fragmentCount; ++i)
    14781854            data[i].y = 1 - data[i].y;
    14791855    }
     
    14821858
    14831859    bool isBitmap = pixmap.isQBitmap();
    1484     bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque;
     1860    bool isOpaque = !isBitmap && (!pixmap.hasAlpha() || (hints & QPainter::OpaqueHint)) && allOpaque;
    14851861
    14861862    updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
     
    14891865    // Setup for texture drawing
    14901866    currentBrush = noBrush;
    1491     shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
     1867    shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc
     1868                                            : QGLEngineShaderManager::ImageSrc);
    14921869    if (prepareForDraw(isOpaque))
    14931870        shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
     
    14981875    }
    14991876
    1500     glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount);
     1877    glDrawArrays(GL_TRIANGLES, 0, 6 * fragmentCount);
    15011878}
    15021879
     
    15231900    d->brushTextureDirty = true;
    15241901    d->brushUniformsDirty = true;
     1902    d->matrixUniformDirty = true;
    15251903    d->matrixDirty = true;
    15261904    d->compositionModeDirty = true;
     
    15601938#if defined(Q_WS_WIN)
    15611939    if (qt_cleartype_enabled)
     1940#endif
     1941#if defined(Q_WS_MAC)
     1942    if (qt_applefontsmoothing_enabled)
    15621943#endif
    15631944        d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
     
    16051986        d->unusedVBOSToClean.clear();
    16061987    }
     1988    if (!d->unusedIBOSToClean.isEmpty()) {
     1989        glDeleteBuffers(d->unusedIBOSToClean.size(), d->unusedIBOSToClean.constData());
     1990        d->unusedIBOSToClean.clear();
     1991    }
    16071992#endif
    16081993
     
    16262011        glViewport(0, 0, d->width, d->height);
    16272012        d->needsSync = false;
     2013        d->lastMaskTextureUsed = 0;
    16282014        d->shaderManager->setDirty();
    16292015        d->ctx->d_func()->syncGlState();
     
    18062192        QRectF rect(points[0], points[2]);
    18072193
    1808         if (state()->matrix.type() <= QTransform::TxScale) {
     2194        if (state()->matrix.type() <= QTransform::TxScale
     2195            || (state()->matrix.type() == QTransform::TxRotate
     2196                && qFuzzyIsNull(state()->matrix.m11())
     2197                && qFuzzyIsNull(state()->matrix.m22())))
     2198        {
    18092199            state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toRect());
    18102200            d->updateClipScissorTest();
Note: See TracChangeset for help on using the changeset viewer.