[haiku-commits] BRANCH looncraz-github.ScreenStream [62c2759aca09] in src: servers/app/drawing servers/app kits/interface

  • From: looncraz-github.ScreenStream <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 30 Mar 2015 03:16:38 +0200 (CEST)

added 1 changeset to branch 'refs/remotes/looncraz-github/ScreenStream'
old head: e2bacf5298027add4b696482de30ff3947964040
new head: 62c2759aca0918326563bd8132afd8d531b896a5
overview: https://github.com/looncraz/haiku/compare/e2bacf529802...62c2759aca09

----------------------------------------------------------------------------

62c2759aca09: Refactoring Complete
  
  Rendering now occurs on the server side, and memory usage is reduced
  by half thanks to now longer using a backing buffer.
  
  Using a special inclusive raw copy in ServerBitmap for performance as
  well as including the full area (akin to BeOS) on region updates.
  
  Found that ServerApp was not settings it fClientToken.
  
  Performance is improved, memory performance is cut in half, and there
  are no more missing dirty regions on the screen (as far sc I can see).

                                        [ looncraz <looncraz@xxxxxxxxxxxx> ]

----------------------------------------------------------------------------

Commit:      62c2759aca0918326563bd8132afd8d531b896a5
Author:      looncraz <looncraz@xxxxxxxxxxxx>
Date:        Mon Mar 30 01:01:04 2015 UTC

----------------------------------------------------------------------------

15 files changed, 536 insertions(+), 169 deletions(-)
headers/os/interface/ScreenStream.h       |  13 +-
src/kits/interface/ScreenStream.cpp       | 140 ++++++++++++--------
src/servers/app/Desktop.cpp               |  54 +++++++-
src/servers/app/IntRect.h                 |  31 +++--
src/servers/app/ServerApp.cpp             |  10 ++
src/servers/app/ServerApp.h               |   2 +
src/servers/app/ServerBitmap.cpp          |  75 +++++++++++
src/servers/app/ServerBitmap.h            |  12 +-
src/servers/app/ServerWindow.cpp          |   2 +-
src/servers/app/drawing/DrawingEngine.cpp |   6 +-
src/servers/app/drawing/DrawingEngine.h   |   2 +-
src/servers/app/drawing/HWInterface.cpp   | 177 +++++++++++++++++++++++---
src/servers/app/drawing/HWInterface.h     |  13 +-
src/servers/app/drawing/UpdateStream.cpp  | 131 +++++++++++--------
src/servers/app/drawing/UpdateStream.h    |  37 ++++--

----------------------------------------------------------------------------

