[haiku-commits] r40014 - haiku/trunk/src/servers/app/drawing/remote

  • From: mmlr@xxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 29 Dec 2010 08:03:03 +0100 (CET)

Author: mmlr
Date: 2010-12-29 08:03:03 +0100 (Wed, 29 Dec 2010)
New Revision: 40014
Changeset: http://dev.haiku-os.org/changeset/40014

Modified:
   haiku/trunk/src/servers/app/drawing/remote/RemoteDrawingEngine.cpp
   haiku/trunk/src/servers/app/drawing/remote/RemoteDrawingEngine.h
Log:
Implement a new RP_DRAW_BITMAP_RECTS which splits up bitmaps to be sent into the
relevant parts (i.e. removes clipped or out of bounds parts) and does local
scaling in case the view rect is smaller than the bitmap rect. This avoids
sending the full blown bitmaps across when they are in the end scaled to a much
smaller representation. It's nowhere near perfect yet, but it's useable and
improves the network traffic heaviness quite a bit depending on the application.


Modified: haiku/trunk/src/servers/app/drawing/remote/RemoteDrawingEngine.cpp
===================================================================
--- haiku/trunk/src/servers/app/drawing/remote/RemoteDrawingEngine.cpp  
2010-12-29 05:58:39 UTC (rev 40013)
+++ haiku/trunk/src/servers/app/drawing/remote/RemoteDrawingEngine.cpp  
2010-12-29 07:03:03 UTC (rev 40014)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009, Haiku, Inc.
+ * Copyright 2009-2010, Haiku, Inc.
  * Distributed under the terms of the MIT License.
  *
  * Authors:
@@ -9,6 +9,7 @@
 #include "RemoteDrawingEngine.h"
 #include "RemoteMessage.h"
 
+#include "BitmapDrawingEngine.h"
 #include "DrawState.h"
 
 #include <Bitmap.h>
@@ -24,7 +25,8 @@
        fToken((uint32)this), // TODO: need to redo that for 64 bit
        fExtendWidth(0),
        fCallbackAdded(false),
-       fResultNotify(-1)
+       fResultNotify(-1),
+       fBitmapDrawingEngine(NULL)
 {
        RemoteMessage message(NULL, fHWInterface->SendBuffer());
        message.Start(RP_CREATE_STATE);
@@ -39,6 +41,8 @@
        message.Add(fToken);
        message.Flush();
 
+       delete fBitmapDrawingEngine;
+
        if (fCallbackAdded)
                fHWInterface->RemoveCallback(fToken);
        if (fResultNotify >= 0)
@@ -288,47 +292,67 @@
 RemoteDrawingEngine::DrawBitmap(ServerBitmap* bitmap, const BRect& _bitmapRect,
        const BRect& _viewRect, uint32 options)
 {
-       if (!fClippingRegion.Intersects(_viewRect))
-               return;
-
+       BRect bitmapRect = _bitmapRect;
        BRect viewRect = _viewRect;
-       BRect bitmapRect = _bitmapRect;
-       if (bitmapRect.IntegerWidth() == viewRect.IntegerWidth()
-               && bitmapRect.IntegerHeight() == viewRect.IntegerHeight()) {
-               // unscaled bitmap we can chop off stuff we don't need
-               BRegion target(viewRect);
-               target.IntersectWith(&fClippingRegion);
-               BRect frame = target.Frame();
+       double xScale = (bitmapRect.Width() + 1) / (viewRect.Width() + 1);
+       double yScale = (bitmapRect.Height() + 1) / (viewRect.Height() + 1);
 
-               if (frame != viewRect) {
-                       BPoint offset = frame.LeftTop() - viewRect.LeftTop();
-                       viewRect = frame;
-                       bitmapRect = viewRect.OffsetToCopy(bitmapRect.LeftTop() 
+ offset);
-               }
+       // constrain rect to passed bitmap bounds
+       // and transfer the changes to the viewRect with the right scale
+       BRect actualBitmapRect = bitmap->Bounds();
+       if (bitmapRect.left < actualBitmapRect.left) {
+               float diff = actualBitmapRect.left - bitmapRect.left;
+               viewRect.left += diff / xScale;
+               bitmapRect.left = actualBitmapRect.left;
        }
+       if (bitmapRect.top < actualBitmapRect.top) {
+               float diff = actualBitmapRect.top - bitmapRect.top;
+               viewRect.top += diff / yScale;
+               bitmapRect.top = actualBitmapRect.top;
+       }
+       if (bitmapRect.right > actualBitmapRect.right) {
+               float diff = bitmapRect.right - actualBitmapRect.right;
+               viewRect.right -= diff / xScale;
+               bitmapRect.right = actualBitmapRect.right;
+       }
+       if (bitmapRect.bottom > actualBitmapRect.bottom) {
+               float diff = bitmapRect.bottom - actualBitmapRect.bottom;
+               viewRect.bottom -= diff / yScale;
+               bitmapRect.bottom = actualBitmapRect.bottom;
+       }
 
-       UtilityBitmap* other = NULL;
-       BRect bounds = bitmap->Bounds();
-       BRect newBounds;
-       newBounds.right
-               = min_c(bounds.IntegerWidth(), bitmapRect.IntegerWidth());
-       newBounds.bottom        
-               = min_c(bounds.IntegerHeight(), bitmapRect.IntegerHeight());
+       BRegion clippedRegion(viewRect);
+       clippedRegion.IntersectWith(&fClippingRegion);
 
-       if (newBounds.IntegerWidth() < bounds.IntegerWidth()
-               || newBounds.IntegerHeight() < bounds.IntegerHeight()) {
+       int32 rectCount = clippedRegion.CountRects();
+       if (rectCount == 0)
+               return;
 
-               other = new(std::nothrow) UtilityBitmap(newBounds, 
bitmap->ColorSpace(),
-                       bitmap->Flags());
+       if (rectCount > 1 || (rectCount == 1 && clippedRegion.RectAt(0) != 
viewRect)
+               || viewRect.Width() < bitmapRect.Width()
+               || viewRect.Height() < bitmapRect.Height()) {
+               UtilityBitmap** bitmaps;
+               if (_ExtractBitmapRegions(*bitmap, options, bitmapRect, 
viewRect,
+                               xScale, yScale, clippedRegion, bitmaps) != 
B_OK) {
+                       return;
+               }
 
-               if (other != NULL && other->ImportBits(bitmap->Bits(),
-                               bitmap->BitsLength(), bitmap->BytesPerRow(),
-                               bitmap->ColorSpace(), bitmapRect.LeftTop(), 
BPoint(0, 0),
-                               newBounds.IntegerWidth() + 1,
-                               newBounds.IntegerHeight() + 1) == B_OK) {
-                       bitmapRect.OffsetTo(0, 0);
-                       bitmap = other;
+               RemoteMessage message(NULL, fHWInterface->SendBuffer());
+               message.Start(RP_DRAW_BITMAP_RECTS);
+               message.Add(fToken);
+               message.Add(options);
+               message.Add(bitmap->ColorSpace());
+               message.Add(bitmap->Flags());
+               message.Add(rectCount);
+
+               for (int32 i = 0; i < rectCount; i++) {
+                       message.Add(clippedRegion.RectAt(i));
+                       message.AddBitmap(*bitmaps[i], true);
+                       delete bitmaps[i];
                }
+
+               free(bitmaps);
+               return;
        }
 
        // TODO: we may want to cache/checksum bitmaps
@@ -339,9 +363,6 @@
        message.Add(viewRect);
        message.Add(options);
        message.AddBitmap(*bitmap);
-
-       if (other != NULL)
-               delete other;
 }
 
 
@@ -972,3 +993,120 @@
 
        return bounds;
 }
+
+
+status_t
+RemoteDrawingEngine::_ExtractBitmapRegions(ServerBitmap& bitmap, uint32 
options,
+       const BRect& bitmapRect, const BRect& viewRect, double xScale,
+       double yScale, BRegion& region, UtilityBitmap**& bitmaps)
+{
+       int32 rectCount = region.CountRects();
+       bitmaps = (UtilityBitmap**)malloc(rectCount * sizeof(UtilityBitmap*));
+       if (bitmaps == NULL)
+               return B_NO_MEMORY;
+
+       for (int32 i = 0; i < rectCount; i++) {
+               BRect sourceRect = 
region.RectAt(i).OffsetByCopy(-viewRect.LeftTop());
+               int32 targetWidth = (int32)(sourceRect.Width() + 1.5);
+               int32 targetHeight = (int32)(sourceRect.Height() + 1.5);
+
+               if (xScale != 1.0) {
+                       sourceRect.left = (int32)(sourceRect.left * xScale + 
0.5);
+                       sourceRect.right = (int32)(sourceRect.right * xScale + 
0.5);
+                       if (xScale < 1.0)
+                               targetWidth = (int32)(sourceRect.Width() + 1.5);
+               }
+
+               if (yScale != 1.0) {
+                       sourceRect.top = (int32)(sourceRect.top * yScale + 0.5);
+                       sourceRect.bottom = (int32)(sourceRect.bottom * yScale 
+ 0.5);
+                       if (yScale < 1.0)
+                               targetHeight = (int32)(sourceRect.Height() + 
1.5);
+               }
+
+               sourceRect.OffsetBy(bitmapRect.LeftTop());
+                       // sourceRect is now the part of the bitmap we want 
copied
+
+               status_t result = B_OK;
+               if ((xScale > 1.0 || yScale > 1.0)
+                       && (targetWidth * targetHeight < 
(int32)(sourceRect.Width() + 1.5)
+                               * (int32)(sourceRect.Height() + 1.5))) {
+                       // the target bitmap is smaller than the source, scale 
it locally
+                       // and send over the smaller version to avoid sending 
any extra data
+                       if (fBitmapDrawingEngine == NULL) {
+                               fBitmapDrawingEngine
+                                       = new(std::nothrow) 
BitmapDrawingEngine(B_RGBA32);
+                               if (fBitmapDrawingEngine == NULL)
+                                       result = B_NO_MEMORY;
+                       }
+
+                       if (result == B_OK) {
+                               result = 
fBitmapDrawingEngine->SetSize(targetWidth,
+                                       targetHeight);
+                       }
+
+                       if (result == B_OK) {
+                               fBitmapDrawingEngine->SetDrawingMode(B_OP_COPY);
+
+                               switch (bitmap.ColorSpace()) {
+                                       case B_RGBA32:
+                                       case B_RGBA32_BIG:
+                                       case B_RGBA15:
+                                       case B_RGBA15_BIG:
+                                               break;
+
+                                       default:
+                                       {
+                                               // we need to clear the 
background if there may be
+                                               // transparency through 
transparent magic (we use
+                                               // B_OP_COPY when we draw alpha 
enabled bitmaps, so we
+                                               // don't need to clear there)
+                                               // TODO: this is not actually 
correct, as we're going to
+                                               // loose the transparency with 
the conversion to the
+                                               // original non-alpha 
colorspace happening in
+                                               // ExportToBitmap
+                                               rgb_color background = { 0, 0, 
0, 0 };
+                                               fBitmapDrawingEngine->FillRect(
+                                                       BRect(0, 0, targetWidth 
- 1, targetHeight -1),
+                                                       background);
+                                               
fBitmapDrawingEngine->SetDrawingMode(B_OP_OVER);
+                                               break;
+                                       }
+                               }
+
+                               fBitmapDrawingEngine->DrawBitmap(&bitmap, 
sourceRect,
+                                       BRect(0, 0, targetWidth - 1, 
targetHeight - 1), options);
+                               bitmaps[i] = 
fBitmapDrawingEngine->ExportToBitmap(targetWidth,
+                                       targetHeight, bitmap.ColorSpace());
+                               if (bitmaps[i] == NULL)
+                                       result = B_NO_MEMORY;
+                       }
+               } else {
+                       // source is smaller or equal target, extract the 
relevant rects
+                       // directly without any scaling and conversion
+                       targetWidth = (int32)(sourceRect.Width() + 1.5);
+                       targetHeight = (int32)(sourceRect.Height() + 1.5);
+
+                       bitmaps[i] = new(std::nothrow) UtilityBitmap(
+                               BRect(0, 0, targetWidth - 1, targetHeight - 1),
+                               bitmap.ColorSpace(), 0);
+                       if (bitmaps[i] == NULL)
+                               result = B_NO_MEMORY;
+
+                       result = bitmaps[i]->ImportBits(bitmap.Bits(), 
bitmap.BitsLength(),
+                               bitmap.BytesPerRow(), bitmap.ColorSpace(), 
sourceRect.LeftTop(),
+                               BPoint(0, 0), targetWidth, targetHeight);
+                       if (result != B_OK)
+                               delete bitmaps[i];
+               }
+
+               if (result != B_OK) {
+                       for (int32 j = 0; j < i; j++)
+                               delete bitmaps[j];
+                       free(bitmaps);
+                       return result;
+               }
+       }
+
+       return B_OK;
+}

Modified: haiku/trunk/src/servers/app/drawing/remote/RemoteDrawingEngine.h
===================================================================
--- haiku/trunk/src/servers/app/drawing/remote/RemoteDrawingEngine.h    
2010-12-29 05:58:39 UTC (rev 40013)
+++ haiku/trunk/src/servers/app/drawing/remote/RemoteDrawingEngine.h    
2010-12-29 07:03:03 UTC (rev 40014)
@@ -13,6 +13,13 @@
 #include "RemoteHWInterface.h"
 #include "ServerFont.h"
 
+class BPoint;
+class BRect;
+class BRegion;
+
+class BitmapDrawingEngine;
+class ServerBitmap;
+
 class RemoteDrawingEngine : public DrawingEngine {
 public:
                                                                
RemoteDrawingEngine(
@@ -99,18 +106,18 @@
                                                                        float 
yRadius, const BGradient& gradient);
 
        virtual void                            DrawShape(const BRect& bounds,
-                                                                       int32 
opCount, const uint32* opList, 
+                                                                       int32 
opCount, const uint32* opList,
                                                                        int32 
pointCount, const BPoint* pointList,
                                                                        bool 
filled,
                                                                        const 
BPoint& viewToScreenOffset,
                                                                        float 
viewScale);
        virtual void                            FillShape(const BRect& bounds,
-                                                                       int32 
opCount, const uint32* opList, 
+                                                                       int32 
opCount, const uint32* opList,
                                                                        int32 
pointCount, const BPoint* pointList,
                                                                        const 
BGradient& gradient,
                                                                        const 
BPoint& viewToScreenOffset,
                                                                        float 
viewScale);
-       
+
        virtual void                            DrawTriangle(BPoint* points,
                                                                        const 
BRect& bounds, bool filled);
        virtual void                            FillTriangle(BPoint* points,
@@ -147,6 +154,11 @@
                                                                        
RemoteMessage& message);
 
                        BRect                           _BuildBounds(BPoint* 
points, int32 pointCount);
+               status_t                                
_ExtractBitmapRegions(ServerBitmap& bitmap,
+                                                                       uint32 
options, const BRect& bitmapRect,
+                                                                       const 
BRect& viewRect, double xScale,
+                                                                       double 
yScale, BRegion& region,
+                                                                       
UtilityBitmap**& bitmaps);
 
                        RemoteHWInterface*      fHWInterface;
                        uint32                          fToken;
@@ -160,6 +172,8 @@
                        BPoint                          fDrawStringResult;
                        float                           fStringWidthResult;
                        BBitmap*                        fReadBitmapResult;
+
+               BitmapDrawingEngine*    fBitmapDrawingEngine;
 };
 
 #endif // REMOTE_DRAWING_ENGINE_H


Other related posts:

  • » [haiku-commits] r40014 - haiku/trunk/src/servers/app/drawing/remote - mmlr