summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/painting/qpaintengineex.cpp16
-rw-r--r--src/gui/painting/qvectorpath_p.h13
-rw-r--r--src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h2
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp115
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h4
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