diff options
Diffstat (limited to 'recipes/qt4/qt-4.6.0/0860-Added-caching-of-vectorpaths-to-the-GL-paint-engine.patch')
-rw-r--r-- | recipes/qt4/qt-4.6.0/0860-Added-caching-of-vectorpaths-to-the-GL-paint-engine.patch | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/recipes/qt4/qt-4.6.0/0860-Added-caching-of-vectorpaths-to-the-GL-paint-engine.patch b/recipes/qt4/qt-4.6.0/0860-Added-caching-of-vectorpaths-to-the-GL-paint-engine.patch new file mode 100644 index 0000000000..794380ab91 --- /dev/null +++ b/recipes/qt4/qt-4.6.0/0860-Added-caching-of-vectorpaths-to-the-GL-paint-engine.patch @@ -0,0 +1,317 @@ +From dbfdfdb1bc37dd18dd1b723b5d5b0b65c37f3f41 Mon Sep 17 00:00:00 2001 +From: Gunnar Sletta <gunnar@trolltech.com> +Date: Tue, 1 Dec 2009 09:18:47 +0100 +Subject: [PATCH 0860/1244] Added caching of vectorpaths to the GL paint engine. + +The first time a path is drawn we call makeCachable on the path, which +means that if it is drawn again, we start caching it. This is a bit of +a trick to avoid caching paths that are drawn once and discared while +at the same time cache paths that are reused automatically. + +The GL engine owns the vertex information and is responsible for cleaning +it up. If the vectorpath is destroyed first, it will call the cleanup function. +if the engine dies first, we still require some hooks to clean up the cache +in the path. More to come. When VBO's are used, these will be a leaked if the +path is destroyed after the engine. + +Reviewed-by: Samuel +--- + src/gui/painting/qpaintengineex.cpp | 16 +++- + src/gui/painting/qvectorpath_p.h | 13 ++- + src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h | 2 + + .../gl2paintengineex/qpaintengineex_opengl2.cpp | 115 +++++++++++++++++++- + .../gl2paintengineex/qpaintengineex_opengl2_p.h | 4 + + 5 files changed, 139 insertions(+), 11 deletions(-) + +diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp +index 7d1c109..9a0e319 100644 +--- a/src/gui/painting/qpaintengineex.cpp ++++ b/src/gui/painting/qpaintengineex.cpp +@@ -56,6 +56,20 @@ QT_BEGIN_NAMESPACE + * class QVectorPath + * + */ ++QVectorPath::~QVectorPath() ++{ ++ if (m_hints & ShouldUseCacheHint) { ++ CacheEntry *e = m_cache; ++ while (e) { ++ if (e->data) ++ e->cleanup(e->engine, e->data); ++ CacheEntry *n = e->next; ++ delete e; ++ e = n; ++ } ++ } ++} ++ + + QRectF QVectorPath::controlPointRect() const + { +@@ -94,7 +108,7 @@ QRectF QVectorPath::controlPointRect() const + + + QVectorPath::CacheEntry *QVectorPath::addCacheData(QPaintEngineEx *engine, void *data, +- qvectorpath_cache_cleanup cleanup) { ++ qvectorpath_cache_cleanup cleanup) const{ + Q_ASSERT(!lookupCacheData(engine)); + if ((m_hints & IsCachedHint) == 0) { + m_cache = 0; +diff --git a/src/gui/painting/qvectorpath_p.h b/src/gui/painting/qvectorpath_p.h +index ec27970..5eaddf4 100644 +--- a/src/gui/painting/qvectorpath_p.h ++++ b/src/gui/painting/qvectorpath_p.h +@@ -68,7 +68,7 @@ QT_MODULE(Gui) + + class QPaintEngineEx; + +-typedef void (*qvectorpath_cache_cleanup)(void *data); ++typedef void (*qvectorpath_cache_cleanup)(QPaintEngineEx *engine, void *data); + + struct QRealRect { + qreal x1, y1, x2, y2; +@@ -118,6 +118,8 @@ public: + { + } + ++ ~QVectorPath(); ++ + QRectF controlPointRect() const; + + inline Hint shape() const { return (Hint) (m_hints & ShapeMask); } +@@ -128,6 +130,7 @@ public: + inline bool hasImplicitClose() const { return m_hints & ImplicitClose; } + inline bool hasWindingFill() const { return m_hints & WindingFill; } + ++ inline void makeCacheable() const { m_hints |= ShouldUseCacheHint; m_cache = 0; } + inline uint hints() const { return m_hints; } + + inline const QPainterPath::ElementType *elements() const { return m_elements; } +@@ -146,9 +149,9 @@ public: + CacheEntry *next; + }; + +- CacheEntry *addCacheData(QPaintEngineEx *engine, void *data, qvectorpath_cache_cleanup cleanup); ++ CacheEntry *addCacheData(QPaintEngineEx *engine, void *data, qvectorpath_cache_cleanup cleanup) const; + inline CacheEntry *lookupCacheData(QPaintEngineEx *engine) const { +- Q_ASSERT(m_hints & IsCachedHint); ++ Q_ASSERT(m_hints & ShouldUseCacheHint); + CacheEntry *e = m_cache; + while (e) { + if (e->engine == engine) +@@ -162,14 +165,14 @@ public: + private: + Q_DISABLE_COPY(QVectorPath) + +- CacheEntry *m_cache; +- + const QPainterPath::ElementType *m_elements; + const qreal *m_points; + const int m_count; + + mutable uint m_hints; + mutable QRealRect m_cp_rect; ++ ++ mutable CacheEntry *m_cache; + }; + + Q_GUI_EXPORT const QVectorPath &qtVectorPathForPath(const QPainterPath &path); +diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h +index 03aec17..98eaa91 100644 +--- a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h ++++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h +@@ -112,6 +112,8 @@ public: + int stopCount() const { return vertexArrayStops.size(); } + QGLRect boundingRect() const; + ++ int vertexCount() const { return vertexArray.size(); } ++ + void lineToArray(const GLfloat x, const GLfloat y); + + private: +diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +index 6a708b4..3fce384 100644 +--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp ++++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +@@ -62,6 +62,8 @@ + and use the correct program when we really need it. + */ + ++// #define QT_OPENGL_CACHE_AS_VBOS ++ + #include "qpaintengineex_opengl2_p.h" + + #include <string.h> //for memcpy +@@ -344,6 +346,13 @@ extern QImage qt_imageForBrush(int brushStyle, bool invert); + QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate() + { + delete shaderManager; ++ ++ while (pathCaches.size()) { ++ QVectorPath::CacheEntry *e = *(pathCaches.constBegin()); ++ e->cleanup(e->engine, e->data); ++ e->data = 0; ++ e->engine = 0; ++ } + } + + void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id) +@@ -846,6 +855,30 @@ void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) + mode = newMode; + } + ++struct QGL2PEVectorPathCache ++{ ++#ifdef QT_OPENGL_CACHE_AS_VBOS ++ GLuint vbo; ++#else ++ float *vertices; ++#endif ++ int vertexCount; ++ GLenum primitiveType; ++ qreal iscale; ++}; ++ ++void qopengl2paintengine_cleanup_vectorpath(QPaintEngineEx *engine, void *data) ++{ ++ QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data; ++#ifdef QT_OPENGL_CACHE_AS_VBOS ++ QGL2PaintEngineExPrivate *d = QGL2PaintEngineExPrivate::getData((QGL2PaintEngineEx *) engine); ++ d->unusedVBOSToClean << c->vbo; ++#else ++ qFree(c->vertices); ++#endif ++ delete c; ++} ++ + // Assumes everything is configured for the brush you want to use + void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) + { +@@ -863,10 +896,74 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) + prepareForDraw(currentBrush->isOpaque()); + composite(rect); + } else if (path.isConvex()) { +- vertexCoordinateArray.clear(); +- vertexCoordinateArray.addPath(path, inverseScale, false); +- prepareForDraw(currentBrush->isOpaque()); +- drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); ++ ++ if (path.isCacheable()) { ++ QVectorPath::CacheEntry *data = path.lookupCacheData(q); ++ QGL2PEVectorPathCache *cache; ++ ++ if (data) { ++ cache = (QGL2PEVectorPathCache *) data->data; ++ // Check if scale factor is exceeded for curved paths and generate curves if so... ++ if (path.isCurved()) { ++ qreal scaleFactor = cache->iscale / inverseScale; ++ if (scaleFactor < 0.5 || scaleFactor > 2.0) { ++#ifdef QT_OPENGL_CACHE_AS_VBOS ++ glDeleteBuffers(1, &cache->vbo); ++ cache->vbo = 0; ++#else ++ qFree(cache->vertices); ++#endif ++ cache->vertexCount = 0; ++ } ++ } ++ } else { ++ cache = new QGL2PEVectorPathCache; ++ cache->vertexCount = 0; ++ data = const_cast<QVectorPath &>(path).addCacheData(q, cache, qopengl2paintengine_cleanup_vectorpath); ++ } ++ ++ // Flatten the path at the current scale factor and fill it into the cache struct. ++ if (!cache->vertexCount) { ++ vertexCoordinateArray.clear(); ++ vertexCoordinateArray.addPath(path, inverseScale, false); ++ int vertexCount = vertexCoordinateArray.vertexCount(); ++ int floatSizeInBytes = vertexCount * 2 * sizeof(float); ++ cache->vertexCount = vertexCount; ++ cache->primitiveType = GL_TRIANGLE_FAN; ++ cache->iscale = inverseScale; ++#ifdef QT_OPENGL_CACHE_AS_VBOS ++ glGenBuffers(1, &cache->vbo); ++ glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); ++ glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW); ++#else ++ cache->vertices = (float *) qMalloc(floatSizeInBytes); ++ memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes); ++#endif ++ } ++ ++ prepareForDraw(currentBrush->isOpaque()); ++ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); ++#ifdef QT_OPENGL_CACHE_AS_VBOS ++ glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); ++ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0); ++#else ++ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, cache->vertices); ++#endif ++ glDrawArrays(cache->primitiveType, 0, cache->vertexCount); ++ ++ } else { ++ // printf(" - Marking path as cachable...\n"); ++ // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable ++ // ### Remove before release... ++ static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty(); ++ if (do_vectorpath_cache) ++ path.makeCacheable(); ++ vertexCoordinateArray.clear(); ++ vertexCoordinateArray.addPath(path, inverseScale, false); ++ prepareForDraw(currentBrush->isOpaque()); ++ drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); ++ } ++ + } else { + // The path is too complicated & needs the stencil technique + vertexCoordinateArray.clear(); +@@ -1756,7 +1853,8 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) + d->device->beginPaint(); + + #if !defined(QT_OPENGL_ES_2) +- bool success = qt_resolve_version_2_0_functions(d->ctx); ++ bool success = qt_resolve_version_2_0_functions(d->ctx) ++ && qt_resolve_buffer_extensions(d->ctx); + Q_ASSERT(success); + Q_UNUSED(success); + #endif +@@ -1817,6 +1915,13 @@ bool QGL2PaintEngineEx::end() + delete d->shaderManager; + d->shaderManager = 0; + ++#ifdef QT_OPENGL_CACHE_AS_VBOS ++ if (!d->unusedVBOSToClean.isEmpty()) { ++ glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData()); ++ d->unusedVBOSToClean.clear(); ++ } ++#endif ++ + return false; + } + +diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +index b554f6d..0084476 100644 +--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h ++++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +@@ -221,6 +221,7 @@ public: + void restoreDepthRangeForRenderText(); + + static QGLEngineShaderManager* shaderManagerForEngine(QGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; } ++ static QGL2PaintEngineExPrivate *getData(QGL2PaintEngineEx *engine) { return engine->d_func(); } + + QGL2PaintEngineEx* q; + QGLPaintDevice* device; +@@ -294,6 +295,9 @@ public: + QScopedPointer<QPixmapFilter> fastBlurFilter; + QScopedPointer<QPixmapFilter> dropShadowFilter; + QScopedPointer<QPixmapFilter> fastDropShadowFilter; ++ ++ QSet<QVectorPath::CacheEntry *> pathCaches; ++ QVector<GLuint> unusedVBOSToClean; + }; + + QT_END_NAMESPACE +-- +1.6.5 + |