diff --git a/headers/os/interface/ScreenStream.h 
b/headers/os/interface/ScreenStream.h
index 5adb6a2..135250f 100644
--- a/headers/os/interface/ScreenStream.h
+++ b/headers/os/interface/ScreenStream.h
@@ -17,7 +17,8 @@ namespace BPrivate {
 
 class BScreenStream {
 public:
-                                                               
BScreenStream(screen_id id = B_MAIN_SCREEN_ID);
+                                                               
BScreenStream(screen_id id = B_MAIN_SCREEN_ID,
+                                                                       bool 
enableBitmap = true);
        virtual                                         ~BScreenStream();
 
                        status_t                        InitCheck() const;
@@ -41,8 +42,8 @@ public:
                        void                            ShowCursor();
 
                        bigtime_t                       LastUpdate() const;
-                       bigtime_t                       MaxUpdateInterval() 
const;
-                       void                            
SetMaxUpdateInterval(bigtime_t interval);
+                       uint32                          GetMaxFrameRate() const;
+                       void                            SetMaxFrameRate(uint32 
rate);
 
 private:
                        status_t                        _UpdateBitmap();
@@ -51,13 +52,15 @@ private:
        mutable BLocker                         fLock;
                        BScreen                         fScreen;
                        BBitmap*                        fBitmap;
-                       BBitmap*                        fBackMap;
                        BRegion                         fRegion;
                        BRegion                         fRegionMaskUpdate;
                        BRegion                         fRegionMask;
+
                        bigtime_t                       fLastUpdate;
                        bigtime_t                       fMaxUpdateInterval;
-                       bool                            fShowCursor;
+                       uint32                          fMaxFrameRate;
+
+                       bool                            fHideCursor;
                        bool                            fEnableBitmap;
 
                        status_t                        fInitStatus;
diff --git a/src/kits/interface/ScreenStream.cpp 
b/src/kits/interface/ScreenStream.cpp
index 7a7dc5e..dd1cffd 100644
--- a/src/kits/interface/ScreenStream.cpp
+++ b/src/kits/interface/ScreenStream.cpp
@@ -1,15 +1,23 @@
 #include <stdio.h>
 
+#include <Application.h>
 #include <Autolock.h>
-#include <Bitmap.h>
+// Is there a way to get rid of this?
+#      undef private
+#      define private public
+#      include <Bitmap.h>
+#      undef private
+#      define private private
 #include <GraphicsDefs.h>
 #include <Region.h>
 #include <Screen.h>
 #include "ScreenStream.h"
 #include <OS.h>
 
-#include "private/app/ServerProtocol.h"
+#include "private/app/AppMisc.h"
 #include "private/app/DesktopLink.h"
+#include "private/app/ServerProtocol.h"
+
 
 #define DEBUGSS
 
@@ -28,32 +36,57 @@
        doesn't take different screens into account at all when reading
        the screen bitmap, so it would be a moot point until the protocol
        includes the screen ID.
+
+       Our protocol always sends the screen ID, but does nothing with it,
+       for now.
 */
 
-BScreenStream::BScreenStream(screen_id id)
+BScreenStream::BScreenStream(screen_id id, bool enableBitmap)
        :
        fScreen(id),
        fBitmap(NULL),
        fLastUpdate(0),
        fMaxUpdateInterval(16666),      // 60hz, 16.67ms
-       fShowCursor(true),
-       fEnableBitmap(true),
+       fHideCursor(false),
+       fEnableBitmap(enableBitmap),
        fInitStatus(B_NO_INIT),
        fPortLink(new BPrivate::DesktopLink()),
        fStreamID(0)
 {
+       if (be_app == NULL)
+               debugger("BApplication object required!");
+
+       int32 appClientToken = _get_object_token_(be_app);
+       int32 bitmapToken = -1;
+
+       if (enableBitmap) {
+               fInitStatus = _UpdateBitmap();
+               if (fInitStatus != B_OK)
+                       return;
+
+               bitmapToken = fBitmap->_ServerToken();
+       }
+
        int32 reply = B_NO_MEMORY;
        if (fPortLink != NULL
                && fPortLink->InitCheck() == B_OK) {
+
                fPortLink->StartMessage(AS_CREATE_SCREEN_STREAM);
+
                if (fPortLink->Attach(fPortLink->ReceiverPort()) == B_OK
                        && fPortLink->Attach<screen_id>(id) == B_OK
+                       && fPortLink->Attach<int32>(appClientToken) == B_OK
+                       && fPortLink->Attach<int32>(bitmapToken) == B_OK
                        && fPortLink->FlushWithReply(reply) == B_OK) {
 
-                       if (fPortLink->Read(&fStreamID) != B_OK)
-                               fInitStatus = B_BAD_VALUE;
-               } else
+                       if (reply == B_OK) {
+                               if (fPortLink->Read(&fStreamID) != B_OK)
+                                       fInitStatus = B_BAD_VALUE;
+                       }
+               } else {
                        fPortLink->CancelMessage();
+                       STRACE(("Message send failed!\n"));
+               }
        }
 
        fInitStatus = reply;
@@ -93,12 +126,16 @@ BScreenStream::Update()
        if (InitCheck() != B_OK)
                return InitCheck();
 
+       if (fBitmap == NULL
+               && fEnableBitmap)
+               return _UpdateBitmap();
+
        // Limit to a maximum interval
        while (system_time() - fLastUpdate < fMaxUpdateInterval) {
                if (fScreen.WaitForRetrace() != B_OK)
                        snooze(fMaxUpdateInterval/10);
        }
-
+       BAutolock _(fLock);
        fLastUpdate = system_time();
 
        bool success = false;
@@ -108,6 +145,7 @@ BScreenStream::Update()
                if (fPortLink->Attach(fPortLink->ReceiverPort()) == B_OK
                        && fPortLink->Attach(fScreen.ID()) == B_OK
                        && fPortLink->Attach(fStreamID) == B_OK
+                       && fPortLink->Attach(fHideCursor) == B_OK
                        && fPortLink->FlushWithReply(reply) == B_OK) {
                        if (reply == B_OK) {
                                success = true;
@@ -117,7 +155,8 @@ BScreenStream::Update()
                                        fRegionMaskUpdate = fRegion;
                                        
fRegionMaskUpdate.IntersectWith(&fRegionMask);
                                        fRegion.Exclude(&fRegionMask);
-                                       error = _UpdateBitmap();
+                                       if (fEnableBitmap)
+                                               error = _UpdateBitmap();
                                }
 
                        } else {
@@ -208,7 +247,7 @@ bool
 BScreenStream::IsCursorHidden() const
 {
        BAutolock _(fLock);
-       return fShowCursor;
+       return fHideCursor;
 }
 
 
@@ -216,7 +255,7 @@ void
 BScreenStream::HideCursor()
 {
        BAutolock _(fLock);
-       fShowCursor = false;
+       fHideCursor = true;
 }
 
 
@@ -224,7 +263,7 @@ void
 BScreenStream::ShowCursor()
 {
        BAutolock _(fLock);
-       fShowCursor = true;
+       fHideCursor = false;
 }
 
 
@@ -236,19 +275,26 @@ BScreenStream::LastUpdate() const
 }
 
 
-bigtime_t
-BScreenStream::MaxUpdateInterval() const
+uint32
+BScreenStream::GetMaxFrameRate() const
 {
        BAutolock _(fLock);
-       return fMaxUpdateInterval;
+       return fMaxFrameRate;
 }
 
 
 void
-BScreenStream::SetMaxUpdateInterval(bigtime_t interval)
+BScreenStream::SetMaxFrameRate(uint32 rate)
 {
        BAutolock _(fLock);
-       fMaxUpdateInterval = interval;
+
+       if (rate < 1)
+               rate = 1;
+       if (rate > 60)
+               rate = 60;
+
+       fMaxFrameRate = rate;
+       fMaxUpdateInterval = 1000000 / rate;
 }
 
 
@@ -263,44 +309,19 @@ BScreenStream::_UpdateBitmap()
 
        // First update is always a full-update
        if (fBitmap == NULL) {
-               error = fScreen.GetBitmap(&fBitmap, fShowCursor);
-               if (error == B_OK)
-                       error = fScreen.GetBitmap(&fBackMap, fShowCursor);
-               return error;
-       }
-
-
-
-       BRect screenFrame = fBitmap->Bounds();
-
-       for (int i = 0; i < fRegion.CountRects(); ++i) {
-               BRect frame = fRegion.RectAt(i);
-
-               if (frame.IsValid()) {
-
-                       // Include a slightly larger region:
-                       frame.InsetBy(-5, -5);
-                       _Constrain(frame, screenFrame);
-
-                       error = fScreen.ReadBitmap(fBackMap, fShowCursor, 
&frame);
-                       if (error != B_OK) {
-                               STRACE(("Error reading bitmap from screen!\n"));
-                       }
-
-                       fBitmap->ImportBits(fBackMap, BPoint(0, 0),
-                               frame.LeftTop(), frame.Width(), frame.Height());
-
-               } else {
-                       STRACE(("Invalid rect in region!\n\t"));
-                       #ifdef DEBUGSS
-                               frame.PrintToStream();
-                       #endif
+               error = fScreen.GetBitmap(&fBitmap, !fHideCursor);
+               if (error != B_OK) {
+                       STRACE(("ERROR on GetBitmap(): %li\n", error));
+                       return error;
                }
+
+               fRegionMaskUpdate = fRegionMask;
        }
 
+       BRect screenFrame = fBitmap->Bounds();
        BRegion forbidden = fRegionMaskUpdate;
 
-       int32 ppr = fBitmap->BytesPerRow()/4;
+       int32 pixelsPerRow = fBitmap->BytesPerRow()/4;
        uint32 color = 0xffaa0000ul;
 
        uint32* bits = (uint32*)fBitmap->Bits();
@@ -308,14 +329,21 @@ BScreenStream::_UpdateBitmap()
        for (int i = 0; i < forbidden.CountRects(); ++i) {
                BRect rect = forbidden.RectAt(i);
                _Constrain(rect, screenFrame);
-               int yStart = rect.top;
-               int xStart = rect.left;
-               int yEnd = yStart + rect.Height();
-               int xEnd = xStart + rect.Width();
+                       // TODO:
+                       // why in the heck is this STILL required?!?
+                       // The server cleans it up, the draws should never
+                       // attempt to be out of bounds...
+                       // Obviously it is an off-by-one error somewhere
+                               // (ran into this before in the same area, 
seems to be
+                               // a bug with clipping, but all the code looked 
good).
+               int yStart = (int)rect.top;
+               int xStart = (int)rect.left;
+               int yEnd = yStart + (int)rect.Height();
+               int xEnd = xStart + (int)rect.Width();
 
                for (int y = yStart; y < yEnd; ++y)
                        for (int x = xStart; x < xEnd; ++x)
-                               bits[(y*ppr) + x] = color;
+                               bits[(y*pixelsPerRow) + x] = color;
        }
 
        fRegionMaskUpdate.MakeEmpty();
diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp
index 224973e..a4a36ce 100644
--- a/src/servers/app/Desktop.cpp
+++ b/src/servers/app/Desktop.cpp
@@ -1428,6 +1428,7 @@ Desktop::MoveWindowBy(Window* window, float x, float y, 
int32 workspace)
        newDirtyRegion.Exclude(&copyRegion);
 
        MarkDirty(newDirtyRegion);
+
        _SetBackground(background);
        _WindowChanged(window);
 
@@ -1486,7 +1487,7 @@ Desktop::ResizeWindowBy(Window* window, float x, float y)
        // make sure the window cannot mark stuff dirty outside
        // its visible region...
        newDirtyRegion.IntersectWith(&window->VisibleRegion());
-       // ...because we do this outself
+       // ...because we do this ourself
        newDirtyRegion.Include(&previouslyOccupiedRegion);
 
        MarkDirty(newDirtyRegion);
@@ -2533,8 +2534,10 @@ Desktop::_DispatchMessage(int32 code, 
BPrivate::LinkReceiver& link)
 
                        fApplicationsLock.Unlock();
 
-                       if (removeApp != NULL)
+                       if (removeApp != NULL) {
+                               
//HWInterface()->DeleteUpdateStreams(removeApp->ClientToken());
                                removeApp->Quit(fShutdownSemaphore);
+                       }
 
                        if (fQuitting && count <= 1) {
                                // wait for the last app to die
@@ -2654,15 +2657,37 @@ Desktop::_DispatchMessage(int32 code, 
BPrivate::LinkReceiver& link)
                        // Create an UpdateStream and attach it to the our 
HWInterface
                        screen_id screenID = B_MAIN_SCREEN_ID;
                        port_id replyPort = -1;
+                       int32 clientToken = -1;
+                       int32 bitmapToken = -1;
 
                        if (link.Read<port_id>(&replyPort) != B_OK
-                               || link.Read<screen_id>(&screenID) != B_OK)
+                               || link.Read<screen_id>(&screenID) != B_OK
+                               || link.Read<int32>(&clientToken) != B_OK
+                               || link.Read<int32>(&bitmapToken) != B_OK)
                                break;
 
-                       UpdateStream* stream = 
HWInterface()->CreateUpdateStream();
+                       ServerBitmap* bitmap = NULL;
+
+                       // find bitmap for bitmapToken
+                       if (bitmapToken >= 0) {
+                               BAutolock appsLock(fApplicationsLock);
+                               ServerApp* app = NULL;
+                               for (int32 i = fApplications.CountItems(); i-- 
> 0;) {
+                                       app = fApplications.ItemAt(i);
+                                       if (app->ClientToken() == clientToken) {
+                                               bitmap = 
app->GetBitmap(bitmapToken);
+                                               break;
+                                       }
+                               }
+                       }
+
+                       status_t error = B_OK;
+                       UpdateStream* stream = HWInterface()
+                               ->CreateUpdateStream(clientToken, bitmap, 
&error);
+
                        BPrivate::LinkSender replyLink(replyPort);
                        if (stream == NULL) {
-                               replyLink.StartMessage(B_PERMISSION_DENIED);
+                               replyLink.StartMessage(error);
                                replyLink.Flush();
                                break;
                        }
@@ -2678,10 +2703,12 @@ Desktop::_DispatchMessage(int32 code, 
BPrivate::LinkReceiver& link)
                        screen_id screenID = B_MAIN_SCREEN_ID;
                        uint32 streamID = 0;
                        port_id replyPort = -1;
+                       bool hideCursor = false;
 
                        if (link.Read<port_id>(&replyPort) != B_OK
-                               || link.Read<screen_id>(&screenID)
-                               || link.Read<uint32>(&streamID))
+                               || link.Read<screen_id>(&screenID) != B_OK
+                               || link.Read<uint32>(&streamID) != B_OK
+                               || link.Read<bool>(&hideCursor) != B_OK)
                                break;
 
                        UpdateStream* stream = 
HWInterface()->FindUpdateStream(streamID);
@@ -2693,10 +2720,22 @@ Desktop::_DispatchMessage(int32 code, 
BPrivate::LinkReceiver& link)
                                break;
                        }
 
