now doing without a global dirty region, and it seems it gained a little speed too, should be easier now to make the multi locker work

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15231 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2005-11-29 20:35:47 +00:00
parent 4dd89c6903
commit c63a78aafa
5 changed files with 67 additions and 101 deletions
@@ -22,7 +22,6 @@ Desktop::Desktop(DrawView* drawView)
fIs2ndButton(false), fIs2ndButton(false),
fClippingLock("clipping lock"), fClippingLock("clipping lock"),
fDirtyRegion(),
fBackgroundRegion(), fBackgroundRegion(),
fDrawView(drawView), fDrawView(drawView),
@@ -102,20 +101,8 @@ Desktop::MouseDown(BPoint where, uint32 buttons)
fIs2ndButton = true; fIs2ndButton = true;
} else if (buttons == B_TERTIARY_MOUSE_BUTTON) { } else if (buttons == B_TERTIARY_MOUSE_BUTTON) {
if (modifiers() & B_SHIFT_KEY) {
// render global dirty region
if (fDrawingEngine->Lock()) {
fDrawingEngine->SetHighColor(255, 0, 0);
fDrawingEngine->FillRegion(&fDirtyRegion);
fDrawingEngine->MarkDirty(&fDirtyRegion);
fDrawingEngine->Unlock();
}
} else {
// complete redraw
#if RUN_WITH_FRAME_BUFFER #if RUN_WITH_FRAME_BUFFER
if (fDrawingEngine->Lock()) { if (fDrawingEngine->Lock()) {
fDirtyRegion.MakeEmpty();
BRegion region(fDrawingEngine->Bounds()); BRegion region(fDrawingEngine->Bounds());
fDrawingEngine->Unlock(); fDrawingEngine->Unlock();
@@ -125,12 +112,10 @@ Desktop::MouseDown(BPoint where, uint32 buttons)
_SetBackground(&region); _SetBackground(&region);
} }
#else #else
fDirtyRegion.MakeEmpty();
fDrawingEngine->MarkDirty(); fDrawingEngine->MarkDirty();
#endif #endif
} }
} }
}
// MouseUp // MouseUp
void void
@@ -245,7 +230,7 @@ Desktop::MessageReceived(BMessage* message)
} }
} }
#pragma mark - // #pragma mark -
// AddWindow // AddWindow
bool bool
@@ -367,10 +352,6 @@ Desktop::MoveWindowBy(WindowLayer* window, int32 x, int32 y)
if (LockClipping()) { if (LockClipping()) {
// the dirty region starts with the visible area of the window being moved // the dirty region starts with the visible area of the window being moved
BRegion newDirtyRegion(window->VisibleRegion()); BRegion newDirtyRegion(window->VisibleRegion());
// we have to move along the part of the current dirty region
// that intersects with the window being moved
BRegion alreadyDirtyRegion(fDirtyRegion);
alreadyDirtyRegion.IntersectWith(&window->VisibleRegion());
window->MoveBy(x, y); window->MoveBy(x, y);
@@ -394,15 +375,10 @@ Desktop::MoveWindowBy(WindowLayer* window, int32 x, int32 y)
// could move by blitting // could move by blitting
copyRegion.OffsetBy(x, y); copyRegion.OffsetBy(x, y);
newDirtyRegion.Exclude(&copyRegion); newDirtyRegion.Exclude(&copyRegion);
MarkClean(&copyRegion);
fDrawingEngine->MarkDirty(&copyRegion); fDrawingEngine->MarkDirty(&copyRegion);
fDrawingEngine->Unlock(); fDrawingEngine->Unlock();
} }
// include the moved peviously dirty region
alreadyDirtyRegion.OffsetBy(x, y);
alreadyDirtyRegion.IntersectWith(&window->VisibleRegion());
newDirtyRegion.Include(&alreadyDirtyRegion);
MarkDirty(&newDirtyRegion); MarkDirty(&newDirtyRegion);
_SetBackground(&background); _SetBackground(&background);
@@ -531,7 +507,7 @@ Desktop::SetFocusWindow(WindowLayer* window)
#pragma mark - // #pragma mark -
// MarkDirty // MarkDirty
void void
@@ -540,28 +516,7 @@ Desktop::MarkDirty(BRegion* region)
if (region->CountRects() == 0) if (region->CountRects() == 0)
return; return;
// NOTE: the idea is that for all dirty areas ever included
// in the culmulative dirty region, redraw messages have been
// sent to the windows affected by just the newly included
// area. Therefor, _TriggerWindowRedrawing() is not called
// with "fDirtyRegion", but with just the new "region" instead.
// Whenever a window is actually carrying out a redraw request,
// it is expected to remove the redrawn area from the dirty region.
if (LockClipping()) { if (LockClipping()) {
// add the new dirty region to the culmulative dirty region
fDirtyRegion.Include(region);
#if SHOW_GLOBAL_DIRTY_REGION
if (fDrawingEngine->Lock()) {
fDrawingEngine->SetHighColor(255, 0, 0);
fDrawingEngine->FillRegion(region);
fDrawingEngine->MarkDirty(region);
fDrawingEngine->Unlock();
snooze(100000);
}
#endif
// send redraw messages to all windows intersecting the dirty region // send redraw messages to all windows intersecting the dirty region
_TriggerWindowRedrawing(region); _TriggerWindowRedrawing(region);
@@ -569,29 +524,7 @@ if (fDrawingEngine->Lock()) {
} }
} }
// MarkClean // #pragma mark -
void
Desktop::MarkClean(BRegion* region)
{
// NOTE: when a window owns the read lock for
// the clipping, it means the Desktop thread is currently
// not messing with the regions. Since a window is expected
// to only remove parts from the dirty region that intersect
// it's own visible region, it cannot remove the wrong parts
// of the dirty region (ie parts intersecting another window)
// writelocking would therefor not be needed, but of course
// BRegion is not threadsafe, and therefor, it would be cool
// if the dirty region was moved into each window again.
if (LockClipping()) {
// remove the clean region from the culmulative dirty region
fDirtyRegion.Exclude(region);
UnlockClipping();
}
}
#pragma mark -
// _RebuildClippingForAllWindows // _RebuildClippingForAllWindows
void void
@@ -629,7 +562,8 @@ Desktop::_TriggerWindowRedrawing(BRegion* newDirtyRegion)
for (int32 i = count - 1; i >= 0; i--) { for (int32 i = count - 1; i >= 0; i--) {
WindowLayer* window = WindowAtFast(i); WindowLayer* window = WindowAtFast(i);
if (newDirtyRegion->Intersects(window->VisibleRegion().Frame())) if (newDirtyRegion->Intersects(window->VisibleRegion().Frame()))
window->PostMessage(MSG_REDRAW); // window->PostMessage(MSG_REDRAW);
window->ProcessDirtyRegion(newDirtyRegion);
} }
} }
@@ -656,6 +590,5 @@ Desktop::_SetBackground(BRegion* background)
fDrawingEngine->Unlock(); fDrawingEngine->Unlock();
} }
MarkClean(&dirtyBackground);
} }
} }
@@ -91,11 +91,7 @@ class Desktop : public BLooper {
void UnlockClipping() { fClippingLock.Unlock(); } void UnlockClipping() { fClippingLock.Unlock(); }
#endif #endif
void MarkDirty(BRegion* region); void MarkDirty(BRegion* region);
void MarkClean(BRegion* region);
BRegion* DirtyRegion()
{ return &fDirtyRegion; }
DrawingEngine* GetDrawingEngine() const DrawingEngine* GetDrawingEngine() const
{ return fDrawingEngine; } { return fDrawingEngine; }
@@ -122,7 +118,6 @@ private:
#else #else
BLocker fClippingLock; BLocker fClippingLock;
#endif #endif
BRegion fDirtyRegion;
BRegion fBackgroundRegion; BRegion fBackgroundRegion;
DrawView* fDrawView; DrawView* fDrawView;
@@ -375,7 +375,7 @@ ViewLayer::SetName(const char* string)
fName.SetTo(string); fName.SetTo(string);
} }
#pragma mark - // #pragma mark -
// MoveBy // MoveBy
void void
@@ -551,7 +551,7 @@ ViewLayer::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion)
InvalidateScreenClipping(true); InvalidateScreenClipping(true);
} }
#pragma mark - // #pragma mark -
// Draw // Draw
void void
@@ -617,7 +617,7 @@ ViewLayer::ClientDraw(DrawingEngine* drawingEngine, BRegion* effectiveClipping)
} }
} }
#pragma mark - // #pragma mark -
// IsHidden // IsHidden
bool bool
@@ -30,6 +30,7 @@ WindowLayer::WindowLayer(BRect frame, const char* name,
fVisibleRegion(), fVisibleRegion(),
fVisibleContentRegion(), fVisibleContentRegion(),
fDirtyRegion(),
fBorderRegion(), fBorderRegion(),
fBorderRegionValid(false), fBorderRegionValid(false),
@@ -93,6 +94,15 @@ WindowLayer::MessageReceived(BMessage* message)
_DrawBorder(); _DrawBorder();
_TriggerContentRedraw(); _TriggerContentRedraw();
// reset the dirty region, since
// we're fully clean. If the desktop
// thread wanted to mark something
// dirty in the mean time, it was
// blocking on the global region lock to
// get write access, since we held the
// read lock for the whole time.
fDirtyRegion.MakeEmpty();
fDesktop->ReadUnlockClipping(); fDesktop->ReadUnlockClipping();
} else { } else {
//printf("%s MSG_REDRAW -> pending redraws\n", Name()); //printf("%s MSG_REDRAW -> pending redraws\n", Name());
@@ -225,6 +235,10 @@ WindowLayer::MoveBy(int32 x, int32 y)
fFrame.OffsetBy(x, y); fFrame.OffsetBy(x, y);
// take along the dirty region which have not
// processed yet
fDirtyRegion.OffsetBy(x, y);
if (fBorderRegionValid) if (fBorderRegionValid)
fBorderRegion.OffsetBy(x, y); fBorderRegion.OffsetBy(x, y);
if (fContentRegionValid) if (fContentRegionValid)
@@ -315,6 +329,22 @@ WindowLayer::Show()
} }
// ProcessDirtyRegion
void
WindowLayer::ProcessDirtyRegion(BRegion* region)
{
// this is exectuted in the desktop thread,
// and it means that the window thread currently
// blocks on the global region lock
if (fDirtyRegion.CountRects() == 0) {
// the window needs to be informed
// when the dirty region was empty
PostMessage(MSG_REDRAW, this);
}
// this is executed from the desktop thread
fDirtyRegion.Include(region);
}
// MarkDirty // MarkDirty
void void
WindowLayer::MarkDirty(BRegion* regionOnScreen) WindowLayer::MarkDirty(BRegion* regionOnScreen)
@@ -370,7 +400,7 @@ WindowLayer::CopyContents(BRegion* region, int32 xOffset, int32 yOffset)
// move along the already dirty regions that are common // move along the already dirty regions that are common
// with the region that we could copy // with the region that we could copy
_ShiftPartOfRegion(fDesktop->DirtyRegion(), region, xOffset, yOffset); _ShiftPartOfRegion(&fDirtyRegion, region, xOffset, yOffset);
if (fCurrentUpdateSession) if (fCurrentUpdateSession)
_ShiftPartOfRegion(&fCurrentUpdateSession->DirtyRegion(), region, xOffset, yOffset); _ShiftPartOfRegion(&fCurrentUpdateSession->DirtyRegion(), region, xOffset, yOffset);
if (fPendingUpdateSession) if (fPendingUpdateSession)
@@ -390,7 +420,7 @@ WindowLayer::CopyContents(BRegion* region, int32 xOffset, int32 yOffset)
} }
} }
# pragma mark - // #pragma mark -
// _ShiftPartOfRegion // _ShiftPartOfRegion
void void
@@ -415,7 +445,7 @@ WindowLayer::_TriggerContentRedraw()
{ {
//printf("%s - DrawContents()\n", Name()); //printf("%s - DrawContents()\n", Name());
BRegion dirtyContentRegion(fVisibleContentRegion); BRegion dirtyContentRegion(fVisibleContentRegion);
dirtyContentRegion.IntersectWith(fDesktop->DirtyRegion()); dirtyContentRegion.IntersectWith(&fDirtyRegion);
if (dirtyContentRegion.CountRects() > 0) { if (dirtyContentRegion.CountRects() > 0) {
@@ -431,8 +461,6 @@ snooze(100000);
// send UPDATE message to the client // send UPDATE message to the client
_MarkContentDirty(&dirtyContentRegion); _MarkContentDirty(&dirtyContentRegion);
fDesktop->MarkClean(&dirtyContentRegion);
#if DELAYED_BACKGROUND_CLEARING #if DELAYED_BACKGROUND_CLEARING
fTopLayer->Draw(fDrawingEngine, &dirtyContentRegion, fTopLayer->Draw(fDrawingEngine, &dirtyContentRegion,
&fVisibleContentRegion, false); &fVisibleContentRegion, false);
@@ -505,10 +533,13 @@ WindowLayer::_DrawBorder()
// construct the region of the border that needs redrawing // construct the region of the border that needs redrawing
BRegion dirtyBorderRegion; BRegion dirtyBorderRegion;
GetBorderRegion(&dirtyBorderRegion); GetBorderRegion(&dirtyBorderRegion);
// TODO: why is it not enough to only intersect with the dirty region?
// is it faster to intersect the dirty region with the visible when it
// is set in ProcessDirtyRegion()?
// intersect with our visible region // intersect with our visible region
dirtyBorderRegion.IntersectWith(&fVisibleRegion); dirtyBorderRegion.IntersectWith(&fVisibleRegion);
// intersect with the Desktop's dirty region // intersect with the dirty region
dirtyBorderRegion.IntersectWith(fDesktop->DirtyRegion()); dirtyBorderRegion.IntersectWith(&fDirtyRegion);
if (dirtyBorderRegion.CountRects() > 0) { if (dirtyBorderRegion.CountRects() > 0) {
if (fDrawingEngine->Lock()) { if (fDrawingEngine->Lock()) {
@@ -564,8 +595,6 @@ WindowLayer::_DrawBorder()
fDrawingEngine->MarkDirty(&dirtyBorderRegion); fDrawingEngine->MarkDirty(&dirtyBorderRegion);
fDrawingEngine->Unlock(); fDrawingEngine->Unlock();
} }
fDesktop->MarkClean(&dirtyBorderRegion);
} }
} }
@@ -667,7 +696,7 @@ WindowLayer::_EndUpdate()
} }
} }
#pragma mark - // #pragma mark -
// constructor // constructor
UpdateSession::UpdateSession(const BRegion& dirtyRegion) UpdateSession::UpdateSession(const BRegion& dirtyRegion)
@@ -71,6 +71,8 @@ class WindowLayer : public BLooper {
void MarkDirty(BRegion* regionOnScreen); void MarkDirty(BRegion* regionOnScreen);
void MarkContentDirty(BRegion* regionOnScreen); void MarkContentDirty(BRegion* regionOnScreen);
void ProcessDirtyRegion(BRegion* region);
DrawingEngine* GetDrawingEngine() const DrawingEngine* GetDrawingEngine() const
{ return fDrawingEngine; } { return fDrawingEngine; }
@@ -93,11 +95,18 @@ class WindowLayer : public BLooper {
BRect fFrame; BRect fFrame;
// the visible region is only recalculated from the // the visible region is only recalculated from the
// Desktop thread, when using it, Desktop::LockClipping() // Desktop thread, when using it, Desktop::ReadLockClipping()
// has to be called // has to be called
BRegion fVisibleRegion; BRegion fVisibleRegion;
BRegion fVisibleContentRegion; BRegion fVisibleContentRegion;
// our part of the "global" dirty region
// it is calculated from the desktop thread,
// but we can write to it when we read locked
// the clipping, since it is local and the desktop
// thread is blocked
BRegion fDirtyRegion;
// caching local regions // caching local regions
BRegion fBorderRegion; BRegion fBorderRegion;