I did some profiling using Daniel Reinholds ezprof, which is quite nice actually. I optimized a bit, without spending too much time on that yet, and now the clipping is on average 7 times faster than the current app_server (the time spend in the root layer thread)

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15251 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2005-11-30 20:35:47 +00:00
parent 5ca8477eca
commit 7fd1af6f04
6 changed files with 90 additions and 50 deletions

View File

@ -144,13 +144,13 @@ Desktop::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
if (dx != 0 || dy != 0) {
if (fClickedWindow) {
//bigtime_t now = system_time();
bigtime_t now = system_time();
if (fResizing) {
ResizeWindowBy(fClickedWindow, dx, dy);
//printf("resizing: %lld\n", system_time() - now);
printf("resizing: %lld\n", system_time() - now);
} else {
MoveWindowBy(fClickedWindow, dx, dy);
//printf("moving: %lld\n", system_time() - now);
printf("moving: %lld\n", system_time() - now);
}
}
}

View File

@ -37,7 +37,7 @@ DrawingEngine::Unlock()
#if RUN_WITH_FRAME_BUFFER
Sync();
#else
Flush();
// Flush();
#endif
Window()->Unlock();
}

View File

@ -30,6 +30,7 @@ WindowLayer::WindowLayer(BRect frame, const char* name,
fVisibleRegion(),
fVisibleContentRegion(),
fVisibleContentRegionValid(false),
fDirtyRegion(),
fBorderRegion(),
@ -54,8 +55,8 @@ WindowLayer::WindowLayer(BRect frame, const char* name,
fTokenViewMap(64),
fClient(new ClientLooper(name, this)),
fCurrentUpdateSession(NULL),
fPendingUpdateSession(NULL),
fCurrentUpdateSession(),
fPendingUpdateSession(),
fUpdateRequested(false),
fInUpdate(false)
{
@ -133,9 +134,7 @@ WindowLayer::SetClipping(BRegion* stillAvailableOnScreen)
// clip to region still available on screen
fVisibleRegion.IntersectWith(stillAvailableOnScreen);
GetContentRegion(&fVisibleContentRegion);
fVisibleContentRegion.IntersectWith(&fVisibleRegion);
fVisibleContentRegionValid = false;
fEffectiveDrawingRegionValid = false;
}
@ -188,6 +187,18 @@ WindowLayer::GetContentRegion(BRegion* region)
*region = fContentRegion;
}
// VisibleContentRegion
BRegion&
WindowLayer::VisibleContentRegion()
{
// regions expected to be locked
if (!fVisibleContentRegionValid) {
GetContentRegion(&fVisibleContentRegion);
fVisibleContentRegion.IntersectWith(&fVisibleRegion);
}
return fVisibleContentRegion;
}
// SetFocus
void
WindowLayer::SetFocus(bool focus)
@ -224,10 +235,10 @@ WindowLayer::MoveBy(int32 x, int32 y)
if (fContentRegionValid)
fContentRegion.OffsetBy(x, y);
if (fCurrentUpdateSession)
fCurrentUpdateSession->MoveBy(x, y);
if (fPendingUpdateSession)
fPendingUpdateSession->MoveBy(x, y);
if (fCurrentUpdateSession.IsUsed())
fCurrentUpdateSession.MoveBy(x, y);
if (fPendingUpdateSession.IsUsed())
fPendingUpdateSession.MoveBy(x, y);
fEffectiveDrawingRegionValid = false;
@ -357,7 +368,7 @@ WindowLayer::MarkContentDirty(BRegion* regionOnScreen)
// an update message is triggered
if (fDesktop && fDesktop->ReadLockClipping()) {
regionOnScreen->IntersectWith(&fVisibleContentRegion);
regionOnScreen->IntersectWith(&VisibleContentRegion());
ProcessDirtyRegion(regionOnScreen);
fDesktop->ReadUnlockClipping();
@ -377,8 +388,10 @@ WindowLayer::CopyContents(BRegion* region, int32 xOffset, int32 yOffset)
BRegion newDirty(*region);
// clip the region to the visible contents at the
// source and destination location
region->IntersectWith(&fVisibleContentRegion);
// source and destination location (not that VisibleContentRegion()
// is used once to make sure it is valid, then fVisibleContentRegion
// is used directly)
region->IntersectWith(&VisibleContentRegion());
if (region->CountRects() > 0) {
region->OffsetBy(xOffset, yOffset);
region->IntersectWith(&fVisibleContentRegion);
@ -397,10 +410,10 @@ WindowLayer::CopyContents(BRegion* region, int32 xOffset, int32 yOffset)
// move along the already dirty regions that are common
// with the region that we could copy
_ShiftPartOfRegion(&fDirtyRegion, region, xOffset, yOffset);
if (fCurrentUpdateSession)
_ShiftPartOfRegion(&fCurrentUpdateSession->DirtyRegion(), region, xOffset, yOffset);
if (fPendingUpdateSession)
_ShiftPartOfRegion(&fPendingUpdateSession->DirtyRegion(), region, xOffset, yOffset);
if (fCurrentUpdateSession.IsUsed())
_ShiftPartOfRegion(&fCurrentUpdateSession.DirtyRegion(), region, xOffset, yOffset);
if (fPendingUpdateSession.IsUsed())
_ShiftPartOfRegion(&fPendingUpdateSession.DirtyRegion(), region, xOffset, yOffset);
}
}
@ -444,7 +457,7 @@ void
WindowLayer::_TriggerContentRedraw()
{
//printf("%s - DrawContents()\n", Name());
BRegion dirtyContentRegion(fVisibleContentRegion);
BRegion dirtyContentRegion(VisibleContentRegion());
dirtyContentRegion.IntersectWith(&fDirtyRegion);
if (dirtyContentRegion.CountRects() > 0) {
@ -490,10 +503,10 @@ WindowLayer::_DrawClient(int32 token)
if (fDesktop->ReadLockClipping()) {
if (!fEffectiveDrawingRegionValid) {
fEffectiveDrawingRegion = fVisibleContentRegion;
fEffectiveDrawingRegion = VisibleContentRegion();
if (fInUpdate) {
// enforce the dirty region of the update session
fEffectiveDrawingRegion.IntersectWith(&fCurrentUpdateSession->DirtyRegion());
fEffectiveDrawingRegion.IntersectWith(&fCurrentUpdateSession.DirtyRegion());
} else {
printf("%s - _DrawClient(token: %ld) - not in update\n", Name(), token);
}
@ -615,13 +628,9 @@ WindowLayer::_MarkContentDirty(BRegion* contentDirtyRegion)
if (contentDirtyRegion->CountRects() <= 0)
return;
if (!fPendingUpdateSession) {
// create new pending
fPendingUpdateSession = new UpdateSession(*contentDirtyRegion);
} else {
// add to pending
fPendingUpdateSession->Include(contentDirtyRegion);
}
// add to pending
fPendingUpdateSession.SetUsed(true);
fPendingUpdateSession.Include(contentDirtyRegion);
// clip pending update session from current
// update session, it makes no sense to draw stuff
@ -629,8 +638,8 @@ WindowLayer::_MarkContentDirty(BRegion* contentDirtyRegion)
// this could be done smarter (clip layers from pending
// that have not yet been redrawn in the current update
// session)
if (fCurrentUpdateSession) {
fCurrentUpdateSession->Exclude(contentDirtyRegion);
if (fCurrentUpdateSession.IsUsed()) {
fCurrentUpdateSession.Exclude(contentDirtyRegion);
fEffectiveDrawingRegionValid = false;
}
@ -658,11 +667,14 @@ WindowLayer::_BeginUpdate()
// at the same time.
if (fDesktop->ReadLockClipping()) {
if (fUpdateRequested && !fCurrentUpdateSession) {
fCurrentUpdateSession = fPendingUpdateSession;
fPendingUpdateSession = NULL;
if (fCurrentUpdateSession) {
if (fUpdateRequested && !fCurrentUpdateSession.IsUsed()) {
if (fPendingUpdateSession.IsUsed()) {
// TODO: the toggling between the update sessions is too
// expensive, optimize with some pointer tricks
fCurrentUpdateSession = fPendingUpdateSession;
fPendingUpdateSession.SetUsed(false);
// all drawing command from the client
// will have the dirty region from the update
// session enforced
@ -671,7 +683,7 @@ WindowLayer::_BeginUpdate()
fEffectiveDrawingRegionValid = false;
}
fDesktop->ReadUnlockClipping();
fDesktop->ReadUnlockClipping();
}
}
@ -683,13 +695,12 @@ WindowLayer::_EndUpdate()
if (fDesktop->ReadLockClipping()) {
if (fInUpdate) {
delete fCurrentUpdateSession;
fCurrentUpdateSession = NULL;
fCurrentUpdateSession.SetUsed(false);
fInUpdate = false;
fEffectiveDrawingRegionValid = false;
}
if (fPendingUpdateSession) {
if (fPendingUpdateSession.IsUsed()) {
// send this to client
fClient->PostMessage(MSG_UPDATE);
fUpdateRequested = true;
@ -720,8 +731,9 @@ WindowLayer::_UpdateContentRegion()
// #pragma mark -
// constructor
UpdateSession::UpdateSession(const BRegion& dirtyRegion)
: fDirtyRegion(dirtyRegion)
UpdateSession::UpdateSession()
: fDirtyRegion(),
fInUse(false)
{
}
@ -751,6 +763,22 @@ UpdateSession::MoveBy(int32 x, int32 y)
fDirtyRegion.OffsetBy(x, y);
}
// SetUsed
void
UpdateSession::SetUsed(bool used)
{
fInUse = used;
if (!fInUse) {
fDirtyRegion.MakeEmpty();
}
}
// operator=
UpdateSession&
UpdateSession::operator=(const UpdateSession& other)
{
fDirtyRegion = other.fDirtyRegion;
}

View File

@ -23,7 +23,7 @@ enum {
class UpdateSession {
public:
UpdateSession(const BRegion& dirtyRegion);
UpdateSession();
virtual ~UpdateSession();
void Include(BRegion* additionalDirty);
@ -34,8 +34,15 @@ class UpdateSession {
void MoveBy(int32 x, int32 y);
void SetUsed(bool used);
inline bool IsUsed() const
{ return fInUse; }
UpdateSession& operator=(const UpdateSession& other);
private:
BRegion fDirtyRegion;
bool fInUse;
};
class WindowLayer : public BLooper {
@ -49,9 +56,12 @@ class WindowLayer : public BLooper {
inline BRect Frame() const
{ return fFrame; }
// setting and getting the "hard" clipping
void SetClipping(BRegion* stillAvailableOnScreen);
inline BRegion& VisibleRegion()
{ return fVisibleRegion; }
BRegion& VisibleContentRegion();
void GetFullRegion(BRegion* region) const;
void GetBorderRegion(BRegion* region);
void GetContentRegion(BRegion* region);
@ -102,6 +112,7 @@ class WindowLayer : public BLooper {
// has to be called
BRegion fVisibleRegion;
BRegion fVisibleContentRegion;
bool fVisibleContentRegionValid;
// our part of the "global" dirty region
// it is calculated from the desktop thread,
// but we can write to it when we read locked
@ -142,8 +153,8 @@ class WindowLayer : public BLooper {
// this is the current update session. All new
// redraw requests from the root layer will go
// into the pending update session.
UpdateSession* fCurrentUpdateSession;
UpdateSession* fPendingUpdateSession;
UpdateSession fCurrentUpdateSession;
UpdateSession fPendingUpdateSession;
// these two flags are supposed to ensure a sane
// and consistent update session
bool fUpdateRequested;

View File

@ -181,14 +181,14 @@ Window::Test()
AddWindow(frame, name.String());
}
/* frame.Set(10, 80, 320, 290);
frame.Set(10, 80, 320, 290);
for (int32 i = 20; i < 40; i++) {
BString name("Window ");
frame.OffsetBy(20, 15);
name << i + 1;
AddWindow(frame, name.String());
}
/*
frame.Set(20, 140, 330, 230);
for (int32 i = 40; i < 60; i++) {
BString name("Window ");

View File

@ -36,7 +36,8 @@ SRCS= ClientLooper.cpp \
main.cpp \
MultiLocker.cpp \
ViewLayer.cpp \
WindowLayer.cpp
WindowLayer.cpp \
# trace.c
# specify the resource files to use
# full path or a relative path to the resource file can be used.
@ -105,7 +106,7 @@ SYMBOLS =
DEBUGGER =
# specify additional compiler flags for all files
COMPILER_FLAGS =
COMPILER_FLAGS = #-finstrument-functions
# specify additional linker flags
LINKER_FLAGS =