| Introduction
| |
What's that flickering ?
This document and provided patches are focused on reducing the visual effect that
people names 'flicker'. Even if you have a 300MHz cpu or a high end 3GHz processor
you can notice it. It might sound stange, but the latter case is 'visually' the worst because
people will perceive the screen 'flickering' (and say: "i hate X" :-) while the proud
owners of the 300MHz cpu will perceive it as what it really is: a repaint!
Where do the flickering comes from ?
Basically I found 3 classes of problems on our lovely widgets that lead into flickering
and visual performance degradation:
- graphics updates to the screen while a paint operation is in progress
example: updating the framebuffer composting a 3 layer image with unpredictable
random repainting of the screen (so you'll see the image growing from the background).
- uncorrectly handling/redundant paint operations
example: draw a first block, then a second, then a third, ..., then draw all
the widget! (in that case only the last operation should be performed)
- excessive repainting
example: for (10 times) { draw_the_same_thing! };
Only the first case represents the real flickering and it can be solved by buffering
drawing operations so slow composting can be done on a pixmap and then blitted to
the screen in a small time slot between 2 consecutive X refreshes.
The second case requires identifying unuseful paint operations (to be suppressed) and
optimize the graphical flow and the third case requires it too.
How to debug ? And what have you sorted out ?
Just a little note: to be able to catch the problem I changed the cpu frequency to 316.6 MHz
and ran konqueror under valgrind! (That means: you see konqueror painted to the screen
pixel by pixel and you're slow enough to debug ^_^). When opening a flat konqueror and
clicking on the 'home' button I got the following paint operations:
| 2 | complete redraws (only background) |
| 25 | small 'blank' areas with the same size of the 25 items (in my dir)
think at what will happen in a large directory.. below is the answer |
| 2 | complete redraws (all icons but no previews) |
| 1 | draw of the top-left corner icon (with 'focus' rectangle this time) |
| 3 | draws of the previews at the right place |
Ok, I see icons in konqy, where is the code that draws them?
QWidget |
|
QFrame |
|
QScrollView |
|
QIconView |
|
KIconView |
|
KonqIconViewWidget |
| |
From now on we'll focus on the konqueror window. When you browse your filesystem in
the IconView mode (and in the MultiColumn mode too) what you see is the KonqKfmIconView
at work. That class inherits the browsing function from KonqDirPart and represents
data using it's internal KonqIconViewWidget.
Here is the inheritance diagram; please note that flickering is introduced at some
points in that chain. |
|
| Gimme the patches now!
(I can't wait to screw up my system! :-)
| |
- 5 patches available
- 0 things are being investigated (maybe kdesktop repaints in the future)
| 01
Buffering paint operations on IconViews |
| Addition: removes flicker on: icon selection/hover, repaints,
... |
Let's take a look at the inheritance chain. A repaint/update operation that occours in
the iconview (Q/K/KonqW) is handled by the QScrollView's internal
function 'viewportPaintEvent'. Here the painter gets opened to the viewport widget (the
main area of the scrollview). This acts like a screen.. the opened painter is passed to
the QIconView or deeper childs via 'drawContents' and 'drawBackground' calls.
Inside that functions, the QIconView iterates over its 'icons' to draw them.
|
In the following patch, paint events on QIconView are caught internally and processed in a
function called 'bufferedPaintEvent()'. This opens a painter to a pixmap
and passes it to the 'drawContents' functions instead of opening the painter
directly to the screen surface. Only that class and its derivates will be doublebuffered.
01
qiconview_buffered.patch
|
| 02
No repaint on activation - Sent to Qt |
| BugFix: 1 wasted repaint when window loses/gains focus (and maybe more..) |
A complete repaint is made when a window containing a QIconView loses/gains focus.
This is generated only if the 'viewport' of the QScrollView was set to have a picture in
the background. (Try to switch between 2 konqueror windows in iconview mode. You'll notice
the flickering only when the background is set to a pixmap and not if is set to a color).
|
The following patch fixes the problem that I discovered to be a bug() of the QScrollview's
viewport.
02
qscrollview_fixwindowactivate.patch
|
| 03
Saving *lots* of paint operations - Applied in CVS |
| BugFix: wasted paints when displaying icons |
Here comes a very small patch that leads to big speed
increase when browsing large directories. If you take a look at the
table with paint operations you'll see what I saw in the right picture:
for each item in the directory a paint operation is performed on the top-left
corner of the iconview. Fixes introduced with this patch:
- loading times of a 600 files directory went down from ~0.5 to ~0.2 s on
a 2.6GHz processor and from 3.2 to 1.3 seconds on a 300MHz processor.
(tested with the antiflicker patch; the gain will be lower without it,
but we're always talking about a 2x .. 3x speed increase, not some percents :-P)
- the 'mistery of the top-left item flickering' now solved.
- I'm now noticing great visual and speed improvements on the file search dialog!
|
The patch acts by disabling the updates while inserting items in the iconview,
so this will block paint calls raised in the meanwhile.
03
konqiconview_fixsingleupdates.patch
|
| 04
Strange flicker: unsorted frame - Applied in CVS |
| BugFix: 1 wasted paint (with bad placed icons) |
This patch removes an annoying visual
artifact that shows up sometimes when browsing your filesystem. Sometimes
this is preceived as flickering on fast machines, but on slower processor you're
able to see "icons in the wrong place (or order) for a short amount of time".
For example, if a directory will be rendered this way, you
can catch for a while (maybe some milliseconds) this image.
|
The patch reorders some instructions, so they work in the right
order preventing a paint operation before the view gets sorted.
04
konqiconview_fixbadsort.patch
|
| 05/06
Disable clearing background - Applied in CVS |
| Addition: don't display an empty background before directory
contents |
This patch removes an annoying visual
artifact that shows up when changing URL. In fact, you see that the viewport gets
cleared and the filled up with icons. So it will be useful (and looks so good to me) to
remove that "blank paints", so folders are displayed with 'continuity' when browsing.
Here you can see a couple of pictures about the rendering before and after this patch:
| before |
 |
<- here you can see that background is painted 3 times and then the first icon is painted |
| after |
 |
<- here you can see that background is painted only one time |
|
NOTE: To apply this patch you must also apply patches 03 + 04
The patch disables graphics updates on the viewport during some calls that
may clear the viewport and re-enables updates after that calls.
05
konqiconview_noclearing.patch
Added the following patch: it clears the viewport after a timeout if the update
is taking too long.
06
konqiconview_cleartimeout.patch
|
|
| Conclusions
| |
You might be interested in seeing the current (re)paint list when updating the view:
| 1 | complete redraw |
| 3 | draws of the previews at the right place |
I'm currently running a konqueror with all the patches applied and .. I'm feeling sort
of BORED about konqueror's Anti-Flickerness ^_^ (kidding). No more wait-before-content-appears
no more flashing icons, no more blinking on window change, .. what will catch my attention now??
Let's revert! :-)
/really now/ -> Try this patches, they're simple but they SpEEdS and C00LS up your browsing :-P
|