Screen damage logic [was: Re: RE: Timers, Stepping, ...]
Dan.Ingalls at disney.com
Wed Mar 22 05:42:37 UTC 2000
>On Tue, 21 Mar 2000 20:20:26 -0500 "David Pennell" <dpennell at quallaby.com> wrote:
>>I have a very sparse Morph, like a diagonal line or a hollow polygon that
>>occupies a substantial part of the screen. Can I declare a list of smaller
>>dirty rectangles in order to speed up World redraw?
Bob Arning <arning at charm.net> replied...
>The unqualified answer is... maybe. Each morph that knows it has changed says:
> self invalidRect: self fullBounds
>which translates to:
> owner ifNotNil: [owner invalidRect: damageRect].
>which ultimately gets to the world which says
> self damageRecorder recordInvalidRect: damageRect
>which ends up (in DamageRecorder>>recordInvalidRect:) with:
>"Note: The totalRepaint policy has poor behavior when many local rectangles (such as parts of a text selection) force repaint of the entire screen. As an alternative, this code performs a simple merge of all rects whenever there are more than 10."
>So, if your diagonal morph could present its change as fewer than 10 rectangles (i.e. instead of invalidating your fullBounds, invalidate 2 or 5 or 9 subsections), then you *might* win. The tradeoff is the work involved in keeping track of many individual rectangles vs. the work in redrawing more morphs than are strictly necessary.
Of course, you could change the merge-at-10 strategy (I put that there), but it seems to work well, and there is a way to trick it into doing what you want...
There was a period early int he MVC->morphic migration when we had 8 reframe handles on browsers. I discovered that waking up a window was quite slow, and it turned out that this was because the handle damage was getting merged and forcing the entire window to be repainted. By simply inserting a couple of calls to
self world displayWorld
I was able to cause only a couple of tiny border strips (and none of the actual text panes) to get refreshed and things ran *much* faster. Get it? Executing this statement handles the damage so far, and resets the damageRecorder.
You can see another case of this in the current system in SystemWindow>>passivate. Here I discovered that the damage from un-highlighting the title bar of the passivating window was getting merged with the damage from activating another, and causing almost the whole screen to repaint. The answer - do a display world after the title bar change. This way only the title bar gets repainted, followed by whatever needs to happen in the other window.
[Hackers notebook: For anyone interested in damage reporting and consolidation, note the lines
false ifTrue: [ "*make this true to flash damaged areas for testing*"
self flashRects: allDamage color: Color black].
in PasteUpMorph>>displayWorld. If you change the false to true, you will see a screen flash wherever damage is being repaired. It can be extemely enlightening!]
Back on topic: So if you are doing a lot of long diagonal lines, you could put a displayWorld before and after and every 9 or 10 sub-rectangles along the way, and thus avoid a complete repaint of your screen. Naturally there will be tradeoffs that affect how fine to make the segmentation.
Hope this helps
More information about the Squeak-dev