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:
16 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk

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

    r651 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)
     
    6262}
    6363
    64 void QGL2PEXVertexArray::addRect(const QRectF &rect)
    65 {
    66     vertexArray << rect.topLeft() << rect.topRight() << rect.bottomRight()
    67                 << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
    68 }
    69 
    7064void QGL2PEXVertexArray::addClosingLine(int index)
    7165{
    72     if (QPointF(vertexArray.at(index)) != QPointF(vertexArray.last()))
    73         vertexArray.add(vertexArray.at(index));
     66    QPointF point(vertexArray.at(index));
     67    if (point != QPointF(vertexArray.last()))
     68        vertexArray.add(point);
    7469}
    7570
     
    146141                int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * 3.14f / (curveInverseScale * 6));
    147142                if (threshold < 3) threshold = 3;
    148                 qreal one_over_threshold_minus_1 = 1.f / (threshold - 1);
     143                qreal one_over_threshold_minus_1 = qreal(1) / (threshold - 1);
    149144                for (int t=0; t<threshold; ++t) {
    150145                    QPointF pt = b.pointAt(t * one_over_threshold_minus_1);
  • trunk/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h

    r651 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)
     
    9494    GLfloat bottom;
    9595
    96     operator QRectF() {return QRectF(left, top, right-left, bottom-top);}
     96    operator QRectF() const {return QRectF(left, top, right-left, bottom-top);}
    9797};
    9898
     
    101101public:
    102102    QGL2PEXVertexArray() :
     103        vertexArray(0), vertexArrayStops(0),
    103104        maxX(-2e10), maxY(-2e10), minX(2e10), minY(2e10),
    104         boundingRectDirty(true) {}
     105        boundingRectDirty(true)
     106    { }
     107   
     108    inline void addRect(const QRectF &rect)
     109    {
     110        qreal top = rect.top();
     111        qreal left = rect.left();
     112        qreal bottom = rect.bottom();
     113        qreal right = rect.right();
     114   
     115        vertexArray << QGLPoint(left, top)
     116                    << QGLPoint(right, top)
     117                    << QGLPoint(right, bottom)
     118                    << QGLPoint(right, bottom)
     119                    << QGLPoint(left, bottom)
     120                    << QGLPoint(left, top);       
     121    }
    105122
    106     void addRect(const QRectF &rect);
     123    inline void addQuad(const QRectF &rect)
     124    {
     125        qreal top = rect.top();
     126        qreal left = rect.left();
     127        qreal bottom = rect.bottom();
     128        qreal right = rect.right();
     129
     130        vertexArray << QGLPoint(left, top)
     131                    << QGLPoint(right, top)
     132                    << QGLPoint(left, bottom)
     133                    << QGLPoint(right, bottom);
     134
     135    }
     136
     137    inline void addVertex(const GLfloat x, const GLfloat y)
     138    {
     139        vertexArray.add(QGLPoint(x, y));
     140    }
     141
    107142    void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true);
    108143    void clear();
  • trunk/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp

    r651 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)
  • trunk/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h

    r651 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)
  • trunk/src/opengl/gl2paintengineex/qglengineshadermanager.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)
     
    4242#include "qglengineshadermanager_p.h"
    4343#include "qglengineshadersource_p.h"
     44#include "qpaintengineex_opengl2_p.h"
    4445
    4546#if defined(QT_DEBUG)
     
    9798        code[UntransformedPositionVertexShader] = qglslUntransformedPositionVertexShader;
    9899        code[PositionOnlyVertexShader] = qglslPositionOnlyVertexShader;
     100        code[ComplexGeometryPositionOnlyVertexShader] = qglslComplexGeometryPositionOnlyVertexShader;
    99101        code[PositionWithPatternBrushVertexShader] = qglslPositionWithPatternBrushVertexShader;
    100102        code[PositionWithLinearGradientBrushVertexShader] = qglslPositionWithLinearGradientBrushVertexShader;
     
    248250
    249251// The address returned here will only be valid until next time this function is called.
     252// The program is return bound.
    250253QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineShaderProg &prog)
    251254{
     
    255258            // Move the program to the top of the list as a poor-man's cache algo
    256259            cachedPrograms.move(i, 0);
     260            cachedProg->program->bind();
    257261            return cachedProg;
    258262        }
     
    330334        if (newProg->useOpacityAttribute)
    331335            newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
    332         if (newProg->usePmvMatrix) {
     336        if (newProg->usePmvMatrixAttribute) {
    333337            newProg->program->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
    334338            newProg->program->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
     
    355359            break;
    356360        }
     361
     362        newProg->program->bind();
     363
     364        if (newProg->maskFragShader != QGLEngineSharedShaders::NoMaskFragmentShader) {
     365            GLuint location = newProg->program->uniformLocation("maskTexture");
     366            newProg->program->setUniformValue(location, QT_MASK_TEXTURE_UNIT);
     367        }
     368
    357369        if (cachedPrograms.count() > 30) {
    358370            // The cache is full, so delete the last 5 programs in the list.
     
    404416    : ctx(context),
    405417      shaderProgNeedsChanging(true),
     418      complexGeometry(false),
    406419      srcPixelType(Qt::NoBrush),
    407420      opacityMode(NoOpacity),
     
    445458        "invertedTextureSize",
    446459        "brushTransform",
    447         "brushTexture"
     460        "brushTexture",
     461        "matrix"
    448462    };
    449463
     
    753767    requiredProgram.useTextureCoords = texCoords;
    754768    requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity);
    755     requiredProgram.usePmvMatrix = true;
     769    if (complexGeometry && srcPixelType == Qt::SolidPattern) {
     770        requiredProgram.positionVertexShader = QGLEngineSharedShaders::ComplexGeometryPositionOnlyVertexShader;
     771        requiredProgram.usePmvMatrixAttribute = false;
     772    } else {
     773        requiredProgram.usePmvMatrixAttribute = true;
     774
     775        // Force complexGeometry off, since we currently don't support that mode for
     776        // non-solid brushes
     777        complexGeometry = false;
     778    }
    756779
    757780    // At this point, requiredProgram is fully populated so try to find the program in the cache
    758781    currentShaderProg = sharedShaders->findProgramInCache(requiredProgram);
    759782
    760     if (currentShaderProg) {
    761         currentShaderProg->program->bind();
    762         if (useCustomSrc)
    763             customSrcStage->setUniforms(currentShaderProg->program);
     783    if (currentShaderProg && useCustomSrc) {
     784        customSrcStage->setUniforms(currentShaderProg->program);
    764785    }
    765786
  • trunk/src/opengl/gl2paintengineex/qglengineshadermanager_p.h

    r651 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)
     
    7373    calculations which logically belong in the fragment shader have been moved
    7474    into the vertex shader to improve performance. This is why the position
    75     calculation is in a seperate shader. Not only does it calculate the
     75    calculation is in a separate shader. Not only does it calculate the
    7676    position, but it also calculates some data to be passed to the fragment
    7777    shader as a varying. It is optimal to move as much of the calculation as
     
    273273        UntransformedPositionVertexShader,
    274274        PositionOnlyVertexShader,
     275        ComplexGeometryPositionOnlyVertexShader,
    275276        PositionWithPatternBrushVertexShader,
    276277        PositionWithLinearGradientBrushVertexShader,
     
    401402    bool                useTextureCoords;
    402403    bool                useOpacityAttribute;
    403     bool                usePmvMatrix;
     404    bool                usePmvMatrixAttribute;
    404405
    405406    bool operator==(const QGLEngineShaderProg& other) {
     
    447448        BrushTransform,
    448449        BrushTexture,
     450        Matrix,
    449451        NumUniforms
    450452    };
     
    456458    };
    457459
    458     // There are optimisations we can do, depending on the brush transform:
     460    // There are optimizations we can do, depending on the brush transform:
    459461    //    1) May not have to apply perspective-correction
    460462    //    2) Can use lower precision for matrix
     
    475477    void useSimpleProgram();
    476478    void useBlitProgram();
     479    void setHasComplexGeometry(bool hasComplexGeometry)
     480    {
     481        complexGeometry = hasComplexGeometry;
     482        shaderProgNeedsChanging = true;
     483    }
     484    bool hasComplexGeometry() const
     485    {
     486        return complexGeometry;
     487    }
    477488
    478489    QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
     
    488499    QGLContext*     ctx;
    489500    bool            shaderProgNeedsChanging;
     501    bool            complexGeometry;
    490502
    491503    // Current state variables which influence the choice of shader:
  • trunk/src/opengl/gl2paintengineex/qglengineshadersource_p.h

    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)
     
    107107        gl_Position = vec4(transformedPos.xy, 0.0, transformedPos.z); \n\
    108108    }\n";
     109
     110static const char* const qglslComplexGeometryPositionOnlyVertexShader = "\n\
     111    uniform highp mat3 matrix; \n\
     112    attribute highp vec2 vertexCoordsArray; \n\
     113    void setPosition(void) \n\
     114    { \n\
     115      gl_Position = vec4(matrix * vec3(vertexCoordsArray, 1), 1);\n\
     116    } \n";
    109117
    110118static const char* const qglslUntransformedPositionVertexShader = "\n\
     
    275283    uniform   highp   vec2      invertedTextureSize; \n\
    276284    uniform   highp   mat3      brushTransform; \n\
    277     varying   highp   vec2      textureCoords; \n\
     285    varying   highp   vec2      brushTextureCoords; \n\
    278286    void setPosition(void) \n\
    279287    { \n\
     
    285293        mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
    286294        gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
    287         textureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \n\
     295        brushTextureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \n\
    288296    }\n";
    289297
     
    296304// TODO: Special case POT textures which don't need this emulation
    297305static const char* const qglslTextureBrushSrcFragmentShader = "\n\
    298     varying highp   vec2      textureCoords; \n\
     306    varying highp   vec2      brushTextureCoords; \n\
    299307    uniform lowp    sampler2D brushTexture; \n\
    300308    lowp vec4 srcPixel() { \n\
    301         return texture2D(brushTexture, fract(textureCoords)); \n\
     309        return texture2D(brushTexture, fract(brushTextureCoords)); \n\
    302310    }\n";
    303311#else
    304312static const char* const qglslTextureBrushSrcFragmentShader = "\n\
    305     varying   highp   vec2      textureCoords; \n\
     313    varying   highp   vec2      brushTextureCoords; \n\
    306314    uniform   lowp    sampler2D brushTexture; \n\
    307315    lowp vec4 srcPixel() \n\
    308316    { \n\
    309         return texture2D(brushTexture, textureCoords); \n\
     317        return texture2D(brushTexture, brushTextureCoords); \n\
    310318    }\n";
    311319#endif
    312320
    313321static const char* const qglslTextureBrushSrcWithPatternFragmentShader = "\n\
    314     varying   highp   vec2      textureCoords; \n\
     322    varying   highp   vec2      brushTextureCoords; \n\
    315323    uniform   lowp    vec4      patternColor; \n\
    316324    uniform   lowp    sampler2D brushTexture; \n\
    317325    lowp vec4 srcPixel() \n\
    318326    { \n\
    319         return patternColor * (1.0 - texture2D(brushTexture, textureCoords).r); \n\
     327        return patternColor * (1.0 - texture2D(brushTexture, brushTextureCoords).r); \n\
    320328    }\n";
    321329
     
    333341    lowp vec4 srcPixel() \n\
    334342    { \n"
    335 #ifdef QT_OPENGL_ES_2
    336         // work-around for driver bug
    337         "return 1.0 * texture2D(imageTexture, textureCoords); \n"
    338 #else
    339343        "return texture2D(imageTexture, textureCoords); \n"
    340 #endif
    341344    "}\n";
    342345
  • trunk/src/opengl/gl2paintengineex/qglgradientcache.cpp

    r651 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)
     
    4040****************************************************************************/
    4141
     42#include "qglgradientcache_p.h"
    4243#include <private/qdrawhelper_p.h>
    4344#include <private/qgl_p.h>
    4445
    45 #include "qglgradientcache_p.h"
    4646
    4747QT_BEGIN_NAMESPACE
  • trunk/src/opengl/gl2paintengineex/qglgradientcache_p.h

    r651 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)
  • 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();
  • trunk/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h

    r651 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)
     
    124124    virtual void transformChanged();
    125125
    126     virtual void drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr);
    127126    virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
    128     virtual void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints);
     127    virtual void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap,
     128                                     QPainter::PixmapFragmentHints hints);
    129129    virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
    130130                           Qt::ImageConversionFlags flags = Qt::AutoColor);
     
    134134    virtual void clip(const QVectorPath &path, Qt::ClipOperation op);
    135135
     136    virtual void drawStaticTextItem(QStaticTextItem *textItem);
     137
     138    bool drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr);
    136139
    137140    Type type() const { return OpenGL2; }
     
    149152    void endNativePainting();
    150153
     154    void invalidateState();
     155
    151156    QPixmapFilter *pixmapFilter(int type, const QPixmapFilter *prototype);
    152157
    153158    void setRenderTextActive(bool);
    154159
     160    bool isNativePaintingActive() const;
    155161private:
    156162    Q_DISABLE_COPY(QGL2PaintEngineEx)
    157163};
    158 
    159164
    160165class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate
     
    174179            ctx(0),
    175180            useSystemClip(true),
     181            elementIndicesVBOId(0),
     182            opacityArray(0),
    176183            snapToPixelGrid(false),
    177184            addOffset(false),
    178             inverseScale(1)
     185            nativePaintingActive(false),
     186            inverseScale(1),
     187            lastMaskTextureUsed(0)
    179188    { }
    180189
     
    194203    void stroke(const QVectorPath &path, const QPen &pen);
    195204    void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false);
    196     void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints);
    197     void drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, const QTextItemInt &ti);
     205    void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap,
     206                             QPainter::PixmapFragmentHints hints);
     207    void drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem);
    198208
    199209    // Calls glVertexAttributePointer if the pointer has changed
     
    254264    bool brushUniformsDirty;
    255265    bool opacityUniformDirty;
     266    bool matrixUniformDirty;
    256267
    257268    bool stencilClean; // Has the stencil not been used for clipping so far?
     
    264275    const QBrush noBrush;
    265276
     277    QPixmap currentBrushPixmap;
     278
    266279    QGL2PEXVertexArray vertexCoordinateArray;
    267280    QGL2PEXVertexArray textureCoordinateArray;
     281    QVector<GLushort> elementIndices;
     282    GLuint elementIndicesVBOId;
    268283    QDataBuffer<GLfloat> opacityArray;
    269284    GLfloat staticVertexCoordinateArray[8];
     
    272287    bool snapToPixelGrid;
    273288    bool addOffset; // When enabled, adds a 0.49,0.49 offset to matrix in updateMatrix
     289    bool nativePaintingActive;
    274290    GLfloat pmvMatrix[3][3];
    275291    GLfloat inverseScale;
    276292
    277293    GLuint lastTextureUsed;
     294    GLuint lastMaskTextureUsed;
    278295
    279296    bool needsSync;
     
    294311    QSet<QVectorPath::CacheEntry *> pathCaches;
    295312    QVector<GLuint> unusedVBOSToClean;
     313    QVector<GLuint> unusedIBOSToClean;
    296314
    297315    const GLfloat *vertexAttribPointers[3];
  • trunk/src/opengl/gl2paintengineex/qtextureglyphcache_gl.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)
     
    4343#include "qpaintengineex_opengl2_p.h"
    4444
     45#if defined QT_OPENGL_ES_2 && !defined(QT_NO_EGL)
     46#include "private/qeglcontext_p.h"
     47#endif
     48
    4549QT_BEGIN_NAMESPACE
    4650
     
    5054
    5155QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix)
    52     : QTextureGlyphCache(type, matrix)
    53     , ctx(context)
     56    : QImageTextureGlyphCache(type, matrix)
     57    , ctx(0)
    5458    , m_width(0)
    5559    , m_height(0)
    56 {
    57     glGenFramebuffers(1, &m_fbo);
     60    , m_filterMode(Nearest)
     61{
     62    setContext(context);
     63}
     64
     65void QGLTextureGlyphCache::setContext(QGLContext *context)
     66{
     67    ctx = context;
     68
     69    // broken FBO readback is a bug in the SGX 1.3 and 1.4 drivers for the N900 where
     70    // copying between FBO's is broken if the texture is either GL_ALPHA or POT. The
     71    // workaround is to use a system-memory copy of the glyph cache for this device.
     72    // Switching to NPOT and GL_RGBA would both cost a lot more graphics memory and
     73    // be slower, so that is not desireable.
     74    if (!ctx->d_ptr->workaround_brokenFBOReadBack)
     75        glGenFramebuffers(1, &m_fbo);
     76
    5877    connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
    5978            SLOT(contextDestroyed(const QGLContext*)));
    6079}
    6180
    62 QGLTextureGlyphCache::~QGLTextureGlyphCache()
     81void QGLTextureGlyphCache::clear()
    6382{
    6483    if (ctx) {
    6584        QGLShareContextScope scope(ctx);
    66         glDeleteFramebuffers(1, &m_fbo);
    6785
    6886        if (m_width || m_height)
    6987            glDeleteTextures(1, &m_texture);
    70     }
     88
     89        m_texture = 0;
     90        m_width = 0;
     91        m_height = 0;
     92        m_w = 0;
     93        m_h = 0;
     94        m_cx = 0;
     95        m_cy = 0;
     96        m_currentRowHeight = 0;
     97        coords.clear();
     98    }
     99 
     100}
     101
     102QGLTextureGlyphCache::~QGLTextureGlyphCache()
     103{
     104    if (ctx) {
     105        QGLShareContextScope scope(ctx);
     106
     107        if (!ctx->d_ptr->workaround_brokenFBOReadBack)
     108            glDeleteFramebuffers(1, &m_fbo);
     109    }
     110
     111    clear();
    71112}
    72113
    73114void QGLTextureGlyphCache::createTextureData(int width, int height)
    74115{
     116    // create in QImageTextureGlyphCache baseclass is meant to be called
     117    // only to create the initial image and does not preserve the content,
     118    // so we don't call when this function is called from resize.
     119    if (ctx->d_ptr->workaround_brokenFBOReadBack && image().isNull())
     120        QImageTextureGlyphCache::createTextureData(width, height);
     121
     122    // Make the lower glyph texture size 16 x 16.
     123    if (width < 16)
     124        width = 16;
     125    if (height < 16)
     126        height = 16;
     127
    75128    glGenTextures(1, &m_texture);
    76129    glBindTexture(GL_TEXTURE_2D, m_texture);
     
    79132    m_height = height;
    80133
    81     QVarLengthArray<uchar> data(width * height);
    82     for (int i = 0; i < data.size(); ++i)
    83         data[i] = 0;
    84 
    85     if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
    86         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
    87     else
     134    if (m_type == QFontEngineGlyphCache::Raster_RGBMask) {
     135        QVarLengthArray<uchar> data(width * height * 4);
     136        for (int i = 0; i < data.size(); ++i)
     137            data[i] = 0;
     138        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
     139    } else {
     140        QVarLengthArray<uchar> data(width * height);
     141        for (int i = 0; i < data.size(); ++i)
     142            data[i] = 0;
    88143        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
     144    }
    89145
    90146    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    91147    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     148    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     149    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     150    m_filterMode = Nearest;
    92151}
    93152
    94153void QGLTextureGlyphCache::resizeTextureData(int width, int height)
    95154{
     155    int oldWidth = m_width;
     156    int oldHeight = m_height;
     157
     158    // Make the lower glyph texture size 16 x 16.
     159    if (width < 16)
     160        width = 16;
     161    if (height < 16)
     162        height = 16;
     163
     164    GLuint oldTexture = m_texture;
     165    createTextureData(width, height);
     166
     167    if (ctx->d_ptr->workaround_brokenFBOReadBack) {
     168        QImageTextureGlyphCache::resizeTextureData(width, height);
     169        Q_ASSERT(image().depth() == 8);
     170        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, image().constBits());
     171        glDeleteTextures(1, &oldTexture);
     172        return;
     173    }
     174
    96175    // ### the QTextureGlyphCache API needs to be reworked to allow
    97176    // ### resizeTextureData to fail
    98 
    99     int oldWidth = m_width;
    100     int oldHeight = m_height;
    101 
    102     GLuint oldTexture = m_texture;
    103     createTextureData(width, height);
    104177
    105178    glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
     
    114187    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    115188    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     189    m_filterMode = Nearest;
    116190    glBindTexture(GL_TEXTURE_2D, 0);
    117191    glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
     
    160234    glBindTexture(GL_TEXTURE_2D, m_texture);
    161235
    162 #ifdef QT_OPENGL_ES_2
    163     QDataBuffer<uchar> buffer(4*oldWidth*oldHeight);
    164     buffer.resize(4*oldWidth*oldHeight);
    165     glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
    166 
    167     // do an in-place conversion from GL_RGBA to GL_ALPHA
    168     for (int i=0; i<oldWidth*oldHeight; ++i)
    169         buffer.data()[i] = buffer.at(4*i + 3);
    170 
    171     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight,
    172                     GL_ALPHA, GL_UNSIGNED_BYTE, buffer.data());
    173 #else
    174236    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
    175 #endif
    176237
    177238    glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
     
    188249void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
    189250{
     251    if (ctx->d_ptr->workaround_brokenFBOReadBack) {
     252        QImageTextureGlyphCache::fillTexture(c, glyph);
     253
     254        glBindTexture(GL_TEXTURE_2D, m_texture);
     255        const QImage &texture = image();
     256        const uchar *bits = texture.constBits();
     257        bits += c.y * texture.bytesPerLine() + c.x;
     258        for (int i=0; i<c.h; ++i) {
     259            glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, c.w, 1, GL_ALPHA, GL_UNSIGNED_BYTE, bits);
     260            bits += texture.bytesPerLine();
     261        }
     262
     263        return;
     264    }
     265
    190266    QImage mask = textureMapForGlyph(glyph);
    191267    const int maskWidth = mask.width();
     
    218294        glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
    219295    } else {
    220 #ifdef QT_OPENGL_ES2
    221         glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits());
    222 #else
    223296        // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is
    224297        // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista
     
    232305        for (int i = 0; i < maskHeight; ++i)
    233306            glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i));
    234 #endif
    235     }
    236 }
    237 
    238 int QGLTextureGlyphCache::glyphMargin() const
    239 {
    240 #if defined(Q_WS_MAC)
    241     return 2;
    242 #elif defined (Q_WS_X11)
    243     return 0;
    244 #else
    245     return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0;
    246 #endif
    247 }
    248 
     307    }
     308}
     309
     310int QGLTextureGlyphCache::glyphPadding() const
     311{
     312    return 1;
     313}
     314
     315int QGLTextureGlyphCache::maxTextureWidth() const
     316{
     317    return ctx->d_ptr->maxTextureSize();
     318}
     319
     320int QGLTextureGlyphCache::maxTextureHeight() const
     321{
     322    if (ctx->d_ptr->workaround_brokenTexSubImage)
     323        return qMin(1024, ctx->d_ptr->maxTextureSize());
     324    else
     325        return ctx->d_ptr->maxTextureSize();
     326}
    249327QT_END_NAMESPACE
  • trunk/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h

    r651 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)
     
    6363class QGL2PaintEngineExPrivate;
    6464
    65 class QGLTextureGlyphCache : public QObject, public QTextureGlyphCache
     65class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QObject, public QImageTextureGlyphCache
    6666{
    6767    Q_OBJECT
     
    7373    virtual void resizeTextureData(int width, int height);
    7474    virtual void fillTexture(const Coord &c, glyph_t glyph);
    75     virtual int glyphMargin() const;
     75    virtual int glyphPadding() const;
     76    virtual int maxTextureWidth() const;
     77    virtual int maxTextureHeight() const;
    7678
    7779    inline GLuint texture() const { return m_texture; }
     
    8284    inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
    8385
     86    enum FilterMode {
     87        Nearest,
     88        Linear
     89    };
     90    FilterMode filterMode() const { return m_filterMode; }
     91    void setFilterMode(FilterMode m) { m_filterMode = m; }
     92
     93    void setContext(QGLContext *context);
     94    QGLContext *context() const { return ctx; }
    8495
    8596public Q_SLOTS:
     
    91102                // destroy the fbo and texture here, but since the context
    92103                // is about to be destroyed, the GL server will do the
    93                 // clean up for us anyway
     104                // clean up for us anyway. We reset everything, so that the
     105                // glyph cache object can be reused later by setting a new
     106                // context on it.
    94107                m_fbo = 0;
    95108                m_texture = 0;
    96109                ctx = 0;
     110                m_width = 0;
     111                m_height = 0;
     112                m_w = 0;
     113                m_h = 0;
     114                m_cx = 0;
     115                m_cy = 0;
     116                m_currentRowHeight = 0;
     117                coords.clear();
    97118            } else {
    98119                // since the context holding the texture is shared, and
     
    103124        }
    104125    }
     126
     127    void clear();
    105128
    106129private:
     
    116139
    117140    QGLShaderProgram *m_program;
     141
     142    FilterMode m_filterMode;
    118143};
    119144
  • trunk/src/opengl/gl2paintengineex/qtriangulatingstroker.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)
     
    7474
    7575
    76 void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen)
     76void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, const QRectF &)
    7777{
    7878    const qreal *pts = path.points();
     
    112112    //
    113113    // The curvyness value of PI/14 was based on,
    114     // arcLength=2*PI*r/4=PI/2 and splitting length into somewhere
     114    // arcLength = 2*PI*r/4 = PI*r/2 and splitting length into somewhere
    115115    // between 3 and 8 where 5 seemed to be give pretty good results
    116116    // hence: Q_PI/14. Lower divisors will give more detail at the
     
    482482
    483483QDashedStrokeProcessor::QDashedStrokeProcessor()
    484     : m_dash_stroker(0), m_inv_scale(1)
     484    : m_points(0), m_types(0),
     485      m_dash_stroker(0), m_inv_scale(1)
    485486{
    486487    m_dash_stroker.setMoveToHook(qdashprocessor_moveTo);
     
    489490}
    490491
    491 void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen)
     492void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen, const QRectF &clip)
    492493{
    493494
     
    496497    int count = path.elementCount();
    497498
     499    bool cosmetic = pen.isCosmetic();
     500
    498501    m_points.reset();
    499502    m_types.reset();
     503    m_points.reserve(path.elementCount());
     504    m_types.reserve(path.elementCount());
    500505
    501506    qreal width = qpen_widthf(pen);
     
    504509
    505510    m_dash_stroker.setDashPattern(pen.dashPattern());
    506     m_dash_stroker.setStrokeWidth(pen.isCosmetic() ? width * m_inv_scale : width);
     511    m_dash_stroker.setStrokeWidth(cosmetic ? width * m_inv_scale : width);
     512    m_dash_stroker.setDashOffset(pen.dashOffset());
    507513    m_dash_stroker.setMiterLimit(pen.miterLimit());
    508     qreal curvyness = sqrt(width) * m_inv_scale / 8;
     514    m_dash_stroker.setClipRect(clip);
     515
     516    float curvynessAdd, curvynessMul, roundness = 0;
     517
     518    // simplfy pens that are thin in device size (2px wide or less)
     519    if (width < 2.5 && (cosmetic || m_inv_scale == 1)) {
     520        curvynessAdd = 0.5;
     521        curvynessMul = CURVE_FLATNESS / m_inv_scale;
     522        roundness = 1;
     523    } else if (cosmetic) {
     524        curvynessAdd= width / 2;
     525        curvynessMul= CURVE_FLATNESS;
     526        roundness = qMax<int>(4, width * CURVE_FLATNESS);
     527    } else {
     528        curvynessAdd = width * m_inv_scale;
     529        curvynessMul = CURVE_FLATNESS / m_inv_scale;
     530        roundness = qMax<int>(4, width * curvynessMul);
     531    }
    509532
    510533    if (count < 2)
     
    541564                                                *(((const QPointF *) pts) + 2));
    542565                QRectF bounds = b.bounds();
    543                 int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * curvyness);
     566                float rad = qMax(bounds.width(), bounds.height());
     567                int threshold = qMin<float>(64, (rad + curvynessAdd) * curvynessMul);
    544568                if (threshold < 4)
    545569                    threshold = 4;
     570
    546571                qreal threshold_minus_1 = threshold - 1;
    547572                for (int i=0; i<threshold; ++i) {
  • trunk/src/opengl/gl2paintengineex/qtriangulatingstroker_p.h

    r651 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)
     
    5555{
    5656public:
    57     void process(const QVectorPath &path, const QPen &pen);
     57    QTriangulatingStroker() : m_vertices(0) {}
     58    void process(const QVectorPath &path, const QPen &pen, const QRectF &clip);
    5859
    5960    inline int vertexCount() const { return m_vertices.size(); }
     
    9798    QDashedStrokeProcessor();
    9899
    99     void process(const QVectorPath &path, const QPen &pen);
     100    void process(const QVectorPath &path, const QPen &pen, const QRectF &clip);
    100101
    101102    inline void addElement(QPainterPath::ElementType type, qreal x, qreal y) {
Note: See TracChangeset for help on using the changeset viewer.