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;
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 &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
|| 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 &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);
@ -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(&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.
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 &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
@ -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

View File

@ -68,11 +68,12 @@ protected:
private:
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 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];
BRegion fVisible;

View File

@ -3,11 +3,66 @@
#include <Window.h>
#include <stdio.h>
#include <stack.h>
#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<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();
}
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);
}
}

View File

@ -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;

View File

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

View File

@ -14,7 +14,7 @@ public:
private:
void set_decorator_region(BRect frame);
virtual bool alter_visible_for_children(BRegion &region);
virtual void set_user_regions(BRegion &reg);
virtual void get_user_regions(BRegion &reg);
BRegion fDecRegion;
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);
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;