summaryrefslogtreecommitdiff
path: root/recipes/qt4/qt-4.6.0/0860-Added-caching-of-vectorpaths-to-the-GL-paint-engine.patch
diff options
context:
space:
mode:
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.patch317
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
+