From a4aff61d76253ff2252743e427cffac008d5de54 Mon Sep 17 00:00:00 2001 From: Adi Oanca Date: Thu, 2 Jun 2005 20:58:18 +0000 Subject: [PATCH] Imported Stephan's CopyRegion. Trying to optimize resize operations - work in progress. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12934 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../servers/app/newClipping/Clipping.proj | Bin 12308 -> 12308 bytes src/tests/servers/app/newClipping/Layer.cpp | 166 +++++++++++++++--- src/tests/servers/app/newClipping/Layer.h | 5 +- src/tests/servers/app/newClipping/MyView.cpp | 156 +++++++++++++--- src/tests/servers/app/newClipping/MyView.h | 2 +- .../servers/app/newClipping/WinBorder.cpp | 4 +- src/tests/servers/app/newClipping/WinBorder.h | 2 +- src/tests/servers/app/newClipping/main.cpp | 55 +++++- 8 files changed, 337 insertions(+), 53 deletions(-) diff --git a/src/tests/servers/app/newClipping/Clipping.proj b/src/tests/servers/app/newClipping/Clipping.proj index 4effe88a2556dee0852829a5ac4b185c97a97e7f..9a9b1e31c4a6f5ecbdb9d9dd7837130ea505a813 100644 GIT binary patch delta 131 zcmbP|FePEb0X7ziIWi5C7w|f6W@Z1W!n~zXX)~jaAfuT00R{#J79eH@Vul7FcAEcB za`InYwaI?EGsP57f`oy92}CpiF;sdr^Zb8OU}YEe=7|Zu2FhpvF|sl(u=HyEOaNF- BB!2(^ delta 131 zcmbP|FePEb0XCKy@1+_hFW`0D%*y^#g*oMw+-61{K}Iow1_lNO79eH@Vul7FcAB;Q z-sHc!YLoqRXNt*5f`oy92}Cq7FfcmJ+OZQTy_$K}_C~O>i+c0Kxcx!WKmbz)GNlPD Iy;?sL0Gxs(mjD0& diff --git a/src/tests/servers/app/newClipping/Layer.cpp b/src/tests/servers/app/newClipping/Layer.cpp index a0516a1c02..844a8d325f 100644 --- a/src/tests/servers/app/newClipping/Layer.cpp +++ b/src/tests/servers/app/newClipping/Layer.cpp @@ -197,7 +197,7 @@ Layer::Show() { BRegion invalid; - set_user_regions(invalid); + get_user_regions(invalid); if (invalid.CountRects() > 0) fParent->Invalidate(invalid, this); @@ -277,26 +277,51 @@ Layer::resize_layer_frame_by(float x, float y) } void -Layer::resize_redraw_more_regions(BRegion &redraw) +Layer::rezize_layer_redraw_more(BRegion ®, float dx, float dy) { - uint16 rm = fResizeMode & 0x0000FFFF; + for (Layer *lay = VirtualBottomChild(); + lay; lay = VirtualUpperSibling()) + { + uint16 rm = lay->fResizeMode & 0x0000FFFF; - if (rm & B_FOLLOW_RIGHT || rm & B_FOLLOW_H_CENTER - || rm & B_FOLLOW_BOTTOM || rm & B_FOLLOW_V_CENTER - // TODO: these 2 don't need to be redrawn entirely. but ATM we don't have a choice - || rm & B_FOLLOW_LEFT_RIGHT || rm & B_FOLLOW_TOP_BOTTOM) - { - redraw.Include(&fFullVisible); - } - else - { - for (Layer *lay = VirtualBottomChild(); - lay; lay = VirtualUpperSibling()) - lay->resize_redraw_more_regions(redraw); + if (((rm & 0x0F0F) == (uint16)B_FOLLOW_RIGHT && dx != 0) || + ((rm & 0x0F0F) == (uint16)B_FOLLOW_H_CENTER && dx != 0) || + ((rm & 0xF0F0) == (uint16)B_FOLLOW_BOTTOM && dy != 0)|| + ((rm & 0xF0F0) == (uint16)B_FOLLOW_V_CENTER && dy != 0) || + // TODO: these 2 don't need to be redrawn entirely. but ATM we don't have a choice + (rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) + { + reg.Include(&lay->fFullVisible); + } } } -void Layer::ResizeBy(float dx, float dy) +void +Layer::rezize_layer_redraw_more(BRegion &redraw, BRegion ©, float dx, float dy) +{ + for (Layer *lay = VirtualBottomChild(); + lay; lay = VirtualUpperSibling()) + { + uint16 rm = lay->fResizeMode & 0x0000FFFF; + + if ((rm & 0x0F0F) == (uint16)B_FOLLOW_RIGHT && dx != 0) + { + copy.Include(&lay->fFullVisible); + redraw.Include(&lay->fFullVisible); + } + else if (((rm & 0x0F0F) == (uint16)B_FOLLOW_H_CENTER && dx != 0) || + ((rm & 0xF0F0) == (uint16)B_FOLLOW_BOTTOM && dy != 0) || + ((rm & 0xF0F0) == (uint16)B_FOLLOW_V_CENTER && dy != 0) || + // TODO: these 2 don't need to be redrawn entirely. but ATM we don't have a choice + (rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) + { + redraw.Include(&lay->fFullVisible); + } + } +} + +void +Layer::ResizeBy(float dx, float dy) { fFrame.Set(fFrame.left, fFrame.top, fFrame.right+dx, fFrame.bottom+dy); @@ -314,9 +339,20 @@ void Layer::ResizeBy(float dx, float dy) BRegion oldFullVisible(fFullVisible); BRegion oldVisible(fVisible); +// OPT: you can use HW acceleration for either for bottom alligned layer or +// for right alligned ones. investigate! + + // right, center and bottom alligned layers will change their position + // so we need to invalidate their current visible regions +// BRegion redrawRightOrBottom; +// rezize_layer_redraw_more(redrawRightOrBottom, dx, dy); +BRegion redrawRightOrBottom; +BRegion copyReg; +rezize_layer_redraw_more(redrawRightOrBottom, copyReg, dx, dy); + // we'll invalidate the old area and the new, maxmial one. BRegion invalid; - set_user_regions(invalid); + get_user_regions(invalid); invalid.Include(&fFullVisible); clear_visible_regions(); @@ -335,10 +371,95 @@ void Layer::ResizeBy(float dx, float dy) // 3) combine. redrawReg.Include(&redrawReg2); + // for center, right and bottom alligned layers, redraw their old positions + redrawReg.Include(&redrawRightOrBottom); + + // layers that had their frame modified must be entirely redrawn. + rezize_layer_redraw_more(redrawReg, dx, dy); + + // add redrawReg to our RootLayer's redraw region. + GetRootLayer()->fRedrawReg.Include(&redrawReg); + // include layer's visible region in case we want a full update on resize + if (fFlags & B_FULL_UPDATE_ON_RESIZE && fVisible.Frame().IsValid()) + { + GetRootLayer()->fRedrawReg.Include(&fVisible); + GetRootLayer()->fRedrawReg.Include(&oldVisible); + } +copyReg.OffsetBy(dx, 0); +copyReg.IntersectWith(&fFullVisible); +GetRootLayer()->fRedrawReg.Exclude(©Reg); +copyReg.OffsetBy(-dx, 0); +GetRootLayer()->CopyRegion(©Reg, dx, 0); + // clear canvas and set invalid regions for affected WinBorders + GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)? + } + +/* + This works well! Above I'm trying to optimize things. + + if (!IsVisuallyHidden() && GetRootLayer()) + { + BRegion oldFullVisible(fFullVisible); + BRegion oldVisible(fVisible); + +// OPT: you can we HW acceleration for either for bottom alligned layer or +// for right alligned ones. investigate! + + // right, center and bottom alligned layers will change their position + // so we need to invalidate their current visible regions + BRegion redrawRightOrBottom; + for (Layer *lay = VirtualBottomChild(); + lay; lay = VirtualUpperSibling()) + { + uint16 rm = lay->fResizeMode & 0x0000FFFF; + + if ((rm & 0x0F0F) == (uint16)B_FOLLOW_RIGHT || (rm & 0x0F0F) == (uint16)B_FOLLOW_H_CENTER + || (rm & 0xF0F0) == (uint16)B_FOLLOW_BOTTOM || (rm & 0xF0F0) == (uint16)B_FOLLOW_V_CENTER + // TODO: these 2 don't need to be redrawn entirely. but ATM we don't have a choice + || (rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) + { + redrawRightOrBottom.Include(&lay->fFullVisible); + } + } + + // we'll invalidate the old area and the new, maxmial one. + BRegion invalid; + get_user_regions(invalid); + invalid.Include(&fFullVisible); + + clear_visible_regions(); + + fParent->RebuildVisibleRegions(invalid, this); + + // done rebuilding regions, now redraw regions that became visible + + // what's invalid, are the differences between to old and the new fullVisible region + // 1) in case we grow. + BRegion redrawReg(fFullVisible); + redrawReg.Exclude(&oldFullVisible); + // 2) in case we shrink + BRegion redrawReg2(oldFullVisible); + redrawReg2.Exclude(&fFullVisible); + // 3) combine. + redrawReg.Include(&redrawReg2); + + // for center, right and bottom alligned layers, redraw their old positions + redrawReg.Include(&redrawRightOrBottom); + // layers that had their frame modified must be entirely redrawn. for (Layer *lay = VirtualBottomChild(); lay; lay = VirtualUpperSibling()) - lay->resize_redraw_more_regions(redrawReg); + { + uint16 rm = lay->fResizeMode & 0x0000FFFF; + + if ((rm & 0x0F0F) == (uint16)B_FOLLOW_RIGHT || (rm & 0x0F0F) == (uint16)B_FOLLOW_H_CENTER + || (rm & 0xF0F0) == (uint16)B_FOLLOW_BOTTOM || (rm & 0xF0F0) == (uint16)B_FOLLOW_V_CENTER + // TODO: these 2 don't need to be redrawn entirely. but ATM we don't have a choice + || (rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) + { + redrawReg.Include(&lay->fFullVisible); + } + } // add redrawReg to our RootLayer's redraw region. GetRootLayer()->fRedrawReg.Include(&redrawReg); @@ -351,6 +472,7 @@ void Layer::ResizeBy(float dx, float dy) // clear canvas and set invalid regions for affected WinBorders GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)? } +*/ } void Layer::MoveBy(float dx, float dy) @@ -370,7 +492,7 @@ void Layer::MoveBy(float dx, float dy) // we'll invalidate the old position and the new, maxmial one. BRegion invalid; - set_user_regions(invalid); + get_user_regions(invalid); invalid.Include(&fFullVisible); clear_visible_regions(); @@ -441,10 +563,10 @@ void Layer::ScrollBy(float dx, float dy) void Layer::GetWantedRegion(BRegion ®) { - set_user_regions(reg); + get_user_regions(reg); } -void Layer::set_user_regions(BRegion ®) +void Layer::get_user_regions(BRegion ®) { // OPT: maybe we should have all these cached in a 'fFull' member @@ -500,7 +622,7 @@ void Layer::rebuild_visible_regions(const BRegion &invalid, // intersect maximum wanted region with the invalid region BRegion common; - set_user_regions(common); + get_user_regions(common); common.IntersectWith(&invalid); // if the resulted region is not valid, this layer is not in the catchment area diff --git a/src/tests/servers/app/newClipping/Layer.h b/src/tests/servers/app/newClipping/Layer.h index a99323c9a2..61e9ff0887 100644 --- a/src/tests/servers/app/newClipping/Layer.h +++ b/src/tests/servers/app/newClipping/Layer.h @@ -68,11 +68,12 @@ protected: private: virtual bool alter_visible_for_children(BRegion ®ion); - virtual void set_user_regions(BRegion ®); + virtual void get_user_regions(BRegion ®); void clear_visible_regions(); void resize_layer_frame_by(float x, float y); - void resize_redraw_more_regions(BRegion &redraw); + void rezize_layer_redraw_more(BRegion ®, float dx, float dy); + void rezize_layer_redraw_more(BRegion &redraw, BRegion ©, float dx, float dy); char fName[50]; BRegion fVisible; diff --git a/src/tests/servers/app/newClipping/MyView.cpp b/src/tests/servers/app/newClipping/MyView.cpp index cd98c12268..cf2368b3c3 100644 --- a/src/tests/servers/app/newClipping/MyView.cpp +++ b/src/tests/servers/app/newClipping/MyView.cpp @@ -3,11 +3,66 @@ #include #include +#include #include "MyView.h" #include "Layer.h" extern BWindow *wind; +struct node { + node() + { + pointers = NULL; + } + node(const BRect& r, int32 maxPointers) + { + init(r, maxPointers); + } + ~node() + { + delete [] pointers; + } + + void init(const BRect& r, int32 maxPointers) + { + rect = r; + pointers = new node*[maxPointers]; + in_degree = 0; + next_pointer = 0; + } + + void push(node* node) + { + pointers[next_pointer] = node; + next_pointer++; + } + node* top() + { + return pointers[next_pointer]; + } + node* pop() + { + node* ret = top(); + next_pointer--; + return ret; + } + + BRect rect; + int32 in_degree; + node** pointers; + int32 next_pointer; +}; + +bool +is_left_of(const BRect& a, const BRect& b) +{ + return (a.right < b.left); +} +bool +is_above(const BRect& a, const BRect& b) +{ + return (a.bottom < b.top); +} MyView::MyView(BRect frame, const char *name, uint32 resizingMode, uint32 flags) : BView(frame, name, resizingMode, flags) @@ -139,22 +194,93 @@ void MyView::MessageReceived(BMessage *msg) } } -void MyView::CopyRegion(BRegion *reg, float dx, float dy) +void MyView::CopyRegion(BRegion *region, int32 xOffset, int32 yOffset) { - // Yes... in this sandbox app, do a redraw. - reg->OffsetBy(dx, dy); wind->Lock(); - ConstrainClippingRegion(reg); - PushState(); - DrawSubTree(topLayer); - PopState(); - ConstrainClippingRegion(NULL); + int32 count = region->CountRects(); + + // TODO: make this step unnecessary + // (by using different stack impl inside node) + node nodes[count]; + for (int32 i= 0; i < count; i++) { + nodes[i].init(region->RectAt(i), count); + } + + for (int32 i = 0; i < count; i++) { + BRect a = region->RectAt(i); + for (int32 k = i + 1; k < count; k++) { + BRect b = region->RectAt(k); + int cmp = 0; + // compare horizontally + if (xOffset > 0) { + if (is_left_of(a, b)) { + cmp -= 1; + } else if (is_left_of(b, a)) { + cmp += 1; + } + } else if (xOffset < 0) { + if (is_left_of(a, b)) { + cmp += 1; + } else if (is_left_of(b, a)) { + cmp -= 1; + } + } + // compare vertically + if (yOffset > 0) { + if (is_above(a, b)) { + cmp -= 1; + } else if (is_above(b, a)) { + cmp += 1; + } + } else if (yOffset < 0) { + if (is_above(a, b)) { + cmp += 1; + } else if (is_above(b, a)) { + cmp -= 1; + } + } + // add appropriate node as successor + if (cmp > 0) { + nodes[i].push(&nodes[k]); + nodes[k].in_degree++; + } else if (cmp < 0) { + nodes[k].push(&nodes[i]); + nodes[i].in_degree++; + } + } + } + // put all nodes onto a stack that have an "indegree" count of zero + stack inDegreeZeroNodes; + for (int32 i = 0; i < count; i++) { + if (nodes[i].in_degree == 0) { + inDegreeZeroNodes.push(&nodes[i]); + } + } + // pop the rects from the stack, do the actual copy operation + // and decrease the "indegree" count of the other rects not + // currently on the stack and to which the current rect pointed + // to. If their "indegree" count reaches zero, put them onto the + // stack as well. + + while (!inDegreeZeroNodes.empty()) { + node* n = inDegreeZeroNodes.top(); + inDegreeZeroNodes.pop(); + + CopyBits(n->rect, BRect(n->rect).OffsetByCopy(xOffset, yOffset)); + + for (int32 k = 0; k < n->next_pointer; k++) { + n->pointers[k]->in_degree--; + if (n->pointers[k]->in_degree == 0) + inDegreeZeroNodes.push(n->pointers[k]); + } + } wind->Unlock(); } void MyView::RequestRedraw() { wind->Lock(); + ConstrainClippingRegion(&fRedrawReg); PushState(); DrawSubTree(topLayer); @@ -168,17 +294,7 @@ void MyView::RequestRedraw() void MyView::Draw(BRect area) { -/* - ConstrainClippingRegion(&fRedrawReg); -//FillRect(Bounds()); -//Flush(); -//snooze(1000000); - PushState(); - DrawSubTree(topLayer); - PopState(); - ConstrainClippingRegion(NULL); - fRedrawReg.MakeEmpty(); -*/ + // empty. you can trigger a redraw by clicking the middle mouse button. } void MyView::DrawSubTree(Layer* lay) @@ -196,4 +312,4 @@ void MyView::DrawSubTree(Layer* lay) FillRect(reg.Frame()); Flush(); ConstrainClippingRegion(NULL); -} \ No newline at end of file +} diff --git a/src/tests/servers/app/newClipping/MyView.h b/src/tests/servers/app/newClipping/MyView.h index ce2e53bd93..846ae2b792 100644 --- a/src/tests/servers/app/newClipping/MyView.h +++ b/src/tests/servers/app/newClipping/MyView.h @@ -16,7 +16,7 @@ public: virtual void MouseMoved(BPoint where, uint32 code, const BMessage *a_message); virtual void MessageReceived(BMessage*); - void CopyRegion(BRegion *reg, float dx, float dy); + void CopyRegion(BRegion *region, int32 xOffset, int32 yOffset); void RequestRedraw(); Layer* FindLayer(Layer *lay, BPoint &where) const; diff --git a/src/tests/servers/app/newClipping/WinBorder.cpp b/src/tests/servers/app/newClipping/WinBorder.cpp index 176dde4153..8e8901fddd 100644 --- a/src/tests/servers/app/newClipping/WinBorder.cpp +++ b/src/tests/servers/app/newClipping/WinBorder.cpp @@ -56,7 +56,7 @@ bool WinBorder::alter_visible_for_children(BRegion ®ion) return true; } -void WinBorder::set_user_regions(BRegion ®) +void WinBorder::get_user_regions(BRegion ®) { if (fRebuildDecRegion) { @@ -74,6 +74,4 @@ wind->Unlock(); reg.IntersectWith(&screenReg); reg.Include(&fDecRegion); - -//reg.PrintToStream(); } diff --git a/src/tests/servers/app/newClipping/WinBorder.h b/src/tests/servers/app/newClipping/WinBorder.h index 109548cd49..be633ea727 100644 --- a/src/tests/servers/app/newClipping/WinBorder.h +++ b/src/tests/servers/app/newClipping/WinBorder.h @@ -14,7 +14,7 @@ public: private: void set_decorator_region(BRect frame); virtual bool alter_visible_for_children(BRegion ®ion); - virtual void set_user_regions(BRegion ®); + virtual void get_user_regions(BRegion ®); BRegion fDecRegion; bool fRebuildDecRegion; diff --git a/src/tests/servers/app/newClipping/main.cpp b/src/tests/servers/app/newClipping/main.cpp index e07fdad1c0..a133be8909 100644 --- a/src/tests/servers/app/newClipping/main.cpp +++ b/src/tests/servers/app/newClipping/main.cpp @@ -96,7 +96,7 @@ void clsMainWindow::test1() WinBorder *wb1 = new WinBorder(BRect(20,20,300,220), "wb1", B_FOLLOW_NONE, B_FULL_UPDATE_ON_RESIZE, c); topLayer->AddLayer(wb1); // same size as wb1 - Layer *lay1 = new Layer(BRect(0,0,280,200), "lay1", B_FOLLOW_NONE, 0, c); + Layer *lay1 = new Layer(BRect(0,0,280,200), "lay1", B_FOLLOW_ALL, 0, c); wb1->AddLayer(lay1); // ------ c.red = rand()/256; @@ -119,18 +119,65 @@ void clsMainWindow::test1() c.green = rand()/256; c.blue = rand()/256; Layer *lay12 = new Layer(BRect(170,20,290,150), "lay12", - B_FOLLOW_NONE, - B_FULL_UPDATE_ON_RESIZE, c); + B_FOLLOW_LEFT | B_FOLLOW_TOP, +// B_FOLLOW_NONE, + 0, c); lay1->AddLayer(lay12); c.red = rand()/256; c.green = rand()/256; c.blue = rand()/256; Layer *lay13 = new Layer(BRect(20,20,100,100), "lay13", - B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, +// B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, + B_FOLLOW_RIGHT | B_FOLLOW_TOP, +// B_FOLLOW_LEFT | B_FOLLOW_V_CENTER, +// B_FOLLOW_H_CENTER | B_FOLLOW_TOP, 0, c); lay12->AddLayer(lay13); + c.red = rand()/256; + c.green = rand()/256; + c.blue = rand()/256; + Layer *lay102 = new Layer(BRect(200,20,420,250), "lay102", + B_FOLLOW_NONE, + B_FULL_UPDATE_ON_RESIZE, c); + lay1->AddLayer(lay102); + + c.red = rand()/256; + c.green = rand()/256; + c.blue = rand()/256; + Layer *lay103 = new Layer(BRect(0,0,100,50), "lay103", + B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, +// B_FOLLOW_LEFT | B_FOLLOW_TOP, + 0, c); + lay102->AddLayer(lay103); + + c.red = rand()/256; + c.green = rand()/256; + c.blue = rand()/256; + Layer *lay104 = new Layer(BRect(0,51,100,130), "lay104", +// B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM, + 0, c); + lay102->AddLayer(lay104); + + c.red = rand()/256; + c.green = rand()/256; + c.blue = rand()/256; + Layer *lay106 = new Layer(BRect(0,140,100, 200), "lay104", +// B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, + B_FOLLOW_RIGHT | B_FOLLOW_TOP, + 0, c); + lay102->AddLayer(lay106); + + c.red = rand()/256; + c.green = rand()/256; + c.blue = rand()/256; + Layer *lay105 = new Layer(BRect(105,51,150,130), "lay104", +// B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, + B_FOLLOW_H_CENTER | B_FOLLOW_BOTTOM, + 0, c); + lay102->AddLayer(lay105); //--------- c.red = rand()/256;