]> source.dussan.org Git - tigervnc.git/commitdiff
Polling screen area around current pointer position with higher
authorConstantin Kaplinsky <const@tightvnc.com>
Wed, 8 Feb 2006 13:36:58 +0000 (13:36 +0000)
committerConstantin Kaplinsky <const@tightvnc.com>
Wed, 8 Feb 2006 13:36:58 +0000 (13:36 +0000)
priority. Also, there is a number of code improvements, and some new
"FIXME" comments for potential future improvements.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@477 3789f03b-4d11-0410-bbf8-ca57d06f2519

x0vncserver/Image.cxx
x0vncserver/Image.h
x0vncserver/PollingManager.cxx
x0vncserver/PollingManager.h
x0vncserver/x0vncserver.cxx

index b310619d1cfcc365dee70a876089a2c3d7020c32..36b2de440d8b974e9696c397e55ba2156ec00f7a 100644 (file)
@@ -106,14 +106,38 @@ void Image::get(Window wnd, int x, int y, int w, int h)
   XGetSubImage(dpy, wnd, x, y, w, h, AllPlanes, ZPixmap, xim, 0, 0);
 }
 
-void Image::updateRect(Image *src, int dst_x, int dst_y)
+//
+// Copying pixels from one image to another.
+//
+// FIXME: Use Point and Rect structures?
+// FIXME: Too many similar methods?
+//
+
+inline
+void Image::copyPixels(XImage *src,
+                       int dst_x, int dst_y,
+                       int src_x, int src_y,
+                       int w, int h)
 {
-  updateRect(src->xim, dst_x, dst_y);
+  const char *srcOffset =
+    src->data + (src_y * src->bytes_per_line +
+                 src_x * (src->bits_per_pixel / 8));
+  char *dstOffset =
+    xim->data + (dst_y * xim->bytes_per_line +
+                 dst_x * (xim->bits_per_pixel / 8));
+
+  int rowLength = w * (xim->bits_per_pixel / 8);
+
+  for (int i = 0; i < h ; i++) {
+    memcpy(dstOffset, srcOffset, rowLength);
+    srcOffset += src->bytes_per_line;
+    dstOffset += xim->bytes_per_line;
+  }
 }
 
 void Image::updateRect(XImage *src, int dst_x, int dst_y)
 {
-  // Limit width and height at destination image size
+  // Limit width and height at destination image size.
   int w = src->width;
   if (dst_x + w > xim->width)
     w = xim->width - dst_x;
@@ -121,16 +145,54 @@ void Image::updateRect(XImage *src, int dst_x, int dst_y)
   if (dst_y + h > xim->height)
     h = xim->height - dst_y;
 
-  // Copy pixels
-  const char *srcOffset = src->data;
-  char *dstOffset = xim->data + (dst_y * xim->bytes_per_line +
-                                 dst_x * (xim->bits_per_pixel / 8));
-  int lineLength = w * (xim->bits_per_pixel / 8);
-  for (int i = 0; i < h ; i++) {
-    memcpy(dstOffset, srcOffset, lineLength);
-    srcOffset += src->bytes_per_line;
-    dstOffset += xim->bytes_per_line;
-  }
+  copyPixels(src, dst_x, dst_y, 0, 0, w, h);
+}
+
+void Image::updateRect(Image *src, int dst_x, int dst_y)
+{
+  updateRect(src->xim, dst_x, dst_y);
+}
+
+void Image::updateRect(XImage *src, int dst_x, int dst_y, int w, int h)
+{
+  // Correct width and height if necessary.
+  if (w > src->width)
+    w = src->width;
+  if (dst_x + w > xim->width)
+    w = xim->width - dst_x;
+  if (h > src->height)
+    h = src->height;
+  if (dst_y + h > xim->height)
+    h = xim->height - dst_y;
+
+  copyPixels(src, dst_x, dst_y, 0, 0, w, h);
+}
+
+void Image::updateRect(Image *src, int dst_x, int dst_y, int w, int h)
+{
+  updateRect(src->xim, dst_x, dst_y, w, h);
+}
+
+void Image::updateRect(XImage *src, int dst_x, int dst_y,
+                       int src_x, int src_y, int w, int h)
+{
+  // Correct width and height if necessary.
+  if (src_x + w > src->width)
+    w = src->width - src_x;
+  if (dst_x + w > xim->width)
+    w = xim->width - dst_x;
+  if (src_y + h > src->height)
+    h = src->height - src_y;
+  if (dst_y + h > xim->height)
+    h = xim->height - dst_y;
+
+  copyPixels(src, dst_x, dst_y, src_x, src_y, w, h);
+}
+
+void Image::updateRect(Image *src, int dst_x, int dst_y,
+                       int src_x, int src_y, int w, int h)
+{
+  updateRect(src->xim, dst_x, dst_y, src_x, src_y, w, h);
 }
 
 #ifdef HAVE_MITSHM
