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
This commit is contained in:
Adi Oanca 2005-06-02 20:58:18 +00:00
parent 80f6ef8bd8
commit a4aff61d76
8 changed files with 337 additions and 53 deletions

View File

@ -197,7 +197,7 @@ Layer::Show()
{ {
BRegion invalid; BRegion invalid;
set_user_regions(invalid); get_user_regions(invalid);
if (invalid.CountRects() > 0) if (invalid.CountRects() > 0)
fParent->Invalidate(invalid, this); fParent->Invalidate(invalid, this);
@ -277,26 +277,51 @@ Layer::resize_layer_frame_by(float x, float y)
} }
void void
Layer::resize_redraw_more_regions(BRegion &redraw) Layer::rezize_layer_redraw_more(BRegion &reg, 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 if (((rm & 0x0F0F) == (uint16)B_FOLLOW_RIGHT && dx != 0) ||
|| rm & B_FOLLOW_BOTTOM || rm & B_FOLLOW_V_CENTER ((rm & 0x0F0F) == (uint16)B_FOLLOW_H_CENTER && dx != 0) ||
// TODO: these 2 don't need to be redrawn entirely. but ATM we don't have a choice ((rm & 0xF0F0) == (uint16)B_FOLLOW_BOTTOM && dy != 0)||
|| rm & B_FOLLOW_LEFT_RIGHT || rm & B_FOLLOW_TOP_BOTTOM) ((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
redraw.Include(&fFullVisible); (rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM)
} {
else reg.Include(&lay->fFullVisible);
{ }
for (Layer *lay = VirtualBottomChild();
lay; lay = VirtualUpperSibling())
lay->resize_redraw_more_regions(redraw);
} }
} }
void Layer::ResizeBy(float dx, float dy) void
Layer::rezize_layer_redraw_more(BRegion &redraw, BRegion &copy, 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); 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 oldFullVisible(fFullVisible);
BRegion oldVisible(fVisible); 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. // we'll invalidate the old area and the new, maxmial one.
BRegion invalid; BRegion invalid;
set_user_regions(invalid); get_user_regions(invalid);
invalid.Include(&fFullVisible); invalid.Include(&fFullVisible);
clear_visible_regions(); clear_visible_regions();
@ -335,10 +371,95 @@ void Layer::ResizeBy(float dx, float dy)
// 3) combine. // 3) combine.
redrawReg.Include(&redrawReg2); 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(&copyReg);
copyReg.OffsetBy(-dx, 0);
GetRootLayer()->CopyRegion(&copyReg, 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. // layers that had their frame modified must be entirely redrawn.
for (Layer *lay = VirtualBottomChild(); for (Layer *lay = VirtualBottomChild();
lay; lay = VirtualUpperSibling()) 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. // add redrawReg to our RootLayer's redraw region.
GetRootLayer()->fRedrawReg.Include(&redrawReg); GetRootLayer()->fRedrawReg.Include(&redrawReg);
@ -351,6 +472,7 @@ void Layer::ResizeBy(float dx, float dy)
// clear canvas and set invalid regions for affected WinBorders // clear canvas and set invalid regions for affected WinBorders
GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)? GetRootLayer()->RequestRedraw(); // TODO: what if we pass (fParent, startFromTHIS, &redrawReg)?
} }
*/
} }
void Layer::MoveBy(float dx, float dy) 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. // we'll invalidate the old position and the new, maxmial one.
BRegion invalid; BRegion invalid;
set_user_regions(invalid); get_user_regions(invalid);
invalid.Include(&fFullVisible); invalid.Include(&fFullVisible);
clear_visible_regions(); clear_visible_regions();
@ -441,10 +563,10 @@ void Layer::ScrollBy(float dx, float dy)
void Layer::GetWantedRegion(BRegion &reg) void Layer::GetWantedRegion(BRegion &reg)
{ {
set_user_regions(reg); get_user_regions(reg);
} }
void Layer::set_user_regions(BRegion &reg) void Layer::get_user_regions(BRegion &reg)
{ {
// OPT: maybe we should have all these cached in a 'fFull' member // 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 // intersect maximum wanted region with the invalid region
BRegion common; BRegion common;
set_user_regions(common); get_user_regions(common);
common.IntersectWith(&invalid); common.IntersectWith(&invalid);
// if the resulted region is not valid, this layer is not in the catchment area // if the resulted region is not valid, this layer is not in the catchment area

View File

@ -68,11 +68,12 @@ protected:
private: private:
virtual bool alter_visible_for_children(BRegion &region); virtual bool alter_visible_for_children(BRegion &region);
virtual void set_user_regions(BRegion &reg); virtual void get_user_regions(BRegion &reg);
void clear_visible_regions(); void clear_visible_regions();
void resize_layer_frame_by(float x, float y); void resize_layer_frame_by(float x, float y);
void resize_redraw_more_regions(BRegion &redraw); void rezize_layer_redraw_more(BRegion &reg, float dx, float dy);
void rezize_layer_redraw_more(BRegion &redraw, BRegion &copy, float dx, float dy);
char fName[50]; char fName[50];
BRegion fVisible; BRegion fVisible;

View File

@ -3,11 +3,66 @@
#include <Window.h> #include <Window.h>
#include <stdio.h> #include <stdio.h>
#include <stack.h>
#include "MyView.h" #include "MyView.h"
#include "Layer.h" #include "Layer.h"
extern BWindow *wind; 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) MyView::MyView(BRect frame, const char *name, uint32 resizingMode, uint32 flags)
: BView(frame, name, resizingMode, 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(); wind->Lock();
ConstrainClippingRegion(reg); int32 count = region->CountRects();
PushState();
DrawSubTree(topLayer); // TODO: make this step unnecessary
PopState(); // (by using different stack impl inside node)
ConstrainClippingRegion(NULL); 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<node*> 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(); wind->Unlock();
} }
void MyView::RequestRedraw() void MyView::RequestRedraw()
{ {
wind->Lock(); wind->Lock();
ConstrainClippingRegion(&fRedrawReg); ConstrainClippingRegion(&fRedrawReg);
PushState(); PushState();
DrawSubTree(topLayer); DrawSubTree(topLayer);
@ -168,17 +294,7 @@ void MyView::RequestRedraw()
void MyView::Draw(BRect area) void MyView::Draw(BRect area)
{ {
/* // empty. you can trigger a redraw by clicking the middle mouse button.
ConstrainClippingRegion(&fRedrawReg);
//FillRect(Bounds());
//Flush();
//snooze(1000000);
PushState();
DrawSubTree(topLayer);
PopState();
ConstrainClippingRegion(NULL);
fRedrawReg.MakeEmpty();
*/
} }
void MyView::DrawSubTree(Layer* lay) void MyView::DrawSubTree(Layer* lay)

View File

@ -16,7 +16,7 @@ public:
virtual void MouseMoved(BPoint where, uint32 code, const BMessage *a_message); virtual void MouseMoved(BPoint where, uint32 code, const BMessage *a_message);
virtual void MessageReceived(BMessage*); virtual void MessageReceived(BMessage*);
void CopyRegion(BRegion *reg, float dx, float dy); void CopyRegion(BRegion *region, int32 xOffset, int32 yOffset);
void RequestRedraw(); void RequestRedraw();
Layer* FindLayer(Layer *lay, BPoint &where) const; Layer* FindLayer(Layer *lay, BPoint &where) const;

View File

@ -56,7 +56,7 @@ bool WinBorder::alter_visible_for_children(BRegion &region)
return true; return true;
} }
void WinBorder::set_user_regions(BRegion &reg) void WinBorder::get_user_regions(BRegion &reg)
{ {
if (fRebuildDecRegion) if (fRebuildDecRegion)
{ {
@ -74,6 +74,4 @@ wind->Unlock();
reg.IntersectWith(&screenReg); reg.IntersectWith(&screenReg);
reg.Include(&fDecRegion); reg.Include(&fDecRegion);
//reg.PrintToStream();
} }

View File

@ -14,7 +14,7 @@ public:
private: private:
void set_decorator_region(BRect frame); void set_decorator_region(BRect frame);
virtual bool alter_visible_for_children(BRegion &region); virtual bool alter_visible_for_children(BRegion &region);
virtual void set_user_regions(BRegion &reg); virtual void get_user_regions(BRegion &reg);
BRegion fDecRegion; BRegion fDecRegion;
bool fRebuildDecRegion; bool fRebuildDecRegion;

View File

@ -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); WinBorder *wb1 = new WinBorder(BRect(20,20,300,220), "wb1", B_FOLLOW_NONE, B_FULL_UPDATE_ON_RESIZE, c);
topLayer->AddLayer(wb1); topLayer->AddLayer(wb1);
// same size as 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); wb1->AddLayer(lay1);
// ------ // ------
c.red = rand()/256; c.red = rand()/256;
@ -119,18 +119,65 @@ void clsMainWindow::test1()
c.green = rand()/256; c.green = rand()/256;
c.blue = rand()/256; c.blue = rand()/256;
Layer *lay12 = new Layer(BRect(170,20,290,150), "lay12", Layer *lay12 = new Layer(BRect(170,20,290,150), "lay12",
B_FOLLOW_NONE, B_FOLLOW_LEFT | B_FOLLOW_TOP,
B_FULL_UPDATE_ON_RESIZE, c); // B_FOLLOW_NONE,
0, c);
lay1->AddLayer(lay12); lay1->AddLayer(lay12);
c.red = rand()/256; c.red = rand()/256;
c.green = rand()/256; c.green = rand()/256;
c.blue = rand()/256; c.blue = rand()/256;
Layer *lay13 = new Layer(BRect(20,20,100,100), "lay13", 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); 0, c);
lay12->AddLayer(lay13); 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; c.red = rand()/256;