Details
-
Bug
-
Resolution: Done
-
P2: Important
-
None
-
5.4.2, 5.5.0
-
None
-
c2ea62dd342ced6da3a634768c4d92dc3067a3fa
Description
Drawing on a QPicture is very slow when a complex and large clip path is set. The attached benchmark shows how the time for drawing a point varies with the extension (0.001, 1.0, 1000.0) and the magnitude of segments (1, 100, 10000) of the clip path:
********* Start testing of PicturePaintTest ********* Config: Using QtTest library 5.4.0, Qt 5.4.0 (x86_64-little_endian-lp64 shared (dynamic) debug build; by GCC 4.8.2) PASS : PicturePaintTest::initTestCase() PASS : PicturePaintTest::complexClipTest(0.001/1) RESULT : PicturePaintTest::complexClipTest():"0.001/1": 0.031 msecs per iteration (total: 65, iterations: 2048) PASS : PicturePaintTest::complexClipTest(0.001/100) RESULT : PicturePaintTest::complexClipTest():"0.001/100": 0.070 msecs per iteration (total: 72, iterations: 1024) PASS : PicturePaintTest::complexClipTest(0.001/10000) RESULT : PicturePaintTest::complexClipTest():"0.001/10000": 3.7 msecs per iteration (total: 60, iterations: 16) PASS : PicturePaintTest::complexClipTest(1.0/1) RESULT : PicturePaintTest::complexClipTest():"1.0/1": 0.031 msecs per iteration (total: 64, iterations: 2048) PASS : PicturePaintTest::complexClipTest(1.0/100) RESULT : PicturePaintTest::complexClipTest():"1.0/100": 0.15 msecs per iteration (total: 79, iterations: 512) PASS : PicturePaintTest::complexClipTest(1.0/10000) RESULT : PicturePaintTest::complexClipTest():"1.0/10000": 1,137 msecs per iteration (total: 1,137, iterations: 1) PASS : PicturePaintTest::complexClipTest(1000/1) RESULT : PicturePaintTest::complexClipTest():"1000/1": 0.081 msecs per iteration (total: 83, iterations: 1024) PASS : PicturePaintTest::complexClipTest(1000/100) RESULT : PicturePaintTest::complexClipTest():"1000/100": 38 msecs per iteration (total: 76, iterations: 2) PASS : PicturePaintTest::complexClipTest(1000/10000) RESULT : PicturePaintTest::complexClipTest():"1000/10000": 9,026 msecs per iteration (total: 9,026, iterations: 1) PASS : PicturePaintTest::cleanupTestCase() Totals: 11 passed, 0 failed, 0 skipped, 0 blacklisted ********* Finished testing of PicturePaintTest *********
This is 0.000031 vs. 9 seconds for drawing a single point.
This was uncovered by a sudden slowdown of Qt's print preview dialog when scaling the logical coordinate system by 1000 in our application. Other paint devices (screen, printer, image) were not affected.
Debugging and code analysis suggest that the bottleneck is calling painter()->clipRegion() in QPicturePaintEngine::writeCmdLength. QPainter::clipRegion() is documented to be potentially expensive. It does a lot of vector resizing and copying in order to determine the clip region from the clip path, and it uses only the integer part of the coordinates.
However, this expensive call is probably not neccessary because QPicturePaintEngine::writeCmdLength uses nothing but the bounding rect of the clip, and there is another method QPainter::clipBoundingRect (since Qt 4.8) which does not promise to return an exact (tight) bound but delivers the result quickly also for complex large clip paths. Experimentation with the proposed method shows acceptable results in both this benchmark and the application print preview.
Config: Using QtTest library 5.4.0, Qt 5.4.0 (x86_64-little_endian-lp64 shared (dynamic) debug build; by GCC 4.8.2) PASS : PicturePaintTest::initTestCase() PASS : PicturePaintTest::complexClipTest(0.001/1) RESULT : PicturePaintTest::complexClipTest():"0.001/1": 0.025 msecs per iteration (total: 53, iterations: 2048) PASS : PicturePaintTest::complexClipTest(0.001/100) RESULT : PicturePaintTest::complexClipTest():"0.001/100": 0.026 msecs per iteration (total: 55, iterations: 2048) PASS : PicturePaintTest::complexClipTest(0.001/10000) RESULT : PicturePaintTest::complexClipTest():"0.001/10000": 0.025 msecs per iteration (total: 53, iterations: 2048) PASS : PicturePaintTest::complexClipTest(1.0/1) RESULT : PicturePaintTest::complexClipTest():"1.0/1": 0.025 msecs per iteration (total: 52, iterations: 2048) PASS : PicturePaintTest::complexClipTest(1.0/100) RESULT : PicturePaintTest::complexClipTest():"1.0/100": 0.025 msecs per iteration (total: 52, iterations: 2048) PASS : PicturePaintTest::complexClipTest(1.0/10000) RESULT : PicturePaintTest::complexClipTest():"1.0/10000": 0.027 msecs per iteration (total: 57, iterations: 2048) PASS : PicturePaintTest::complexClipTest(1000/1) RESULT : PicturePaintTest::complexClipTest():"1000/1": 0.026 msecs per iteration (total: 54, iterations: 2048) PASS : PicturePaintTest::complexClipTest(1000/100) RESULT : PicturePaintTest::complexClipTest():"1000/100": 0.029 msecs per iteration (total: 61, iterations: 2048) PASS : PicturePaintTest::complexClipTest(1000/10000) RESULT : PicturePaintTest::complexClipTest():"1000/10000": 0.026 msecs per iteration (total: 55, iterations: 2048) PASS : PicturePaintTest::cleanupTestCase() Totals: 11 passed, 0 failed, 0 skipped, 0 blacklisted ********* Finished testing of PicturePaintTest *********
Is there any argument against switching to QPainter::clipBoundingRect()?
Attachments
For Gerrit Dashboard: QTBUG-46578 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
114259,3 | QPicturePaintEngine: Avoid slow QPainter::clipRegion | 5.5 | qt/qtbase | Status: MERGED | +2 | 0 |