+                       stream->Lock();
+                       stream->SetCursorHidden(hideCursor);
+                       status_t error = 
HWInterface()->RefreshUpdateStream(stream);
+
+                       if (error != B_OK) {
+                               replyLink.StartMessage(error);
+                               replyLink.Flush();
+                               stream->Unlock();
+                               break;
+                       }
+
                        replyLink.StartMessage(B_OK);
                        replyLink.AttachRegion(stream->GetRegion());
                        replyLink.Flush();
                        stream->MakeEmpty();
+                       stream->Unlock();
                        break;
                }
 
@@ -3298,6 +3337,7 @@ Desktop::_SetBackground(BRegion& background)
                        GetDrawingEngine()->UnlockParallelAccess();
                }
        }
+
 }
 
 
diff --git a/src/servers/app/IntRect.h b/src/servers/app/IntRect.h
index f273bb8..5afbaf3 100644
--- a/src/servers/app/IntRect.h
+++ b/src/servers/app/IntRect.h
@@ -21,29 +21,30 @@ class IntRect {
                        int32                           top;
                        int32                           right;
                        int32                           bottom;
-       
+
                                                                IntRect();
+                                                               
IntRect(clipping_rect r);
                                                                IntRect(const 
IntRect& r);
                                                                IntRect(const 
BRect& r);
                                                                IntRect(int32 
l, int32 t, int32 r, int32 b);
                                                                IntRect(const 
IntPoint& lt,
                                                                                
const IntPoint& rb);
-       
+
                        IntRect&                        operator=(const IntRect 
&r);
                        void                            Set(int32 l, int32 t, 
int32 r, int32 b);
-       
+
                        void                            PrintToStream() const;
-       
+
                        IntPoint                        LeftTop() const;
                        IntPoint                        RightBottom() const;
                        IntPoint                        LeftBottom() const;
                        IntPoint                        RightTop() const;
-       
+
                        void                            SetLeftTop(const 
IntPoint& p);
                        void                            SetRightBottom(const 
IntPoint& p);
                        void                            SetLeftBottom(const 
IntPoint& p);
                        void                            SetRightTop(const 
IntPoint& p);
-       
+
                        // transformation
                        void                            InsetBy(const IntPoint& 
p);
                        void                            InsetBy(int32 dx, int32 
dy);
@@ -51,7 +52,7 @@ class IntRect {
                        void                            OffsetBy(int32 dx, 
int32 dy);
                        void                            OffsetTo(const 
IntPoint& p);
                        void                            OffsetTo(int32 x, int32 
y);
-       
+
                        // expression transformations
                        IntRect&                        InsetBySelf(const 
IntPoint& p);
                        IntRect&                        InsetBySelf(int32 dx, 
int32 dy);
@@ -65,11 +66,11 @@ class IntRect {
                        IntRect&                        OffsetToSelf(int32 dx, 
int32 dy);
                        IntRect                         OffsetToCopy(const 
IntPoint& p);
                        IntRect                         OffsetToCopy(int32 dx, 
int32 dy);
-       
+
                        // comparison
                        bool                            operator==(const 
IntRect& r) const;
                        bool                            operator!=(const 
IntRect& r) const;
-       
+
                        // intersection and union
                        IntRect                         operator&(const 
IntRect& r) const;
                        IntRect                         operator|(const 
IntRect& r) const;
@@ -79,7 +80,7 @@ class IntRect {
                                                                operator 
BRect() const
                                                                        { 
return BRect(left, top,
                                                                                
                   right, bottom); }
-       
+
                        bool                            Intersects(const 
IntRect& r) const;
                        bool                            IsValid() const;
                        int32                           Width() const;
@@ -130,6 +131,16 @@ IntRect::IntRect()
 
 
 inline
+IntRect::IntRect(clipping_rect r)
+{
+       left = r.left;
+       top = r.top;
+       right = r.right;
+       bottom = r.bottom;
+}
+
+
+inline
 IntRect::IntRect(int32 l, int32 t, int32 r, int32 b)
 {
        left = l;
diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp
index 678ab3e..b9e89b8 100644
--- a/src/servers/app/ServerApp.cpp
+++ b/src/servers/app/ServerApp.cpp
@@ -94,6 +94,8 @@ ServerApp::ServerApp(Desktop* desktop, port_id 
clientReplyPort,
 
        fMessagePort(-1),
        fClientReplyPort(clientReplyPort),
+       fClientLooperPort(clientLooperPort),
+       fClientToken(clientToken),
        fDesktop(desktop),
        fSignature(signature),
        fClientTeam(clientTeam),
@@ -472,6 +474,14 @@ ServerApp::RemovePicture(ServerPicture* picture)
 }
 
 
+/*! BApplication's BHandler token */
+int32
+ServerApp::ClientToken() const
+{
+       return fClientToken;
+}
+
+
 /*!    Called from the ClientMemoryAllocator whenever a server area could be
        deleted.
        A message is then sent to the client telling it that it can delete its
diff --git a/src/servers/app/ServerApp.h b/src/servers/app/ServerApp.h
index 84c88af..dec56fa 100644
--- a/src/servers/app/ServerApp.h
+++ b/src/servers/app/ServerApp.h
@@ -96,6 +96,8 @@ public:
 
                        void                            
NotifyDeleteClientArea(area_id serverArea);
 
+                       int32                           ClientToken() const;
+
 private:
        virtual void                            _GetLooperName(char* name, 
size_t size);
        virtual void                            _DispatchMessage(int32 code,
diff --git a/src/servers/app/ServerBitmap.cpp b/src/servers/app/ServerBitmap.cpp
index 0123bbf..c9e5334 100644
--- a/src/servers/app/ServerBitmap.cpp
+++ b/src/servers/app/ServerBitmap.cpp
@@ -21,6 +21,7 @@
 #include "HWInterface.h"
 #include "InterfacePrivate.h"
 #include "Overlay.h"
+#include "RenderingBuffer.h"
 #include "ServerApp.h"
 
 
@@ -158,6 +159,80 @@ ServerBitmap::ImportBits(const void *bits, int32 
bitsLength, int32 bytesPerRow,
 }
 
 
+status_t
+ServerBitmap::CopyBits(const RenderingBuffer* buffer,
+                                               const IntRect& copyFrame)
+{
+       if (buffer == NULL)
+               return B_BAD_VALUE;
+
+       int8 bytesPerPixel = BytesPerPixel(buffer->ColorSpace());
+
+       if (BytesPerPixel(ColorSpace()) != bytesPerPixel)
+               return B_MISMATCHED_VALUES;
+
+       if (bytesPerPixel != 4)
+               return B_NOT_ALLOWED;
+
+       // inlined- copybits 32...
+       // the app_server only works in 32-bit anyway - as it is
+
+       IntRect frame = copyFrame;
+       frame.InsetBy(-1, -1);  // become "inclusive"
+       frame = frame & Bounds();
+       if (buffer->Bounds() != Bounds()
+               || !frame.IsValid())
+               return B_ERROR;
+
+       uint32* destBits = (uint32*)Bits();
+       uint32* srcBits = (uint32*)buffer->Bits();
+
+       uint32 pixPerRowDest = BytesPerRow()/bytesPerPixel;
+       uint32 pixPerRowSrc = buffer->BytesPerRow()/bytesPerPixel;
+
+       for (int32 y = frame.top; y < frame.bottom; ++y)
+               for (int32 x = frame.left; x < frame.right; ++x)
+                       destBits[(y * pixPerRowDest) + x]
+                               = srcBits[(y * pixPerRowSrc)+x];
+
+       return B_OK;
+}
+
+
+int8
+ServerBitmap::BytesPerPixel(color_space space)
+{
+       /*
+               Only recognizes RGB format, for now...
+               and only those with whole-bytes
+               TODO: move this somewhere better
+       */
+       switch (space) {
+               case B_RGB32:
+               case B_RGBA32:
+               case B_RGB32_BIG:
+               case B_RGBA32_BIG:
+                       return 4;
+               case B_RGB24:
+               case B_RGB24_BIG:
+                       return 3;
+               case B_RGB16:
+               case B_RGB16_BIG:
+               case B_RGB15:
+               case B_RGB15_BIG:
+                       return 2;
+               case B_GRAY8:
+               case B_CMAP8:
+                       return 1;
+               default:
+                       break;
+       }
+
+       return -1;
+}
+
+
+
 area_id
 ServerBitmap::Area() const
 {
diff --git a/src/servers/app/ServerBitmap.h b/src/servers/app/ServerBitmap.h
index e3b4b36..cd0212b 100644
--- a/src/servers/app/ServerBitmap.h
+++ b/src/servers/app/ServerBitmap.h
@@ -17,11 +17,12 @@
 #include <Referenceable.h>
 
 #include "ClientMemoryAllocator.h"
-
+#include "IntPoint.h"
 
 class BitmapManager;
 class HWInterface;
 class Overlay;
+class RenderingBuffer;
 class ServerApp;
 
 
@@ -80,8 +81,17 @@ public:
                                                                BPoint from, 
BPoint to, int32 width,
                                                                int32 height);
 
+                       // Copy bits raw from the rendering buffer into 
ourselves
+                       // The colorspaces must be the same size per pixel, we 
do
+                       // not worry about conversion.
+                       // Further, the buffer must have our same Bounds()
+                       status_t                CopyBits(const RenderingBuffer* 
buffer,
+                                                                       const 
IntRect& copyFrame);
+
                        void                    PrintToStream();
 
+                       int8                    BytesPerPixel(color_space 
space);
+
 protected:
        friend class BitmapManager;
 
diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp
index 88d1c02..61b52a8c 100644
--- a/src/servers/app/ServerWindow.cpp
+++ b/src/servers/app/ServerWindow.cpp
@@ -351,7 +351,7 @@ ServerWindow::_Show()
        fDesktop->ShowWindow(fWindow);
        if (fDirectWindowInfo && fDirectWindowInfo->IsFullScreen())
                _ResizeToFullScreen();
-               
+
        fDesktop->LockSingleWindow();
 }
 
diff --git a/src/servers/app/drawing/DrawingEngine.cpp 
b/src/servers/app/drawing/DrawingEngine.cpp
index b5c425a..4a6b47b 100644
--- a/src/servers/app/drawing/DrawingEngine.cpp
+++ b/src/servers/app/drawing/DrawingEngine.cpp
@@ -1070,7 +1070,7 @@ DrawingEngine::FillRegion(BRegion& r)
                                doInSoftware = false;
                        }
                }
-       
+
                if (doInSoftware
                        && (fAvailableHWAccleration & HW_ACC_INVERT_REGION) != 0
                        && fPainter->Pattern() == B_SOLID_HIGH
@@ -1551,6 +1551,8 @@ DrawingEngine::CopyRect(BRect src, int32 xOffset, int32 
yOffset) const
                        dst.OffsetBy(xOffset, yOffset);
                }
        }
+
+
        return dst;
 }
 
@@ -1619,7 +1621,7 @@ DrawingEngine::_CopyRect(uint8* src, uint32 width, uint32 
height,
 
 
 inline void
-DrawingEngine::_CopyToFront(const BRect& frame)
+DrawingEngine::_CopyToFront(const IntRect& frame)
 {
        if (fCopyToFront)
                fGraphicsCard->Invalidate(frame);
diff --git a/src/servers/app/drawing/DrawingEngine.h 
b/src/servers/app/drawing/DrawingEngine.h
index dd15db2..26dc55d 100644
--- a/src/servers/app/drawing/DrawingEngine.h
+++ b/src/servers/app/drawing/DrawingEngine.h
@@ -192,7 +192,7 @@ private:
                                                                uint32 height, 
uint32 bytesPerRow,
                                                                int32 xOffset, 
int32 yOffset) const;
 
-       inline  void                    _CopyToFront(const BRect& frame);
+       inline  void                    _CopyToFront(const IntRect& frame);
 
                        Painter*                fPainter;
                        HWInterface*    fGraphicsCard;
diff --git a/src/servers/app/drawing/HWInterface.cpp 
b/src/servers/app/drawing/HWInterface.cpp
index a0a86fb..8b975e5 100644
--- a/src/servers/app/drawing/HWInterface.cpp
+++ b/src/servers/app/drawing/HWInterface.cpp
@@ -346,20 +346,34 @@ HWInterface::IsDoubleBuffered() const
 }
 
 
