[haiku-appserver] Re: [Haiku-commits] r12953 - haiku/trunk/src/servers/app

  • From: Adi Oanca <adioanca@xxxxxxxxxxxxxx>
  • To: haiku-appserver@xxxxxxxxxxxxx
  • Date: Tue, 07 Jun 2005 13:31:07 +0300

Hi Stephan,

Stephan Assmus wrote:
> May I add that I have tried to understand the Layer tree traversal 
> several times now, but I just don't get it. I also read over it several 
> times in Adis new clipping code, which is a lot cleaner, because it 
> doesn't have so much other stuff in it.

for (Layer *lay = VirtualBottomChild();
        lay; lay = VirtualUpperSibling())
{
        ...
}

        Why I do this? Because of WinBorders. Layers are a linked list,
WinBorders are not. The list of WinBorders is kept per Workspace and changes
frequently. When it changes, I query the active workspace which gives me
the WinBorder list. WinBorder's VirtualXXXYYY() use an index to iterate
through the array, Layer's cache the "current layer" in the linked list.

> What is the adventage of doing it like it is done=3F Compared to using 
> BList or something similar as a container for each Layers children=3F

        To be honest, I didn't think of doing this in other way. That's how
it's done in BView so that's how DW and me did it over here.
        Maybe it could be better using a BList as insertions and deletion
of elements is rare compared to tree traversal operations...

> That aside, the clipping calculation still looks like it might have to 
> recalculate too much during each run.

        Of which clipping code are you talking about?
        The new one? If yes, I can assure you that's not the case, with an
expection(in the next paragraph). I have tested the new code to be sure it
won't calculate anything that's not needed.

        Ever since you started looking at clipping code you asked me what
fFull, fFullVisible and fVisible are for. I have explained that once, and
I will explain again with the new clipping code in mind.

  * fFull - is not used anymore. This was used to cache the area a layer
wanted for itself, including user constrain regions. That was nice as it
was not the case to rebuild the region a layer wanted every time a clipping
operation took place. Think about WinBorders that have decorators with
rounded corners - this could avoided quite a few CPU cycles.
        This member in gone in the new clipping code. It is calculated every
time it is needed - done for simplicity and less memory consuption.

* fFullVisible - This holds the visible are of a layer + the visible areas of
ALL descendants. This region is not necessarily a must, but avoids a lot of CPU
cycles. For example, when moving a window, we need the region that windows
occupied on screen, which is exactly what this region contains. If it not were
for this region, with every move of the window(each step), this region must
be rebuilt. You'll say: cache it. Yes, that's a solution, but I'm not convinced
it's an easy and clean one.
        This member can be removed and save some memory at the expense of quite
a few CPU cycles.
        I wanted to talk about this with you guys... do you think we should
offer a runtime option to have this active or inactive?

  * fVisible - is the actual visible region of a layer without the visible
regions of its descendants.

> Here is some pseudo code which I 
> have been rolling in my head (just typing it now, so please excuse 
> obvious erros):
> 
> void
> Layer::RebuildLocalClipping()
> {
>       fLocalClippingRegion.Set(Bounds());
>       for (int32 i =3D 0; Layer* layer =3D ChildAt(i); i++) {
>               fLocalClippingRegion.Exclude(layer->Frame());
>       }
>       fScreenClippingRegionValid =3D false;
> }
> 
> const BRegion&
> Layer::ScreenClipping(bool forceRebuild)
> {
>       if (forceRebuild || !fScreenClippingRegionValid) {
>               fScreenClippingRegion =3D ConvertToTop(fLocalClippingRegion);
>               fScreenClippingRegion.IntersectWith(Window()->ScreenClipping());
>               fScreenClippingRegionValid =3D true;
>       }
>       return fScreenClippingRegion;
> }

        I know it sounds easy at a first thought, but there are quite
a few variables involved.

> [This code takes the fact into account, that sibbling views don't clip 
> each other. In BeOS, you just have to make sure that views on the same 
> level don't overlap, or both are alowed to draw in the same area.]

        I the code I wrote only the last added view will get the common
region if they overlap. I saw this behavior on BeOS some time ago when I
did some tests, and IMO that is the right way to go. (AFAI'm concerned,
it's the same behavior as with windows)

> Note that the local Layer clipping only ever changes if the Layer 
> itself is resized or if there is a change with its children (add/remove
> /show/hide/move/resize). When for example moving windows, this does not 
> happen at all!

        In the new clipping code visible regions are only offset-ed when
moving windows. Not a CPU intensive task.

> What this code hides is the fact that the "dirty" region 
> needs to be tracked as well during any changes. But I don't see any 
> problems there. In any case, isn't this just much more straight forward 
> as a basis for the real algorithm?

        I wouldn't say... It's the same thing. You keep visible regions
local, I keep them in screen coords. At a given time we both have to
calculate something. When moving a window I just offset visible regions,
you take the dirty screen region and pass it to every layer by converting
it to it's local coordinate system. When you resize, same happens.
        In the end it's almost the same. I chose screen coords because of
mouse_moved operations.



bye,
Adi.

Other related posts: