aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorConstantin Kaplinsky <const@tightvnc.com>2006-02-08 13:36:58 +0000
committerConstantin Kaplinsky <const@tightvnc.com>2006-02-08 13:36:58 +0000
commitce676c671ae9904723fc4cad90aca9749e99586f (patch)
tree8d42fe7ab2fa37ad32ace2abec0ba5e3344bd37f
parent6df6990dc8766fbe31d4a193d5d72d0c5bc7105e (diff)
downloadtigervnc-ce676c671ae9904723fc4cad90aca9749e99586f.tar.gz
tigervnc-ce676c671ae9904723fc4cad90aca9749e99586f.zip
Polling screen area around current pointer position with higher
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
-rw-r--r--x0vncserver/Image.cxx91
-rw-r--r--x0vncserver/Image.h15
-rw-r--r--x0vncserver/PollingManager.cxx173
-rw-r--r--x0vncserver/PollingManager.h22
-rw-r--r--x0vncserver/x0vncserver.cxx1
5 files changed, 278 insertions, 24 deletions
diff --git a/x0vncserver/Image.cxx b/x0vncserver/Image.cxx
index b310619d..36b2de44 100644
--- a/x0vncserver/Image.cxx
+++ b/x0vncserver/Image.cxx
@@ -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) {
diff --git a/x0vncserver/Image.h b/x0vncserver/Image.h
index 032e24a8..e3de17d0 100644
--- a/x0vncserver/Image.h
+++ b/x0vncserver/Image.h
@@ -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;
diff --git a/x0vncserver/PollingManager.cxx b/x0vncserver/PollingManager.cxx
index 9491d766..00580e01 100644
--- a/x0vncserver/PollingManager.cxx
+++ b/x0vncserver/PollingManager.cxx
@@ -19,17 +19,30 @@
// 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;
}
//
@@ -101,6 +120,28 @@ void PollingManager::setVNCServer(VNCServer *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];
diff --git a/x0vncserver/PollingManager.h b/x0vncserver/PollingManager.h
index 8f7f820a..a35fafee 100644
--- a/x0vncserver/PollingManager.h
+++ b/x0vncserver/PollingManager.h
@@ -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;
diff --git a/x0vncserver/x0vncserver.cxx b/x0vncserver/x0vncserver.cxx
index f799de3a..f718164f 100644
--- a/x0vncserver/x0vncserver.cxx
+++ b/x0vncserver/x0vncserver.cxx
@@ -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);