+//#pragma mark -
+
+
 UpdateStream*
-HWInterface::CreateUpdateStream()
+HWInterface::CreateUpdateStream(int32 clientToken, ServerBitmap* bitmap,
+       status_t* errorOut)
 {
        LockExclusiveAccess();
        UpdateStream* stream = NULL;
 
-       if (DrawingBuffer() != NULL)
+       status_t error = B_OK;
+
+       if (DrawingBuffer() != NULL) {
                stream = new(std::nothrow) UpdateStream(fNextUpdateStreamID++,
-                       DrawingBuffer()->Bounds(), &fRegionPool);
+                                               &fRegionPool, clientToken, 
bitmap);
 
-       if (stream != NULL)
-               fUpdateStreams.AddItem(stream);
+               if (stream != NULL)
+                       fUpdateStreams.AddItem(stream);
+               else
+                       error = B_NO_MEMORY;
+       } else
+               error = B_NO_INIT;
 
        UnlockExclusiveAccess();
+
+       if (errorOut != NULL)
+               *errorOut = error;
+
        return stream;
 }
 
@@ -383,6 +397,116 @@ HWInterface::DeleteUpdateStream(UpdateStream* stream)
 }
 
 
+/*! Delete any and all UpdateStreams belonging to an application */
+status_t
+HWInterface::DeleteUpdateStreams(int32 clientToken)
+{
+       // Called when a client (BApplication) is destroyed
+       // either cleanly, or by crashing.
+       if (clientToken < 0)
+               return B_BAD_INDEX;
+
+       LockExclusiveAccess();
+       BList theDead;
+       status_t error = B_BAD_VALUE;
+       UpdateStream* stream = NULL;
+       for (int index = 0; index < fUpdateStreams.CountItems(); ++index) {
+               stream = (UpdateStream*)fUpdateStreams.ItemAt(index);
+               if (stream->ClientToken() == clientToken) {
+                       theDead.AddItem(stream);
+                       delete stream;
+                       error = B_OK;
+               }
+       }
+
+       for (int index = 0; index < theDead.CountItems(); ++index)
+               fUpdateStreams.RemoveItem(theDead.ItemAt(index));
+
+       UnlockExclusiveAccess();
+       return error;
+}
+
+
+status_t
+HWInterface::RefreshUpdateStream(UpdateStream* stream)
+{
+       if (stream == NULL)
+               return B_BAD_VALUE;
+
+       if (!stream->Lock())
+               return B_PERMISSION_DENIED;
+
+       ServerBitmap* bitmap = stream->GetBitmap();
+
+       // If the stream does not have a bitmap, that is just fine!
+       if (bitmap == NULL) {
+               stream->Unlock();
+               return B_OK;
+       }
+
+       BRegion update = stream->GetRegion();
+       bool hideCursor = stream->IsCursorHidden();
+       RenderingBuffer* buffer = NULL;
+
+       // The back buffer should not contain a copy of the cursor,
+       // it is just used to buffer the draws to the front buffer,
+       // so if it contains a drawing of the cursor, that is just
+       // wasteful as the buffers are never swapped.
+       if (hideCursor) {
+               if (BackBuffer() != NULL) {
+                       buffer = BackBuffer();
+                       hideCursor = false;
+               } else {
+                       // TODO:
+                               // verify update region include cursor frame?
+                               // (almost always does, though, due to batching)
+//                     LockExclusiveAccess();
+                       hideCursor = IsCursorVisible();
+                       if (hideCursor)
+                               HideFloatingOverlays();
+                       //      SetCursorVisible(false);
+//                     UnlockExclusiveAccess();
+               }
+       }
+
+       LockParallelAccess();
+
+       if (buffer == NULL)
+               buffer = FrontBuffer();
+
+       status_t error = B_NO_INIT;
+
+       IntRect rect;
+
+       if (buffer != NULL) {
+               error = B_OK;
+               BPoint bitmapOffset;
+               BPoint bufferOffset;
+
+               for (int index = 0; index < update.CountRects(); ++index) {
+                       rect = (IntRect)update.RectAtInt(index);
+
+                       error = bitmap->CopyBits(buffer, rect);
+
+                       if (error != B_OK)
+                               break;
+               }
+       }
+
+       UnlockParallelAccess();
+
+       if (hideCursor) {
+//             LockExclusiveAccess();
+               ShowFloatingOverlays();
+       //      SetCursorVisible(true);
+//             UnlockExclusiveAccess();
+       }
+
+       stream->Unlock();
+       return error;
+}
+
+
 UpdateStream*
 HWInterface::FindUpdateStream(uint32 clientID)
 {
@@ -400,6 +524,9 @@ HWInterface::FindUpdateStream(uint32 clientID)
 }
 
 
