From 14a8f1fb7414885cc3868b1d27699b5a0d59e7ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Wed, 7 Oct 2009 14:59:34 +0200 Subject: Optimized rasterizing of paths using stencil method in GL 2 engine. Making the triangle fan of each sub path start at the sub path's centroid will on average improve performance for complex paths, because less pixels that are outside the path need to be touched. The centroid is a more balanced choice than just picking the first element of the sub path as triangle fan origin. A performance improvement of 20 % was measured for star formed paths. Reviewed-by: Trond --- src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp | 37 +++++++++++++++++++++- src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h | 5 ++- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 6 ++-- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp index 866d1a2..1fe3999 100644 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp @@ -67,7 +67,30 @@ void QGL2PEXVertexArray::addRect(const QRectF &rect) << rect.bottomRight() << rect.bottomLeft() << rect.topLeft(); } -void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale) +void QGL2PEXVertexArray::addClosingLine(int index) +{ + if (QPointF(vertexArray.at(index)) != QPointF(vertexArray.last())) + vertexArray.add(vertexArray.at(index)); +} + +void QGL2PEXVertexArray::addCentroid(const QVectorPath &path, int subPathIndex) +{ + const QPointF *const points = reinterpret_cast(path.points()); + const QPainterPath::ElementType *const elements = path.elements(); + + QPointF sum = points[subPathIndex]; + int count = 1; + + for (int i = subPathIndex + 1; i < path.elementCount() && (!elements || elements[i] != QPainterPath::MoveToElement); ++i) { + sum += points[i]; + ++count; + } + + const QPointF centroid = sum / qreal(count); + vertexArray.add(centroid); +} + +void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline) { const QPointF* const points = reinterpret_cast(path.points()); const QPainterPath::ElementType* const elements = path.elements(); @@ -78,6 +101,10 @@ void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseSc boundingRectDirty = false; } + if (!outline) + addCentroid(path, 0); + + int lastMoveTo = vertexArray.size(); vertexArray.add(points[0]); // The first element is always a moveTo do { @@ -96,8 +123,14 @@ void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseSc const QPainterPath::ElementType elementType = elements[i]; switch (elementType) { case QPainterPath::MoveToElement: + if (!outline) + addClosingLine(lastMoveTo); // qDebug("element[%d] is a MoveToElement", i); vertexArrayStops.append(vertexArray.size()); + if (!outline) { + addCentroid(path, i); + lastMoveTo = vertexArray.size(); + } lineToArray(points[i].x(), points[i].y()); // Add the moveTo as a new vertex break; case QPainterPath::LineToElement: @@ -115,6 +148,8 @@ void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseSc } } while (0); + if (!outline) + addClosingLine(lastMoveTo); vertexArrayStops.append(vertexArray.size()); } diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h index 08ce234..719904f 100644 --- a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h +++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h @@ -104,7 +104,7 @@ public: boundingRectDirty(true) {} void addRect(const QRectF &rect); - void addPath(const QVectorPath &path, GLfloat curveInverseScale); + void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true); void clear(); QGLPoint* data() {return vertexArray.data();} @@ -124,6 +124,9 @@ private: bool boundingRectDirty; inline void curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale); + + void addClosingLine(int index); + void addCentroid(const QVectorPath &path, int subPathIndex); }; QT_END_NAMESPACE diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index b3638ff..ab02c69 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -880,13 +880,13 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) || path.shape() == QVectorPath::ConvexPolygonHint) { vertexCoordinateArray.clear(); - vertexCoordinateArray.addPath(path, inverseScale); + 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(); - vertexCoordinateArray.addPath(path, inverseScale); + vertexCoordinateArray.addPath(path, inverseScale, false); fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); @@ -1825,7 +1825,7 @@ void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value) glStencilFunc(GL_ALWAYS, 0, 0xff); vertexCoordinateArray.clear(); - vertexCoordinateArray.addPath(path, inverseScale); + vertexCoordinateArray.addPath(path, inverseScale, false); if (!singlePass) fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); -- cgit v0.12