[krita] /: Fix "openGL lag at zoom 2000 + rotation"

Dmitry Kazakov dimula73 at gmail.com
Fri Mar 25 12:09:44 UTC 2016


Git commit 08fd3aa8e554557728f60f8571e51364070c09e8 by Dmitry Kazakov.
Committed on 25/03/2016 at 12:08.
Pushed by dkazakov into branch 'master'.

Fix "openGL lag at zoom 2000 + rotation"

The problem was not related to the openGL actualy. It was caused
by the implementation of QPainter::clipRegion() which generated
20k+ rectangles from a rotated rect when rotation angle was near to
a 0 or 90deg.

WARNING for the future:
Never use QPainter::clipRegion(). Use KisPaintingUtils::safeClipRegion()
instead. It workarounds the issue returning a bit bigger rect.

Fixes T1446
BUG:355104
CC:kimageshop at kde.org

M  +3    -1    libs/flake/KoShapeContainer.cpp
M  +3    -1    libs/flake/KoShapeManager.cpp
M  +0    -3    libs/flake/tools/KoCreateShapeStrategy.cpp
M  +0    -2    libs/flake/tools/KoShapeRubberSelectStrategy.cpp
M  +1    -0    libs/global/CMakeLists.txt
A  +51   -0    libs/global/kis_painting_tweaks.cpp     [License: GPL (v2+)]
A  +45   -0    libs/global/kis_painting_tweaks.h     [License: GPL (v2+)]
M  +4    -1    plugins/flake/textshape/TextShape.cpp
M  +2    -1    plugins/flake/textshape/textlayout/KoTextLayoutArea_paint.cpp
M  +3    -1    plugins/flake/vectorshape/VectorShape.cpp

http://commits.kde.org/krita/08fd3aa8e554557728f60f8571e51364070c09e8

diff --git a/libs/flake/KoShapeContainer.cpp b/libs/flake/KoShapeContainer.cpp
index 74cdb23..411098c 100644
--- a/libs/flake/KoShapeContainer.cpp
+++ b/libs/flake/KoShapeContainer.cpp
@@ -29,6 +29,8 @@
 #include <QPainter>
 #include <QPainterPath>
 
+#include "kis_painting_tweaks.h"
+
 KoShapeContainerPrivate::KoShapeContainerPrivate(KoShapeContainer *q)
     : KoShapePrivate(q),
     model(0)