@@ -433,6 +495,8 @@ void SolarisOverlayImage::get(Window wnd, int x, int y, int w, int h)
 //
 // ImageFactory class implementation
 //
+// FIXME: Make ImageFactory always create images of the same class?
+//
 
 // Prepare useful shortcuts for compile-time options.
 #if defined(HAVE_READDISPLAY) && defined(HAVE_MITSHM)
@@ -456,6 +520,7 @@ Image *ImageFactory::newImage(Display *d, int width, int height)
   Image *image = NULL;
 
   // First, try to create an image with overlay support.
+  // FIXME: Replace fprintf() with proper logging.
 
 #ifdef HAVE_OVERLAY_EXT
   if (mayUseOverlay) {
index 032e24a8200c8f9db7ee6bda51a89de80b89d21c..e3de17d0b5eff9972f971001589b59d025624661 100644 (file)
@@ -43,8 +43,15 @@ public:
   virtual void get(Window wnd, int x = 0, int y = 0);
   virtual void get(Window wnd, int x, int y, int w, int h);
 
-  virtual void updateRect(Image *src, int dst_x = 0, int dst_y = 0);
+// Copying pixels from one image to another.
   virtual void updateRect(XImage *src, int dst_x = 0, int dst_y = 0);
+  virtual void updateRect(Image *src, int dst_x = 0, int dst_y = 0);
+  virtual void updateRect(XImage *src, int dst_x, int dst_y, int w, int h);
+  virtual void updateRect(Image *src, int dst_x, int dst_y, int w, int h);
+  virtual void updateRect(XImage *src, int dst_x, int dst_y,
+                          int src_x, int src_y, int w, int h);
+  virtual void updateRect(Image *src, int dst_x, int dst_y,
+                          int src_x, int src_y, int w, int h);
 
   // Pointer to corresponding XImage, made public for efficiency.
   // NOTE: if this field is NULL, then no methods other than Init()
@@ -55,6 +62,12 @@ protected:
 
   void Init(int width, int height);
 
+  // Like updateRect(), but does not check arguments.
+  void copyPixels(XImage *src,
+                  int dst_x, int dst_y,
+                  int src_x, int src_y,
+                  int w, int h);
+
   Display *dpy;
   bool trueColor;
 
index 9491d766dbc04b46cc19e61096b8edb57540031c..00580e01d407a15615a5379139bd5c632025b68d 100644 (file)
 // PollingManager.cxx
 //
 
+// FIXME: Don't compare pixels already marked as changed.
+// FIXME: Use Image::copyPixels() instead of Image::updateRect()?
+//        In that case, note the fact that arguments are not checked.
+
 #include <stdio.h>
 #include <string.h>
 #include <sys/time.h>
 #include <X11/Xlib.h>
 #include <rfb/VNCServer.h>
 #include <rfb/Configuration.h>
+#include <rfb/ServerCore.h>
 
 #include <x0vncserver/Image.h>
 #include <x0vncserver/PollingManager.h>
 
-IntParameter pollingType("PollingType", "Polling algorithm to use (0..3)", 3);
+BoolParameter PollingManager::pollPointer
+("PollPointer",
+ "Poll area under the pointer with higher priority",
+ true);
+
+IntParameter PollingManager::pollingType
+("PollingType",
+ "Polling algorithm to use (0..3)",
+ 3);
 
 const int PollingManager::m_pollingOrder[32] = {
    0, 16,  8, 24,  4, 20, 12, 28,
@@ -47,7 +60,8 @@ const int PollingManager::m_pollingOrder[32] = {
 
 PollingManager::PollingManager(Display *dpy, Image *image,
                                ImageFactory *factory)
-  : m_dpy(dpy), m_server(0), m_image(image), m_pollingStep(0)
+  : m_dpy(dpy), m_server(0), m_image(image), m_pointerPosKnown(false),
+    m_pollingStep(0)
 {
   // Save width and height of the screen (and the image).
   m_width = m_image->xim->width;
@@ -57,10 +71,11 @@ PollingManager::PollingManager(Display *dpy, Image *image,
   m_widthTiles = (m_width + 31) / 32;
   m_heightTiles = (m_height + 31) / 32;
 
-  // Create two additional images used in the polling algorithm.
+  // Create additional images used in the polling algorithm.
   // FIXME: verify that these images use the same pixel format as in m_image.
   m_rowImage = factory->newImage(m_dpy, m_width, 1);
   m_tileImage = factory->newImage(m_dpy, 32, 32);
+  m_areaImage = factory->newImage(m_dpy, 128, 128);
 
   // FIXME: Extend the comment.
   // Create a matrix with one byte per each 32x32 tile. It will be
@@ -89,6 +104,10 @@ PollingManager::~PollingManager()
   delete[] m_rateMatrix;
 
   delete[] m_statusMatrix;
+
+  delete m_areaImage;
+  delete m_tileImage;
+  delete m_rowImage;
 }
 
 //
@@ -100,6 +119,28 @@ void PollingManager::setVNCServer(VNCServer *s)
   m_server = s;
 }
 
+//
+// Update current pointer position which may be used as a hint for
+// polling algorithms.
+//
+
+void PollingManager::setPointerPos(const Point &pos)
+{
+  m_pointerPos = pos;
+  m_pointerPosKnown = true;
+}
+
+//
+// Indicate that current pointer position is unknown.
+// FIXME: Perhaps this should be done automatically after a number of
+//        polling cycles if the cursor position have not been changed?
+//
+
+void PollingManager::unsetPointerPos()
+{
+  m_pointerPosKnown = false;
+}
+
 //
 // DEBUG: a version of poll() measuring time spent in the function.
 //
@@ -160,7 +201,7 @@ bool PollingManager::poll_DetectVideo()
 
   bool grandStep = (m_pollingStep % GRAND_STEP_DIVISOR == 0);
 
-  // FIXME: Save shortcuts in member variables.
+  // FIXME: Save shortcuts in member variables?
   int scanLine = m_pollingOrder[m_pollingStep++ % 32];
   int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
   int bytesPerLine = m_image->xim->bytes_per_line;
@@ -217,6 +258,11 @@ bool PollingManager::poll_DetectVideo()
   if (grandStep)
     adjustVideoArea();
 
+  // FIXME: Exclude area near the pointer from the comparisons above.
+  // FIXME: Code duplication.
+  if (pollPointer && m_pointerPosKnown && pollPointerArea())
+    nTilesChanged++;
+
   return (nTilesChanged != 0);
 }
 
@@ -281,6 +327,11 @@ bool PollingManager::poll_SkipCycles()
     }
   }
 
