]> source.dussan.org Git - tigervnc.git/commitdiff
Be more aggressive in finding solid rectangles
authorPierre Ossman <ossman@cendio.se>
Thu, 12 Feb 2015 12:44:22 +0000 (13:44 +0100)
committerPierre Ossman <ossman@cendio.se>
Fri, 13 Feb 2015 12:20:49 +0000 (13:20 +0100)
The previous FIXME was incorrect. The old code did in fact continue
looking over the entire area. This commit restores that old behaviour.

common/rfb/EncodeManager.cxx
common/rfb/EncodeManager.h

index cd80df97cca016a12c45827aad1ce8e589b14e73..3142ec0ed769b2013385ace4cf336b86003e9c87 100644 (file)
@@ -452,83 +452,104 @@ void EncodeManager::writeSolidRects(Region *changed, const PixelBuffer* pb)
   std::vector<Rect> rects;
   std::vector<Rect>::const_iterator rect;
 
-  // FIXME: This gives up after the first rect it finds. A large update
-  //        (like a whole screen refresh) might have lots of large solid
-  //        areas.
-
   changed->get_rects(&rects);
-  for (rect = rects.begin(); rect != rects.end(); ++rect) {
-    Rect sr;
-    int dx, dy, dw, dh;
-
-    // We start by finding a solid 16x16 block
-    for (dy = rect->tl.y; dy < rect->br.y; dy += SolidSearchBlock) {
-
-      dh = SolidSearchBlock;
-      if (dy + dh > rect->br.y)
-        dh = rect->br.y - dy;
-
-      for (dx = rect->tl.x; dx < rect->br.x; dx += SolidSearchBlock) {
-        // We define it like this to guarantee alignment
-        rdr::U32 _buffer;
-        rdr::U8* colourValue = (rdr::U8*)&_buffer;
-
-        dw = SolidSearchBlock;
-        if (dx + dw > rect->br.x)
-          dw = rect->br.x - dx;
-
-        pb->getImage(colourValue, Rect(dx, dy, dx+1, dy+1));
-
-        sr.setXYWH(dx, dy, dw, dh);
-        if (checkSolidTile(sr, colourValue, pb)) {
-          Rect erb, erp;
-
-          Encoder *encoder;
-
-          // We then try extending the area by adding more blocks
-          // in both directions and pick the combination that gives
-          // the largest area.
-          sr.setXYWH(dx, dy, rect->br.x - dx, rect->br.y - dy);
-          extendSolidAreaByBlock(sr, colourValue, pb, &erb);
-
-          // Did we end up getting the entire rectangle?
-          if (erb.equals(*rect))
-            erp = erb;
-          else {
-            // Don't bother with sending tiny rectangles
-            if (erb.area() < SolidBlockMinArea)
-              continue;
-
-            // Extend the area again, but this time one pixel
-            // row/column at a time.
-            extendSolidAreaByPixel(*rect, erb, colourValue, pb, &erp);
-          }
-
-          // Send solid-color rectangle.
-          encoder = startRect(erp, encoderSolid);
-          if (encoder->flags & EncoderUseNativePF) {
-            encoder->writeSolidRect(erp.width(), erp.height(),
-                                    pb->getPF(), colourValue);
-          } else {
-            rdr::U32 _buffer2;
-            rdr::U8* converted = (rdr::U8*)&_buffer2;
-
-            conn->cp.pf().bufferFromBuffer(converted, pb->getPF(),
-                                           colourValue, 1);
-
-            encoder->writeSolidRect(erp.width(), erp.height(),
-                                    conn->cp.pf(), converted);
-          }
-          endRect();
-
-          changed->assign_subtract(Region(erp));
-
-          break;
+  for (rect = rects.begin(); rect != rects.end(); ++rect)
+    findSolidRect(*rect, changed, pb);
+}
+
+void EncodeManager::findSolidRect(const Rect& rect, Region *changed,
+                                  const PixelBuffer* pb)
+{
+  Rect sr;
+  int dx, dy, dw, dh;
+
+  // We start by finding a solid 16x16 block
+  for (dy = rect.tl.y; dy < rect.br.y; dy += SolidSearchBlock) {
+
+    dh = SolidSearchBlock;
+    if (dy + dh > rect.br.y)
+      dh = rect.br.y - dy;
+
+    for (dx = rect.tl.x; dx < rect.br.x; dx += SolidSearchBlock) {
+      // We define it like this to guarantee alignment
+      rdr::U32 _buffer;
+      rdr::U8* colourValue = (rdr::U8*)&_buffer;
+
+      dw = SolidSearchBlock;
+      if (dx + dw > rect.br.x)
+        dw = rect.br.x - dx;
+
+      pb->getImage(colourValue, Rect(dx, dy, dx+1, dy+1));
+
+      sr.setXYWH(dx, dy, dw, dh);
+      if (checkSolidTile(sr, colourValue, pb)) {
+        Rect erb, erp;
+
+        Encoder *encoder;
+
+        // We then try extending the area by adding more blocks
+        // in both directions and pick the combination that gives
+        // the largest area.
+        sr.setXYWH(dx, dy, rect.br.x - dx, rect.br.y - dy);
+        extendSolidAreaByBlock(sr, colourValue, pb, &erb);
+
+        // Did we end up getting the entire rectangle?
+        if (erb.equals(rect))
+          erp = erb;
+        else {
+          // Don't bother with sending tiny rectangles
+          if (erb.area() < SolidBlockMinArea)
+            continue;
+
+          // Extend the area again, but this time one pixel
+          // row/column at a time.
+          extendSolidAreaByPixel(rect, erb, colourValue, pb, &erp);
         }
-      }
 
-      if (dx < rect->br.x)
-        break;
+        // Send solid-color rectangle.
+        encoder = startRect(erp, encoderSolid);
+        if (encoder->flags & EncoderUseNativePF) {
+          encoder->writeSolidRect(erp.width(), erp.height(),
+                                  pb->getPF(), colourValue);
+        } else {
+          rdr::U32 _buffer2;
+          rdr::U8* converted = (rdr::U8*)&_buffer2;
+
+          conn->cp.pf().bufferFromBuffer(converted, pb->getPF(),
+                                         colourValue, 1);
+
+          encoder->writeSolidRect(erp.width(), erp.height(),
+                                  conn->cp.pf(), converted);
+        }
+        endRect();
+
+        changed->assign_subtract(Region(erp));
+
+        // Search remaining areas by recursion
+        // FIXME: Is this the best way to divide things up?
+
+        // Left? (Note that we've already searched a SolidSearchBlock
+        //        pixels high strip here)
+        if ((erp.tl.x != rect.tl.x) && (erp.height() > SolidSearchBlock)) {
+          sr.setXYWH(rect.tl.x, erp.tl.y + SolidSearchBlock,
+                     erp.tl.x - rect.tl.x, erp.height() - SolidSearchBlock);
+          findSolidRect(sr, changed, pb);
+        }
+
+        // Right?
+        if (erp.br.x != rect.br.x) {
+          sr.setXYWH(erp.br.x, erp.tl.y, rect.br.x - erp.br.x, erp.height());
+          findSolidRect(sr, changed, pb);
+        }
+
+        // Below?
+        if (erp.br.y != rect.br.y) {
+          sr.setXYWH(rect.tl.x, erp.br.y, rect.width(), rect.br.y - erp.br.y);
+          findSolidRect(sr, changed, pb);
+        }
+
+        return;
+      }
     }
   }
 }
index a694e063e4eacbcadaf3b14367873890cd2071ae..a3df8f746160af77c90b863370426175bbbf2612 100644 (file)
@@ -59,6 +59,7 @@ namespace rfb {
 
     void writeCopyRects(const UpdateInfo& ui);
     void writeSolidRects(Region *changed, const PixelBuffer* pb);
+    void findSolidRect(const Rect& rect, Region *changed, const PixelBuffer* pb);
     void writeRects(const Region& changed, const PixelBuffer* pb);
 
     void writeSubRect(const Rect& rect, const PixelBuffer *pb);