@@ -173,7 +175,7 @@ void KoShapeContainer::paint(QPainter &painter, const KoViewConverter &converter
     m.scale(zoomX, zoomY);
     painter.setClipPath(m.map(outline()), Qt::IntersectClip);
 
-    QRectF toPaintRect = converter.viewToDocument(painter.clipRegion().boundingRect());
+    QRectF toPaintRect = converter.viewToDocument(KisPaintingTweaks::safeClipBoundingRect(painter));
     toPaintRect = transform().mapRect(toPaintRect);
     // We'll use this clipRect to see if our child shapes lie within it.
     // Because shape->boundingRect() uses absoluteTransformation(0) we'll
diff --git a/libs/flake/KoShapeManager.cpp b/libs/flake/KoShapeManager.cpp
index f44d4be..6f861f1 100644
--- a/libs/flake/KoShapeManager.cpp
+++ b/libs/flake/KoShapeManager.cpp
@@ -48,6 +48,8 @@
 #include <QTimer>
 #include <FlakeDebug.h>
 
+#include "kis_painting_tweaks.h"
+
 
 void KoShapeManager::Private::updateTree()
 {
@@ -227,7 +229,7 @@ void KoShapeManager::paint(QPainter &painter, const KoViewConverter &converter,
 
     QList<KoShape*> unsortedShapes;
     if (painter.hasClipping()) {
-        QRectF rect = converter.viewToDocument(painter.clipRegion().boundingRect());
+        QRectF rect = converter.viewToDocument(KisPaintingTweaks::safeClipBoundingRect(painter));
         unsortedShapes = d->tree.intersects(rect);
     } else {
         unsortedShapes = shapes();
diff --git a/libs/flake/tools/KoCreateShapeStrategy.cpp b/libs/flake/tools/KoCreateShapeStrategy.cpp
index 7e6ef1a..054a56b 100644
--- a/libs/flake/tools/KoCreateShapeStrategy.cpp
+++ b/libs/flake/tools/KoCreateShapeStrategy.cpp
@@ -119,9 +119,6 @@ void KoCreateShapeStrategy::paint(QPainter &painter, const KoViewConverter &conv
         matrix.scale(xscale, yscale);
         painter.translate(paintRect.left(), paintRect.top());
 
-        if (painter.hasClipping())
-            paintRect = paintRect.intersect(painter.clipRegion().boundingRect());
-
         painter.setTransform(matrix, true);
         painter.drawPath(m_outline);
         painter.restore();
diff --git a/libs/flake/tools/KoShapeRubberSelectStrategy.cpp b/libs/flake/tools/KoShapeRubberSelectStrategy.cpp
index 8240593..0b0a0e8 100644
--- a/libs/flake/tools/KoShapeRubberSelectStrategy.cpp
+++ b/libs/flake/tools/KoShapeRubberSelectStrategy.cpp
@@ -52,8 +52,6 @@ void KoShapeRubberSelectStrategy::paint(QPainter &painter, const KoViewConverter
     QRectF paintRect = converter.documentToView(d->selectedRect());
     paintRect = paintRect.normalized();
     paintRect.adjust(0., -0.5, 0.5, 0.);
-    if (painter.hasClipping())
-        paintRect = paintRect.intersect(painter.clipRegion().boundingRect());
     painter.drawRect(paintRect);
 }
 
diff --git a/libs/global/CMakeLists.txt b/libs/global/CMakeLists.txt
index efb0d98..42a33fe 100644
--- a/libs/global/CMakeLists.txt
+++ b/libs/global/CMakeLists.txt
@@ -12,6 +12,7 @@ set(kritaglobal_LIB_SRCS
     kis_memory_leak_tracker.cpp
     kis_shared.cpp
     kis_dom_utils.cpp
+    kis_painting_tweaks.cpp
 )
 
 add_library(kritaglobal SHARED ${kritaglobal_LIB_SRCS} )
diff --git a/libs/global/kis_painting_tweaks.cpp b/libs/global/kis_painting_tweaks.cpp
new file mode 100644
index 0000000..1c59e1a
--- /dev/null
+++ b/libs/global/kis_painting_tweaks.cpp
@@ -0,0 +1,51 @@
+/*
+ *  Copyright (c) 2016 Dmitry Kazakov <dimula73 at gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "kis_painting_tweaks.h"
+
+#include <QRegion>
+#include <QPainter>
+#include <QTransform>
+
+#include "kis_debug.h"
+
+
+namespace KisPaintingTweaks {
+
+QRegion safeClipRegion(const QPainter &painter)
+{
+    const QTransform t = painter.transform();
+
+    QRegion region = t.type() <= QTransform::TxScale ?
+        painter.clipRegion() :
+        QRegion(painter.clipBoundingRect().toAlignedRect());
+
+    if (region.rectCount() > 1000) {
+        qWarning() << "WARNING: KisPaintingTweaks::safeClipRegion: too many rectangles in the region!" << ppVar(region.rectCount());
+        region = QRegion(painter.clipBoundingRect().toAlignedRect());
+    }
+
+    return region;
+}
+
+QRect safeClipBoundingRect(const QPainter &painter)
+{
+    return painter.clipBoundingRect().toAlignedRect();
+}
+
+}
diff --git a/libs/global/kis_painting_tweaks.h b/libs/global/kis_painting_tweaks.h
new file mode 100644
index 0000000..274cbad
--- /dev/null
+++ b/libs/global/kis_painting_tweaks.h
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2016 Dmitry Kazakov <dimula73 at gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KIS_PAINTING_TWEAKS_H
+#define __KIS_PAINTING_TWEAKS_H
+
+#include "kritaglobal_export.h"
+
+class QPainter;
+class QRegion;
+class QRect;
+
+namespace KisPaintingTweaks {
+
+    /**
+     * This is a workaround for QPainter::clipRegion() bug. When zoom
+     * is about 2000% and rotation is in a range[-5;5] degrees, the
+     * generated region will have about 20k+ regtangles inside. Their
+     * processing will be really slow. These functions fworkarounds
+     * the issue.
+     */
+    KRITAGLOBAL_EXPORT QRegion safeClipRegion(const QPainter &painter);
+
+    /**
+     * \see safeClipRegion()
+     */
+    KRITAGLOBAL_EXPORT QRect safeClipBoundingRect(const QPainter &painter);
+}
+
+#endif /* __KIS_PAINTING_TWEAKS_H */
diff --git a/plugins/flake/textshape/TextShape.cpp b/plugins/flake/textshape/TextShape.cpp
index 65b5ac3..7fdda74 100644
--- a/plugins/flake/textshape/TextShape.cpp
+++ b/plugins/flake/textshape/TextShape.cpp
@@ -63,6 +63,9 @@
 
 #include <QDebug>
 
+#include "kis_painting_tweaks.h"
+
+
 TextShape::TextShape(KoInlineTextObjectManager *inlineTextObjectManager, KoTextRangeManager *textRangeManager)
     : KoShapeContainer(new KoTextShapeContainerModel())
     , KoFrameShape(KoXmlNS::draw, "text-box")
@@ -137,7 +140,7 @@ void TextShape::paintComponent(QPainter &painter, const KoViewConverter &convert
         KoTextPage *page = m_pageProvider->page(this);
         if (page) {
             // this is used to not trigger repaints if layout during the painting is done
-            m_paintRegion = painter.clipRegion();
+            m_paintRegion = KisPaintingTweaks::safeClipRegion(painter);
             if (!m_textShapeData->rootArea()->page() || page->pageNumber() != m_textShapeData->rootArea()->page()->pageNumber()) {
                 m_textShapeData->rootArea()->setPage(page); // takes over ownership of the page
             } else {
diff --git a/plugins/flake/textshape/textlayout/KoTextLayoutArea_paint.cpp b/plugins/flake/textshape/textlayout/KoTextLayoutArea_paint.cpp
index 5d6860c..dbe749e 100644
--- a/plugins/flake/textshape/textlayout/KoTextLayoutArea_paint.cpp
+++ b/plugins/flake/textshape/textlayout/KoTextLayoutArea_paint.cpp
@@ -65,6 +65,7 @@
 #include <QTextLayout>
 #include <QTextCursor>
 #include <QTime>
+#include "kis_painting_tweaks.h"
 
 extern int qt_defaultDpiY();
 Q_DECLARE_METATYPE(QTextDocument *)
@@ -91,7 +92,7 @@ void KoTextLayoutArea::paint(QPainter *painter, const KoTextDocumentLayout::Pain
     painter->translate(0, d->verticalAlignOffset);
 
     painter->setPen(context.textContext.palette.color(QPalette::Text)); // for text that has no color.
-    const QRegion clipRegion = painter->clipRegion(); // fetch after painter->translate so the clipRegion is correct
+    const QRegion clipRegion = KisPaintingTweaks::safeClipRegion(*painter); // fetch after painter->translate so the clipRegion is correct
     KoTextBlockBorderData *lastBorder = 0;
     QRectF lastBorderRect;
 
diff --git a/plugins/flake/vectorshape/VectorShape.cpp b/plugins/flake/vectorshape/VectorShape.cpp
index 6e227df..2a80a5c 100644
--- a/plugins/flake/vectorshape/VectorShape.cpp
+++ b/plugins/flake/vectorshape/VectorShape.cpp
@@ -57,6 +57,8 @@
 #include "SvmParser.h"
 #include "SvmPainterBackend.h"
 
+#include "kis_painting_tweaks.h"
+
 // Comment out to get uncached painting, which is good for debugging
 //#define VECTORSHAPE_PAINT_UNCACHED
 
@@ -247,7 +249,7 @@ void VectorShape::paint(QPainter &painter, const KoViewConverter &converter, KoS
     QImage *cache = render(converter, asynchronous, useCache);
     if (cache) { // paint cached image
         Q_ASSERT(!cache->isNull());
-        QVector<QRect> clipRects = painter.clipRegion().rects();
+        QVector<QRect> clipRects = KisPaintingTweaks::safeClipRegion(painter).rects();
         foreach (const QRect &rc, clipRects) {
             painter.drawImage(rc.topLeft(), *cache, rc);
         }


More information about the kimageshop mailing list