+//#pragma mark -
+
+
 /*! The object needs to be already locked!
 */
 status_t
@@ -438,6 +565,9 @@ HWInterface::Invalidate(const BRect& frame)
 #endif
                return CopyBackToFront(frame);
        }
+
+       _NotifyUpdateStreams(frame);
+
        return B_OK;
 }
 
@@ -452,12 +582,8 @@ HWInterface::CopyBackToFront(const BRect& frame)
 
        IntRect area(frame);
 
-       if (!backBuffer || !frontBuffer) {
-               if (area.IsValid())
-                       _NotifyUpdateStreams(area);
-
+       if (!backBuffer || !frontBuffer)
                return B_NO_INIT;
-       }
 
        // we need to mess with the area, but it is const
        IntRect bufferClip(backBuffer->Bounds());
@@ -506,15 +632,28 @@ HWInterface::_CopyBackToFront(/*const*/ BRegion& region)
 
 
 void
-HWInterface::_NotifyUpdateStreams(const IntRect& frame)
-{      // only called while already locked, but we need to
-       // serialize accesses to the region.
+HWInterface::_NotifyUpdateStreams(const IntRect& _frame)
+{      // only called while already locked, but we need to serialize accesses 
to
+       // the update batch region.
        BAutolock _(fUpdateBatchRegionLock);
-       if (system_time() - fLastUpdateBatch < 8888) {
+       // Only update at clients at ~60hz
+       if (system_time() - fLastUpdateBatch < 16000) {
+               // including a larger area to catch a long-lived off-by-one 
error
+               // somewhere in the clipping code
+               IntRect frame(_frame);
+               frame.InsetBy(-2, -2);
                fUpdateBatchRegion.Include((clipping_rect)frame);
                return;
        }
 
+       RenderingBuffer* buffer = DrawingBuffer();
+               // validity already checked
+
+       // Guarantee the updated region fits without our buffer bounds.
+       BRegion bufferRegion;
+       bufferRegion.Set((clipping_rect)buffer->Bounds());
+       fUpdateBatchRegion.IntersectWith(&bufferRegion);
+
        fLastUpdateBatch = system_time();
        UpdateStream* stream = NULL;
        for (int index = 0; index < fUpdateStreams.CountItems(); ++index) {
@@ -1180,12 +1319,14 @@ HWInterface::_AdoptDragBitmap(const ServerBitmap* 
bitmap, const BPoint& offset)
 void
 HWInterface::_NotifyFrameBufferChanged()
 {
-       if (DrawingBuffer() != NULL) {
+       RenderingBuffer* buffer = DrawingBuffer();
+       if (buffer != NULL) {
+               BRegion region;
+               region.Set((clipping_rect)buffer->Bounds());
                UpdateStream* stream = NULL;
-               IntRect frame = DrawingBuffer()->Bounds();
-               for (int index = 0; index < fUpdateStreams.CountItems(); 
++index) {
+               for (int32 index = 0; index < fUpdateStreams.CountItems(); 
++index) {
                        stream = (UpdateStream*)fUpdateStreams.ItemAt(index);
-                       stream->SetFrame(frame);
+                       stream->IntersectWith(region);
                }
        }
 
diff --git a/src/servers/app/drawing/HWInterface.h 
b/src/servers/app/drawing/HWInterface.h
index 9144fba..638e6af 100644
--- a/src/servers/app/drawing/HWInterface.h
+++ b/src/servers/app/drawing/HWInterface.h
@@ -160,9 +160,16 @@ public:
        virtual bool                            IsDoubleBuffered() const;
 
        // Per-client updated regions
-                       UpdateStream*           CreateUpdateStream();
+       // Do not call while holding a parallel lock!
+       virtual UpdateStream*           CreateUpdateStream(int32 clientToken = 
-1,
+                                                                       
ServerBitmap* bitmap = NULL,
+                                                                       
status_t* error = NULL);
        virtual status_t                        
DeleteUpdateStream(UpdateStream* stream);
-                       UpdateStream*           FindUpdateStream(uint32 
clientID);
+       virtual status_t                        DeleteUpdateStreams(int32 
clientToken);
+       virtual status_t                        
RefreshUpdateStream(UpdateStream* stream);
+       virtual UpdateStream*           FindUpdateStream(uint32 clientID);
+               // FindUpdateStream() can be called while holding a parallel 
lock
+               // or without a lock at all (self-locking)
 
        // Invalidate is used for scheduling an area for updating
        virtual status_t                        InvalidateRegion(BRegion& 
region);
@@ -269,6 +276,8 @@ private:
                        UpdateQueue*            fUpdateExecutor;
 
                        BList                           fListeners;
+
+protected:
                        BList                           fUpdateStreams;
                        BRegion                         fUpdateBatchRegion;
                        BLocker                         fUpdateBatchRegionLock;
diff --git a/src/servers/app/drawing/UpdateStream.cpp 
b/src/servers/app/drawing/UpdateStream.cpp
index 08e8956..dca346e 100644
--- a/src/servers/app/drawing/UpdateStream.cpp
+++ b/src/servers/app/drawing/UpdateStream.cpp
@@ -2,47 +2,55 @@
 #include <Region.h>
 #include <OS.h>
 
-
+#include "ServerBitmap.h"
 #include "UpdateStream.h"
 
 
-/*
-       Represents either a server-side or client-side party which needs to be
-       aware of changes made to the screen since it was last updated.
+/*!    Represents either a server-side or client-side party which needs to be
+       aware of changes made to the HWInterface buffer since it was last 
updated.
 
-       We are owned by HWInterface and the fewest possible number of us
-       should be created since we are updated on each and every updated area
-       on the screen.
+       Owned by HWInterface and derived objects. Does not assume the 
HWInterface
+       buffer implies the screen's frame buffer, since this will not be the 
case
+       with, for example, compositing.
 */
 
 
-UpdateStream::UpdateStream(uint32 id, const IntRect& frame,
-       RegionPool* regionPool)
+UpdateStream::UpdateStream(uint32 id, RegionPool* regionPool,
+               int32 clientToken, ServerBitmap* bitmap)
        :
+       fLock("UpdateStream"),
        fID(id),
-       fRegion(regionPool->GetRegion()),
-       fMaskRegion(NULL),
-       fFrame(regionPool->GetRegion()),
+       fRegion(NULL),
+       fLastRegion(NULL),
+       fBitmap(bitmap),
+       fClientToken(clientToken),
+       fHideCursor(false),
        fRegionPool(regionPool)
        {
-               fFrame->Set((clipping_rect&)frame);
+               if (fRegionPool != NULL) {
+                       fRegion = fRegionPool->GetRegion();
+                       fLastRegion = fRegionPool->GetRegion();
+               } else {
+                       fRegion = new(std::nothrow) BRegion();
+                       fLastRegion = new(std::nothrow) BRegion();
+
+               }
        }
 
 
 UpdateStream::~UpdateStream()
 {
-       fRegionPool->Recycle(fRegion);
-       fRegionPool->Recycle(fFrame);
-
-       if (fMaskRegion != NULL)
-               fRegionPool->Recycle(fMaskRegion);
+       if (fRegionPool != NULL)
+               fRegionPool->Recycle(fRegion);
+       else
+               delete fRegion;
 }
 
 
 void
 UpdateStream::Include(const clipping_rect& frame)
 {
-       BAutolock _(fLock);
+       AutoWriteLocker _(&fLock);
        fRegion->Include(frame);
 }
 
@@ -50,15 +58,28 @@ UpdateStream::Include(const clipping_rect& frame)
 void
 UpdateStream::Include(const BRegion& region)
 {
-       BAutolock _(fLock);
+       AutoWriteLocker _(&fLock);
        fRegion->Include(&region);
 }
 
 
 void
+UpdateStream::IntersectWith(const BRegion& region)
+{
+       // ensure our region is not out of frame
+       AutoWriteLocker _(&fLock);
+       fRegion->IntersectWith(&region);
+}
+
+
+void
 UpdateStream::MakeEmpty()
 {
-       BAutolock _(fLock);
+       AutoWriteLocker _(&fLock);
+
+       BRegion* tempRegionPointer = fRegion;
+       fRegion = fLastRegion;
+       fLastRegion = tempRegionPointer;
        fRegion->MakeEmpty();
 }
 
@@ -66,68 +87,68 @@ UpdateStream::MakeEmpty()
 const BRegion&
 UpdateStream::GetRegion() const
 {
-       BAutolock _(fLock);
-       if (fMaskRegion != NULL)
-               fRegion->Exclude(fMaskRegion);
-
-       fRegion->IntersectWith(fFrame);
+       AutoReadLocker _(&fLock);
        return *fRegion;
 }
 
 
+const BRegion&
+UpdateStream::GetLastRegion() const
+{
+       AutoReadLocker _(&fLock);
+       return *fLastRegion;
+}
+
+
 uint32
 UpdateStream::ID() const
-{
+{      // doesn't change, no need to lock
        return fID;
 }
 
 
-/*! Ignore updates in an area of the screen.
-*/
-
 void
-UpdateStream::SetMaskRegion(const BRegion& mask)
+UpdateStream::SetCursorHidden(bool hidden)
 {
-       BAutolock _(fLock);
-       if (fMaskRegion == NULL)
-               fMaskRegion = fRegionPool->GetRegion();
-
-       *fMaskRegion = mask;
+       AutoWriteLocker _(&fLock);
+       fHideCursor = hidden;
 }
 
 
-void
-UpdateStream::UnsetMaskRegion()
+bool
+UpdateStream::IsCursorHidden() const
 {
-       BAutolock _(fLock);
-       if (fMaskRegion) {
-               fMaskRegion->MakeEmpty();
-               fRegionPool->Recycle(fMaskRegion);
-               fMaskRegion = NULL;
-       }
+       AutoReadLocker _(&fLock);
+       return fHideCursor;
+}
+
+
+int32
+UpdateStream::ClientToken() const
+{      // doesn't change, no need to lock
+       return fClientToken;
 }
 
 
-BRegion*
-UpdateStream::GetMaskRegion()
+ServerBitmap*
+UpdateStream::GetBitmap()
 {
-       BAutolock _(fLock);
-       return fMaskRegion;
+       return fBitmap;
 }
 
 
-const BRegion*
-UpdateStream::GetMaskRegion() const
+bool
+UpdateStream::Lock()
 {
-       BAutolock _(fLock);
-       return fMaskRegion;
+       // Writer threads can nest and also gain read locks
+       // others must wait.
+       return fLock.WriteLock();
 }
 
 
 void
-UpdateStream::SetFrame(const IntRect& frame)
+UpdateStream::Unlock()
 {
-       BAutolock _(fLock);
-       fFrame->Set((clipping_rect&)frame);
+       fLock.WriteUnlock();
 }
 
diff --git a/src/servers/app/drawing/UpdateStream.h 
b/src/servers/app/drawing/UpdateStream.h
index ae6122e..73f3ba8 100644
--- a/src/servers/app/drawing/UpdateStream.h
+++ b/src/servers/app/drawing/UpdateStream.h
@@ -8,38 +8,53 @@
 
 
 #include "IntRect.h"
+#include "MultiLocker.h"
 #include "RegionPool.h"
 
 
+class ServerBitmap;
+
+
 class UpdateStream {
 public:
-                                                               
UpdateStream(uint32 id, const IntRect& frame,
-                                                                       
RegionPool* regionPool);
+                                                               
UpdateStream(uint32 id, RegionPool* pool,
+                                                                               
        int32 clientToken = -1,
+                                                                               
        ServerBitmap* bitmap = NULL);
                                                                ~UpdateStream();
 
                        void                            Include(const 
clipping_rect& frame);
                        void                            Include(const BRegion& 
region);
+                       void                            IntersectWith(const 
BRegion& region);
+
                        void                            MakeEmpty();
 
                        const BRegion&          GetRegion() const;
+                       const BRegion&          GetLastRegion() const;
 
                        uint32                          ID() const;
 
-                       void                            SetMaskRegion(const 
BRegion& mask);
-                       void                            UnsetMaskRegion();
-                       BRegion*                        GetMaskRegion();
-                       const BRegion*          GetMaskRegion() const;
+                       void                            SetCursorHidden(bool 
hidden);
+                       bool                            IsCursorHidden() const;
 
-                       void                            SetFrame(const IntRect& 
frame);
+                       int32                           ClientToken() const;
+                       ServerBitmap*           GetBitmap();
+
+                       bool                            Lock();
+                       void                            Unlock();
 
 private:
-       mutable BLocker                         fLock;
+       mutable MultiLocker                     fLock;
                        uint32                          fID;
-       mutable BRegion*                        fRegion;
-                       BRegion*                        fMaskRegion;
-                       BRegion*                        fFrame;
+
+                       BRegion*                        fRegion;
+                       BRegion*                        fLastRegion;
+
+                       ServerBitmap*           fBitmap;
+                       int32                           fClientToken;
+                       bool                            fHideCursor;
 
                        RegionPool*                     fRegionPool;
+                               // owned by HWInterface
 };
 
 


Other related posts: