From ffac272e35477046672497199d86c09ec2053d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Mon, 10 Mar 2008 22:30:07 +0000 Subject: [PATCH] Used the new mechanism/options in the DrawingEngine with regard to back to front copies in Window for updates. When in an update session, any back to front copies are turned off. When the update session ends, the whole region is copied at once. This has two effects: For once, it avoids a lot of unnecessary copies (for example, rendering text copied the background and then the same area for the text again). But even more effective, it changes the entire drawing of any Haiku app to be completely flicker free. Provided it happens in the normal Invalidate()/Draw() cycle. And of course all this only works for double buffering mode, ie VESA. Potentially, I might have overlooked something, so that this patch could result in some drawing glitches, but in my testing, I have seen none yet. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24354 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/Window.cpp | 150 +++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 72 deletions(-) diff --git a/src/servers/app/Window.cpp b/src/servers/app/Window.cpp index 6373c8be42..93488e98c9 100644 --- a/src/servers/app/Window.cpp +++ b/src/servers/app/Window.cpp @@ -1739,12 +1739,15 @@ Window::_TriggerContentRedraw(BRegion& dirtyContentRegion) } if (fDrawingEngine->LockParallelAccess()) { + bool copyToFrontEnabled = fDrawingEngine->CopyToFrontEnabled(); + fDrawingEngine->SetCopyToFrontEnabled(true); fDrawingEngine->SuspendAutoSync(); fTopView->Draw(fDrawingEngine, backgroundClearingRegion, &fContentRegion, true); fDrawingEngine->Sync(); + fDrawingEngine->SetCopyToFrontEnabled(copyToFrontEnabled); fDrawingEngine->UnlockParallelAccess(); } } @@ -1775,8 +1778,13 @@ Window::_DrawBorder() DrawingEngine* engine = fDecorator->GetDrawingEngine(); if (dirtyBorderRegion->CountRects() > 0 && engine->LockParallelAccess()) { engine->ConstrainClippingRegion(dirtyBorderRegion); + bool copyToFrontEnabled = engine->CopyToFrontEnabled(); + engine->SetCopyToFrontEnabled(true); + fDecorator->Draw(dirtyBorderRegion->Frame()); + engine->SetCopyToFrontEnabled(copyToFrontEnabled); + // TODO: remove this once the DrawState stuff is handled // more cleanly. The reason why this is needed is that // when the decorator draws strings, a draw state is set @@ -1815,23 +1823,6 @@ Window::_TransferToUpdateSession(BRegion* contentDirtyRegion) fPendingUpdateSession->AddCause(fDirtyCause); fPendingUpdateSession->Include(contentDirtyRegion); - // clip pending update session from current - // update session, it makes no sense to draw stuff - // already needing a redraw anyways. Theoretically, - // this could be done smarter (clip views from pending - // that have not yet been redrawn in the current update - // session) - // NOTE: appearently the R5 app_server does not do that, it just - // keeps drawing until the screen is valid, without caring much - // for a consistent display while it does so, it just keeps drawing - // until everything settles down. Potentially, this could even give - // the impression of faster updates, even though they might look - // wrong when looked at closer, but will fix themselves shortly later -// if (fCurrentUpdateSession->IsUsed() && fCurrentUpdateSession->IsExpose()) { -// fCurrentUpdateSession->Exclude(contentDirtyRegion); -// fEffectiveDrawingRegionValid = false; -// } - if (!fUpdateRequested) { // send this to client _SendUpdateMessage(); @@ -1867,36 +1858,42 @@ Window::BeginUpdate(BPrivate::PortLink& link) // dirty regions are not messed with from the Desktop thread // and ServerWindow thread at the same time. - if (fUpdateRequested) { - // make the pending update session the current update session - // (toggle the pointers) - UpdateSession* temp = fCurrentUpdateSession; - fCurrentUpdateSession = fPendingUpdateSession; - fPendingUpdateSession = temp; - fPendingUpdateSession->SetUsed(false); - // all drawing command from the client - // will have the dirty region from the update - // session enforced - fInUpdate = true; - fEffectiveDrawingRegionValid = false; + if (!fUpdateRequested) { + link.StartMessage(B_ERROR); + link.Flush(); + fprintf(stderr, "Window::BeginUpdate() - no update requested!\n"); + return; + } - // TODO: each view could be drawn individually - // right before carrying out the first drawing - // command from the client during an update - // (View::IsBackgroundDirty() can be used - // for this) - if (!fContentRegionValid) - _UpdateContentRegion(); + // make the pending update session the current update session + // (toggle the pointers) + UpdateSession* temp = fCurrentUpdateSession; + fCurrentUpdateSession = fPendingUpdateSession; + fPendingUpdateSession = temp; + fPendingUpdateSession->SetUsed(false); + // all drawing command from the client + // will have the dirty region from the update + // session enforced + fInUpdate = true; + fEffectiveDrawingRegionValid = false; - BRegion* dirty = fRegionPool.GetRegion( - fCurrentUpdateSession->DirtyRegion()); - if (!dirty) { - link.StartMessage(B_ERROR); - link.Flush(); - return; - } + // TODO: each view could be drawn individually + // right before carrying out the first drawing + // command from the client during an update + // (View::IsBackgroundDirty() can be used + // for this) + if (!fContentRegionValid) + _UpdateContentRegion(); - dirty->IntersectWith(&VisibleContentRegion()); + BRegion* dirty = fRegionPool.GetRegion( + fCurrentUpdateSession->DirtyRegion()); + if (!dirty) { + link.StartMessage(B_ERROR); + link.Flush(); + return; + } + + dirty->IntersectWith(&VisibleContentRegion()); //sCurrentColor.red = rand() % 255; //sCurrentColor.green = rand() % 255; @@ -1907,39 +1904,35 @@ Window::BeginUpdate(BPrivate::PortLink& link) //fDrawingEngine->FillRegion(*dirty, sCurrentColor); //snooze(10000); - link.StartMessage(B_OK); - // append the current window geometry to the - // message, the client will need it - link.Attach(fFrame.LeftTop()); - link.Attach(fFrame.Width()); - link.Attach(fFrame.Height()); - // append he update rect in screen coords - link.Attach(dirty->Frame()); - // find and attach all views that intersect with - // the dirty region - fTopView->AddTokensForViewsInRegion(link, *dirty, &fContentRegion); - // mark the end of the token "list" - link.Attach(B_NULL_TOKEN); - link.Flush(); + link.StartMessage(B_OK); + // append the current window geometry to the + // message, the client will need it + link.Attach(fFrame.LeftTop()); + link.Attach(fFrame.Width()); + link.Attach(fFrame.Height()); + // append he update rect in screen coords + link.Attach(dirty->Frame()); + // find and attach all views that intersect with + // the dirty region + fTopView->AddTokensForViewsInRegion(link, *dirty, &fContentRegion); + // mark the end of the token "list" + link.Attach(B_NULL_TOKEN); + link.Flush(); - if (!fCurrentUpdateSession->IsExpose() && fDrawingEngine->LockParallelAccess()) { + // supress back to front buffer copies in the drawing engine + fDrawingEngine->SetCopyToFrontEnabled(false); + + if (!fCurrentUpdateSession->IsExpose() && fDrawingEngine->LockParallelAccess()) { //fDrawingEngine->FillRegion(dirty, (rgb_color){ 255, 0, 0, 255 }); - fDrawingEngine->SuspendAutoSync(); + fDrawingEngine->SuspendAutoSync(); - fTopView->Draw(fDrawingEngine, dirty, &fContentRegion, true); + fTopView->Draw(fDrawingEngine, dirty, &fContentRegion, true); - fDrawingEngine->Sync(); - fDrawingEngine->UnlockParallelAccess(); - } // else the background was cleared already + fDrawingEngine->Sync(); + fDrawingEngine->UnlockParallelAccess(); + } // else the background was cleared already - fRegionPool.Recycle(dirty); - - } else { -printf("BeginUpdate() but no update requested!!\n"); - link.StartMessage(B_ERROR); - link.Flush(); - fprintf(stderr, "Window::BeginUpdate() - no update requested!\n"); - } + fRegionPool.Recycle(dirty); } @@ -1949,6 +1942,19 @@ Window::EndUpdate() // NOTE: see comment in _BeginUpdate() if (fInUpdate) { + // reenable copy to front + fDrawingEngine->SetCopyToFrontEnabled(true); + + BRegion* dirty = fRegionPool.GetRegion( + fCurrentUpdateSession->DirtyRegion()); + + if (dirty) { + dirty->IntersectWith(&VisibleContentRegion()); + + fDrawingEngine->CopyToFront(*dirty); + fRegionPool.Recycle(dirty); + } + fCurrentUpdateSession->SetUsed(false); fInUpdate = false;