+  // FIXME: Exclude area near the pointer from the comparisons above.
+  // FIXME: Code duplication.
+  if (pollPointer && m_pointerPosKnown && pollPointerArea())
+    nTilesChanged++;
+
   return (nTilesChanged != 0);
 }
 
@@ -323,6 +374,11 @@ bool PollingManager::poll_Traditional()
     }
   }
 
+  // FIXME: Exclude area near the pointer from the comparisons above.
+  // FIXME: Code duplication.
+  if (pollPointer && m_pointerPosKnown && pollPointerArea())
+    nTilesChanged++;
+
   return (nTilesChanged != 0);
 }
 
@@ -339,17 +395,118 @@ bool PollingManager::poll_Dumb()
   Rect rect(0, 0, m_width, m_height);
   m_server->add_changed(rect);
 
-  // As we have no idea if any pixels were changed,
-  // always report that some changes have been detected.
+  // Report that some changes have been detected.
+  return true;
+}
+
+//
+// Compute coordinates of the rectangle around the pointer.
+//
+
+void PollingManager::computePointerArea(Rect *r)
+{
+  int x = m_pointerPos.x - 64;
+  int y = m_pointerPos.y - 64;
+  int w = 128;
+  int h = 128;
+  if (x < 0) {
+    w += x; x = 0;
+  }
+  if (x + w > m_width) {
+    w = m_width - x;
+  }
+  if (y < 0) {
+    h += y; y = 0;
+  }
+  if (y + h > m_height) {
+    h = m_height - y;
+  }
+
+  r->setXYWH(x, y, w, h);
+}
+
+//
+// Poll the area under current pointer position. Each pixel of the
+// area should be compared. Using such polling option gives higher
+// priority to screen area under the pointer.
+//
+// ASSUMES: (m_server != NULL && m_pointerPosKnown != false)
+//
+
+bool PollingManager::pollPointerArea()
+{
+  Rect r;
+  computePointerArea(&r);
+
+  // Shortcuts for coordinates.
+  int x = r.tl.x, y = r.tl.y;
+  int w = r.width(), h = r.height();
+
+  // Get new pixels.
+  if (w == 128 && h == 128) {
+    m_areaImage->get(DefaultRootWindow(m_dpy), x, y);
+  } else {
+    m_areaImage->get(DefaultRootWindow(m_dpy), x, y, w, h);
+  }
+
+  // Now, try to minimize the rectangle by cutting out unchanged
+  // borders (at top and bottom).
+  //
+  // FIXME: Perhaps we should work on 32x32 tiles (properly aligned)
+  //        to produce a region instead of a rectangle. If there would
+  //        be just one universal polling algorithm, it could be
+  //        better to integrate pointer area polling into that
+  //        algorithm, instead of a separate pollPointerArea()
+  //        function.
+
+  // Shortcuts.
+  int bytesPerPixel = m_image->xim->bits_per_pixel / 8;
+  int oldBytesPerLine = m_image->xim->bytes_per_line;
+  int newBytesPerLine = m_areaImage->xim->bytes_per_line;
+  char *oldPtr = m_image->xim->data + y * oldBytesPerLine + x * bytesPerPixel;
+  char *newPtr = m_areaImage->xim->data;
+
+  // Check and cut out unchanged rows at the top.
+  int ty;
+  for (ty = 0; ty < h; ty++) {
+    if (memcmp(oldPtr, newPtr, w * bytesPerPixel) != 0)
+      break;
+    oldPtr += oldBytesPerLine;
+    newPtr += newBytesPerLine;
+  }
+  if (ty == h) {
+    return false;               // no changes at all
+  }
+  y += ty; h -= ty;
+
+  // Check and cut out unchanged rows at the bottom.
+  oldPtr = m_image->xim->data + (y+h-1) * oldBytesPerLine + x * bytesPerPixel;
+  newPtr = m_areaImage->xim->data + (ty+h-1) * newBytesPerLine;
+  int by;
+  for (by = 0; by < h - 1; by++) {
+    if (memcmp(oldPtr, newPtr, w * bytesPerPixel) != 0)
+      break;
+    oldPtr -= oldBytesPerLine;
+    newPtr -= newBytesPerLine;
+  }
+  h -= by;
+
+  // Copy pixels.
+  m_image->updateRect(m_areaImage, x, y, 0, ty, w, h);
+
+  // Report updates to the server.
+  Rect rect(x, y, x+w, y+h);
+  m_server->add_changed(rect);
   return true;
 }
 
 //
-// FIXME: Replace with a normal comment.
 // Make video area pattern more regular.
 //
+// FIXME: Replace the above with a normal comment.
+// FIXME: Is the function efficient enough?
+//
 
-// FIXME: Is it efficient enough?
 void PollingManager::adjustVideoArea()
 {
   char newFlags[m_widthTiles * m_heightTiles];
index 8f7f820ae4b43da01a39d5ff6bc697c1b76244f2..a35fafee8ba61d2c94118cd717510c92f05ae259 100644 (file)
@@ -38,9 +38,17 @@ public:
   virtual ~PollingManager();
 
   void setVNCServer(VNCServer *s);
+
+  void setPointerPos(const Point &pos);
+  void unsetPointerPos();
+
   void pollDebug();
   void poll();
 
+  // Configurable parameters.
+  static BoolParameter pollPointer;
+  static IntParameter pollingType;
+
 protected:
 
   //
@@ -52,6 +60,10 @@ protected:
   bool poll_Traditional();
   bool poll_Dumb();
 
+  // Separate polling for the area around current pointer position.
+  void computePointerArea(Rect *r);
+  bool pollPointerArea();
+
   Display *m_dpy;
   VNCServer *m_server;
 
@@ -61,12 +73,18 @@ protected:
   int m_widthTiles;
   int m_heightTiles;
 
+  // Tracking pointer position for polling improvements.
+  bool m_pointerPosKnown;
+  Point m_pointerPos;
+
 private:
 
   void adjustVideoArea();
 
-  Image *m_rowImage;
-  Image *m_tileImage;
+  // Additional images used in polling algorithms.
+  Image *m_rowImage;            // One row of the framebuffer
+  Image *m_tileImage;           // One tile (32x32 or less)
+  Image *m_areaImage;           // Area around the pointer (up to 128x128)
 
   char *m_statusMatrix;
 
index f799de3a52b11d598f980322ff47450cb3744d0c..f718164fd33f14871f8d56134d48df7f29414304 100644 (file)
@@ -146,6 +146,7 @@ public:
   // -=- SDesktop interface
 
   virtual void pointerEvent(const Point& pos, rdr::U8 buttonMask) {
+    pollmgr->setPointerPos(pos);
 #ifdef HAVE_XTEST
     if (!haveXtest) return;
     XTestFakeMotionEvent(dpy, DefaultScreen(dpy), pos.x, pos.y, CurrentTime);