Argh! Accidental double-Revert fixed!
[openembedded.git] / recipes / qt4 / qt-4.6.0 / 0860-Added-caching-of-vectorpaths-to-the-GL-paint-engine.patch
1 From dbfdfdb1bc37dd18dd1b723b5d5b0b65c37f3f41 Mon Sep 17 00:00:00 2001
2 From: Gunnar Sletta <gunnar@trolltech.com>
3 Date: Tue, 1 Dec 2009 09:18:47 +0100
4 Subject: [PATCH 0860/1244] Added caching of vectorpaths to the GL paint engine.
5
6 The first time a path is drawn we call makeCachable on the path, which
7 means that if it is drawn again, we start caching it. This is a bit of
8 a trick to avoid caching paths that are drawn once and discared while
9 at the same time cache paths that are reused automatically.
10
11 The GL engine owns the vertex information and is responsible for cleaning
12 it up. If the vectorpath is destroyed first, it will call the cleanup function.
13 if the engine dies first, we still require some hooks to clean up the cache
14 in the path. More to come. When VBO's are used, these will be a leaked if the
15 path is destroyed after the engine.
16
17 Reviewed-by: Samuel
18 ---
19  src/gui/painting/qpaintengineex.cpp                |   16 +++-
20  src/gui/painting/qvectorpath_p.h                   |   13 ++-
21  src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h |    2 +
22  .../gl2paintengineex/qpaintengineex_opengl2.cpp    |  115 +++++++++++++++++++-
23  .../gl2paintengineex/qpaintengineex_opengl2_p.h    |    4 +
24  5 files changed, 139 insertions(+), 11 deletions(-)
25
26 diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
27 index 7d1c109..9a0e319 100644
28 --- a/src/gui/painting/qpaintengineex.cpp
29 +++ b/src/gui/painting/qpaintengineex.cpp
30 @@ -56,6 +56,20 @@ QT_BEGIN_NAMESPACE
31   * class QVectorPath
32   *
33   */
34 +QVectorPath::~QVectorPath()
35 +{
36 +    if (m_hints & ShouldUseCacheHint) {
37 +        CacheEntry *e = m_cache;
38 +        while (e) {
39 +            if (e->data)
40 +                e->cleanup(e->engine, e->data);
41 +            CacheEntry *n = e->next;
42 +            delete e;
43 +            e = n;
44 +        }
45 +    }
46 +}
47 +
48  
49  QRectF QVectorPath::controlPointRect() const
50  {
51 @@ -94,7 +108,7 @@ QRectF QVectorPath::controlPointRect() const
52  
53  
54  QVectorPath::CacheEntry *QVectorPath::addCacheData(QPaintEngineEx *engine, void *data,
55 -                                                   qvectorpath_cache_cleanup cleanup) {
56 +                                                   qvectorpath_cache_cleanup cleanup) const{
57      Q_ASSERT(!lookupCacheData(engine));
58      if ((m_hints & IsCachedHint) == 0) {
59          m_cache = 0;
60 diff --git a/src/gui/painting/qvectorpath_p.h b/src/gui/painting/qvectorpath_p.h
61 index ec27970..5eaddf4 100644
62 --- a/src/gui/painting/qvectorpath_p.h
63 +++ b/src/gui/painting/qvectorpath_p.h
64 @@ -68,7 +68,7 @@ QT_MODULE(Gui)
65  
66  class QPaintEngineEx;
67  
68 -typedef void (*qvectorpath_cache_cleanup)(void *data);
69 +typedef void (*qvectorpath_cache_cleanup)(QPaintEngineEx *engine, void *data);
70  
71  struct QRealRect {
72      qreal x1, y1, x2, y2;
73 @@ -118,6 +118,8 @@ public:
74      {
75      }
76  
77 +    ~QVectorPath();
78 +
79      QRectF controlPointRect() const;
80  
81      inline Hint shape() const { return (Hint) (m_hints & ShapeMask); }
82 @@ -128,6 +130,7 @@ public:
83      inline bool hasImplicitClose() const { return m_hints & ImplicitClose; }
84      inline bool hasWindingFill() const { return m_hints & WindingFill; }
85  
86 +    inline void makeCacheable() const { m_hints |= ShouldUseCacheHint; m_cache = 0; }
87      inline uint hints() const { return m_hints; }
88  
89      inline const QPainterPath::ElementType *elements() const { return m_elements; }
90 @@ -146,9 +149,9 @@ public:
91          CacheEntry *next;
92      };
93  
94 -    CacheEntry *addCacheData(QPaintEngineEx *engine, void *data, qvectorpath_cache_cleanup cleanup);
95 +    CacheEntry *addCacheData(QPaintEngineEx *engine, void *data, qvectorpath_cache_cleanup cleanup) const;
96      inline CacheEntry *lookupCacheData(QPaintEngineEx *engine) const {
97 -        Q_ASSERT(m_hints & IsCachedHint);
98 +        Q_ASSERT(m_hints & ShouldUseCacheHint);
99          CacheEntry *e = m_cache;
100          while (e) {
101              if (e->engine == engine)
102 @@ -162,14 +165,14 @@ public:
103  private:
104      Q_DISABLE_COPY(QVectorPath)
105  
106 -    CacheEntry *m_cache;
107 -
108      const QPainterPath::ElementType *m_elements;
109      const qreal *m_points;
110      const int m_count;
111  
112      mutable uint m_hints;
113      mutable QRealRect m_cp_rect;
114 +
115 +    mutable CacheEntry *m_cache;
116  };
117  
118  Q_GUI_EXPORT const QVectorPath &qtVectorPathForPath(const QPainterPath &path);
119 diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
120 index 03aec17..98eaa91 100644
121 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
122 +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
123 @@ -112,6 +112,8 @@ public:
124      int stopCount() const { return vertexArrayStops.size(); }
125      QGLRect         boundingRect() const;
126  
127 +    int vertexCount() const { return vertexArray.size(); }
128 +
129      void lineToArray(const GLfloat x, const GLfloat y);
130  
131  private:
132 diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
133 index 6a708b4..3fce384 100644
134 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
135 +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
136 @@ -62,6 +62,8 @@
137      and use the correct program when we really need it.
138  */
139  
140 +// #define QT_OPENGL_CACHE_AS_VBOS
141 +
142  #include "qpaintengineex_opengl2_p.h"
143  
144  #include <string.h> //for memcpy
145 @@ -344,6 +346,13 @@ extern QImage qt_imageForBrush(int brushStyle, bool invert);
146  QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate()
147  {
148      delete shaderManager;
149 +
150 +    while (pathCaches.size()) {
151 +        QVectorPath::CacheEntry *e = *(pathCaches.constBegin());
152 +        e->cleanup(e->engine, e->data);
153 +        e->data = 0;
154 +        e->engine = 0;
155 +    }
156  }
157  
158  void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
159 @@ -846,6 +855,30 @@ void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
160      mode = newMode;
161  }
162  
163 +struct QGL2PEVectorPathCache
164 +{
165 +#ifdef QT_OPENGL_CACHE_AS_VBOS
166 +    GLuint vbo;
167 +#else
168 +    float *vertices;
169 +#endif
170 +    int vertexCount;
171 +    GLenum primitiveType;
172 +    qreal iscale;
173 +};
174 +
175 +void qopengl2paintengine_cleanup_vectorpath(QPaintEngineEx *engine, void *data)
176 +{
177 +    QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data;
178 +#ifdef QT_OPENGL_CACHE_AS_VBOS
179 +    QGL2PaintEngineExPrivate *d = QGL2PaintEngineExPrivate::getData((QGL2PaintEngineEx *) engine);
180 +    d->unusedVBOSToClean << c->vbo;
181 +#else
182 +    qFree(c->vertices);
183 +#endif
184 +    delete c;
185 +}
186 +
187  // Assumes everything is configured for the brush you want to use
188  void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
189  {
190 @@ -863,10 +896,74 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
191          prepareForDraw(currentBrush->isOpaque());
192          composite(rect);
193      } else if (path.isConvex()) {
194 -        vertexCoordinateArray.clear();
195 -        vertexCoordinateArray.addPath(path, inverseScale, false);
196 -        prepareForDraw(currentBrush->isOpaque());
197 -        drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
198 +
199 +        if (path.isCacheable()) {
200 +            QVectorPath::CacheEntry *data = path.lookupCacheData(q);
201 +            QGL2PEVectorPathCache *cache;
202 +
203 +            if (data) {
204 +                cache = (QGL2PEVectorPathCache *) data->data;
205 +                // Check if scale factor is exceeded for curved paths and generate curves if so...
206 +                if (path.isCurved()) {
207 +                    qreal scaleFactor = cache->iscale / inverseScale;
208 +                    if (scaleFactor < 0.5 || scaleFactor > 2.0) {
209 +#ifdef QT_OPENGL_CACHE_AS_VBOS
210 +                        glDeleteBuffers(1, &cache->vbo);
211 +                        cache->vbo = 0;
212 +#else
213 +                        qFree(cache->vertices);
214 +#endif
215 +                        cache->vertexCount = 0;
216 +                    }
217 +                }
218 +            } else {
219 +                cache = new QGL2PEVectorPathCache;
220 +                cache->vertexCount = 0;
221 +                data = const_cast<QVectorPath &>(path).addCacheData(q, cache, qopengl2paintengine_cleanup_vectorpath);
222 +            }
223 +
224 +            // Flatten the path at the current scale factor and fill it into the cache struct.
225 +            if (!cache->vertexCount) {
226 +                vertexCoordinateArray.clear();
227 +                vertexCoordinateArray.addPath(path, inverseScale, false);
228 +                int vertexCount = vertexCoordinateArray.vertexCount();
229 +                int floatSizeInBytes = vertexCount * 2 * sizeof(float);
230 +                cache->vertexCount = vertexCount;
231 +                cache->primitiveType = GL_TRIANGLE_FAN;
232 +                cache->iscale = inverseScale;               
233 +#ifdef QT_OPENGL_CACHE_AS_VBOS
234 +                glGenBuffers(1, &cache->vbo);
235 +                glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
236 +                glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW);
237 +#else
238 +                cache->vertices = (float *) qMalloc(floatSizeInBytes);
239 +                memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
240 +#endif
241 +            }
242 +
243 +            prepareForDraw(currentBrush->isOpaque());
244 +            glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
245 +#ifdef QT_OPENGL_CACHE_AS_VBOS
246 +            glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
247 +            glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0);
248 +#else
249 +            glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, cache->vertices);
250 +#endif
251 +            glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
252 +
253 +        } else {
254 +      //        printf(" - Marking path as cachable...\n");
255 +            // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable
256 +            // ### Remove before release...
257 +            static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty();
258 +            if (do_vectorpath_cache)
259 +                path.makeCacheable();
260 +            vertexCoordinateArray.clear();
261 +            vertexCoordinateArray.addPath(path, inverseScale, false);
262 +            prepareForDraw(currentBrush->isOpaque());
263 +            drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
264 +        }
265 +
266      } else {
267          // The path is too complicated & needs the stencil technique
268          vertexCoordinateArray.clear();
269 @@ -1756,7 +1853,8 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
270      d->device->beginPaint();
271  
272  #if !defined(QT_OPENGL_ES_2)
273 -    bool success = qt_resolve_version_2_0_functions(d->ctx);
274 +    bool success = qt_resolve_version_2_0_functions(d->ctx)
275 +                   && qt_resolve_buffer_extensions(d->ctx);
276      Q_ASSERT(success);
277      Q_UNUSED(success);
278  #endif
279 @@ -1817,6 +1915,13 @@ bool QGL2PaintEngineEx::end()
280      delete d->shaderManager;
281      d->shaderManager = 0;
282  
283 +#ifdef QT_OPENGL_CACHE_AS_VBOS
284 +    if (!d->unusedVBOSToClean.isEmpty()) {
285 +        glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData());
286 +        d->unusedVBOSToClean.clear();
287 +    }
288 +#endif
289 +
290      return false;
291  }
292  
293 diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
294 index b554f6d..0084476 100644
295 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
296 +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
297 @@ -221,6 +221,7 @@ public:
298      void restoreDepthRangeForRenderText();
299  
300      static QGLEngineShaderManager* shaderManagerForEngine(QGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; }
301 +    static QGL2PaintEngineExPrivate *getData(QGL2PaintEngineEx *engine) { return engine->d_func(); }
302  
303      QGL2PaintEngineEx* q;
304      QGLPaintDevice* device;
305 @@ -294,6 +295,9 @@ public:
306      QScopedPointer<QPixmapFilter> fastBlurFilter;
307      QScopedPointer<QPixmapFilter> dropShadowFilter;
308      QScopedPointer<QPixmapFilter> fastDropShadowFilter;
309 +
310 +    QSet<QVectorPath::CacheEntry *> pathCaches;
311 +    QVector<GLuint> unusedVBOSToClean;
312  };
313  
314  QT_END_NAMESPACE
315 -- 
316 1.6.5
317