Merge lp:~adamreichold/qpdfview/track-exposed-tiles into lp:qpdfview

Proposed by Adam Reichold
Status: Merged
Merged at revision: 1858
Proposed branch: lp:~adamreichold/qpdfview/track-exposed-tiles
Merge into: lp:qpdfview
Diff against target: 74 lines (+20/-4)
2 files modified
sources/pageitem.cpp (+18/-4)
sources/pageitem.h (+2/-0)
To merge this branch: bzr merge lp:~adamreichold/qpdfview/track-exposed-tiles
Reviewer Review Type Date Requested Status
Razi Alavizadeh Pending
Review via email: mp+248199@code.launchpad.net

Description of the change

After noticing that the interface begins to "stutter" using high scale factors (roughly above 1000%) and isolating this to using tiling and continuous layout, I noticed during profiling that cancellation has a pretty large overhead. This was somewhat reduced by making sure that the atomic operations to set cancellation were inlined, but even then the atomic operations to cancel and to reset instances of "QPixmap" are still noticable.

It seems the main cause of this is the document view calling "PageItem::cancelRender" on all not-visible page items and with a high scale factor implying a large number of tiles (e.g. 500 tiles per page at 1200%), this easily yields 100000 tiles being cancelled even though rendering on them was not active at all.

This branch tries to alleviate the issue by making the page item explicitly track the exposed tiles and letting the document view cancel only those (for non-force cancellation, i.e. without interrupting prefetching which in itself is a problem with a high tile count) that were actually exposed. The page item itself will also cancel tiles when and only when they are removed from the set of exposed tiles which again reduces the number of pointless cancellation attempts.

The necessary changes are pretty limited, but as they touch a very fundamental function of the program, I would be grateful for a review and test by another developer.

To post a comment you must log in.
1858. By Adam Reichold

Also clear set of exposed tiles after cancellation.

1859. By Adam Reichold

Remerge with trunk to suppress unrelated change.

Revision history for this message
Adam Reichold (adamreichold) wrote :

Maybe we should also consider making "TileItem::cancelRender" inline since even after these optimizations, it shows up on top of gprof's list. I strongly dislike this since it exposes the "RenderTask" internals of "TileItem", but then again "tileitem.h" (and hence indirectly "rendertask.h") are included into "tileitem.cpp" and "pageitem.cpp" only.

It seems like a sensible and pratically free optimization, but it also does not seem to noticeably reduce the "stutter" in any way, so I am very much unsure about it.

Revision history for this message
Razi Alavizadeh (srazi) wrote :

Your patch seems OK. but I didn't see a big difference here. I think maybe the solution is using a limit for number of "tile"s? Because when testing this branch I found that when using a high scale e.g. 1200% "qpdfview.exe" uses more than 120,000 handles and if I change scale factor to 1933% there will be more than 300,000 handles used by qpdfview.exe

Revision history for this message
Adam Reichold (adamreichold) wrote :

Hello,

that's strange as on my system this patch made the difference between stuttering and being able to set that we might need better double-buffering as well. :-\

When you say handles, I suppose you mean Windows HANDLE data type? Do you to which kind of resource these handles refered?

In any case, I think adapting the tile size would be nicer than a hard limit, e.g. using 16 MB instead of 4 MB tiles above some specific number of tiles per page. I am not sure whether I will implement this for 0.4.14 depending on how difficult it is.

In any case, I'll merge this and make "TileItem::cancelRender" inline. I also think the signal-slot invocation using "QTimer::singleShot" within "TileItem::deleteAfterRender" could be replaced by a simple flag to further reduce overhead.

Thanks for the review! Best regards, Adam.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'sources/pageitem.cpp'
2--- sources/pageitem.cpp 2015-02-01 13:27:13 +0000
3+++ sources/pageitem.cpp 2015-02-01 13:33:19 +0000
4@@ -334,10 +334,12 @@
5 }
6 else
7 {
8- foreach(TileItem* tile, m_tileItems)
9+ foreach(TileItem* tile, m_exposedTileItems)
10 {
11 tile->cancelRender();
12 }
13+
14+ m_exposedTileItems.clear();
15 }
16 }
17
18@@ -1121,6 +1123,8 @@
19 m_tileItems.replace(index, new TileItem(this));
20 }
21
22+ m_exposedTileItems.clear();
23+
24 if(oldCount != newCount)
25 {
26 foreach(TileItem* tile, m_tileItems)
27@@ -1173,15 +1177,25 @@
28
29 foreach(TileItem* tile, m_tileItems)
30 {
31- if(translatedExposedRect.intersects(tile->rect()))
32+ const bool intersects = translatedExposedRect.intersects(tile->rect());
33+ const bool contains = m_exposedTileItems.contains(tile);
34+
35+ if(intersects && !contains)
36 {
37- tile->paint(painter, m_boundingRect.topLeft());
38+ m_exposedTileItems.insert(tile);
39 }
40- else
41+ else if(!intersects && contains)
42 {
43+ m_exposedTileItems.remove(tile);
44+
45 tile->cancelRender();
46 }
47 }
48+
49+ foreach(TileItem* tile, m_exposedTileItems)
50+ {
51+ tile->paint(painter, m_boundingRect.topLeft());
52+ }
53 }
54
55 if(s_settings->pageItem().decoratePages() && !presentationMode())
56
57=== modified file 'sources/pageitem.h'
58--- sources/pageitem.h 2014-11-15 11:12:55 +0000
59+++ sources/pageitem.h 2015-02-01 13:33:19 +0000
60@@ -25,6 +25,7 @@
61 #include <QCache>
62 #include <QGraphicsObject>
63 #include <QIcon>
64+#include <QSet>
65
66 class QGraphicsProxyWidget;
67
68@@ -210,6 +211,7 @@
69 void prepareGeometry();
70
71 QVector< TileItem* > m_tileItems;
72+ mutable QSet< TileItem* > m_exposedTileItems;
73
74 void prepareTiling();
75

Subscribers

People subscribed via source and target branches

to all changes: