summaryrefslogtreecommitdiffstats
path: root/x11vnc/x11vnc.c
diff options
context:
space:
mode:
authorrunge <runge>2005-01-24 03:52:47 +0000
committerrunge <runge>2005-01-24 03:52:47 +0000
commitd2a0e40e1b9bf6e76d230e96d1ccfe912998a720 (patch)
tree6e0e67eec738de58bf3d26e278c91c1b55c4f2ab /x11vnc/x11vnc.c
parent6fb3752bf23af0d2fc683986374e716a3eb88bb1 (diff)
downloadlibtdevnc-d2a0e40e1b9bf6e76d230e96d1ccfe912998a720.tar.gz
libtdevnc-d2a0e40e1b9bf6e76d230e96d1ccfe912998a720.zip
sync with new cursor mechanism, -timeout, -noalphablend, try :0 if no other info
Diffstat (limited to 'x11vnc/x11vnc.c')
-rw-r--r--x11vnc/x11vnc.c2141
1 files changed, 2066 insertions, 75 deletions
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c
index 8c26ee2..97a9ae2 100644
--- a/x11vnc/x11vnc.c
+++ b/x11vnc/x11vnc.c
@@ -161,11 +161,11 @@
#include <rfb/rfb.h>
#include <rfb/rfbregion.h>
+#if OLD_TREE
/*
* This is another transient for building in older libvncserver trees,
* due to the API change:
*/
-#if OLD_TREE
#define dontDisconnect rfbDontDisconnect
#define neverShared rfbNeverShared
#define alwaysShared rfbAlwaysShared
@@ -178,6 +178,10 @@
#define rfbEncryptAndStorePasswd vncEncryptAndStorePasswd
#define maxClientWait rfbMaxClientWait
#define rfbHttpInitSockets httpInitSockets
+
+#define RFBUNDRAWCURSOR(s) if (s) {rfbUndrawCursor(s);}
+#else
+#define RFBUNDRAWCURSOR(s)
#endif
#if LIBVNCSERVER_HAVE_XSHM
@@ -255,7 +259,7 @@ int got_xfixes_cursor_notify = 0;
int alpha_threshold = 240;
double alpha_frac = 0.33;
int alpha_remove = 0;
-int alpha_blend = 0;
+int alpha_blend = 1;
#if LIBVNCSERVER_HAVE_LIBXFIXES
#include <X11/extensions/Xfixes.h>
@@ -269,7 +273,7 @@ static int xdamage_base_event_type;
#endif
/* date +'lastmod: %Y-%m-%d' */
-char lastmod[] = "0.7.1pre lastmod: 2005-01-16";
+char lastmod[] = "0.7.1pre lastmod: 2005-01-23";
/* X display info */
@@ -545,6 +549,7 @@ int view_only = 0; /* clients can only watch. */
char *viewonly_passwd = NULL; /* view only passwd. */
int inetd = 0; /* spawned from inetd(1) */
int connect_once = 1; /* disconnect after first connection session. */
+int first_conn_timeout = 0; /* -timeout */
int flash_cmap = 0; /* follow installed colormaps */
int force_indexed_color = 0; /* whether to force indexed color for 8bpp */
int launch_gui = 0; /* -gui */
@@ -556,6 +561,7 @@ int nofb = 0; /* do not send any fb updates */
unsigned long subwin = 0x0; /* -id, -sid */
int subwin_wait_mapped = 0;
+int no_su = 0; /* -nosu */
int xinerama = 0; /* -xinerama */
int xrandr = 0; /* -xrandr */
@@ -680,6 +686,15 @@ int got_nevershared = 0;
/* -- util.h -- */
+// FYI: GB='garbage begin' GE='garbage end'. Lines ending in //G trimmed too.
+int debug = 0;
+int libvnc_count = 0;
+
+#if defined(__sun)
+long long libvnc_time;
+#else
+double libvnc_time;
+#endif
#define NONUL(x) ((x) ? (x) : "")
/* XXX usleep(3) is not thread safe on some older systems... */
@@ -808,6 +823,7 @@ int pick_windowid(unsigned long *num) {
if (fgets(line, 512, p) == NULL) {
break;
}
+if (0) fprintf(stderr, "line: %s\n", line);
q = strstr(line, " id: 0x");
if (q) {
q += 5;
@@ -1179,6 +1195,7 @@ void XTestFakeKeyEvent_wr(Display* dpy, KeyCode key, Bool down,
rfbLog("XTestFakeKeyEvent(dpy, keycode=0x%x \"%s\", %s)\n",
key, XKeysymToString(XKeycodeToKeysym(dpy, key, 0)),
down ? "down":"up");
+ fflush(stderr);
}
if (! xtest_present) {
return;
@@ -1265,6 +1282,82 @@ void XTestDiscard_wr(Display *dpy) {
}
+/* -- vcr.h -- */
+/*
+ * experiment to look for vertical copy rect changes
+ */
+
+void do_vcr(void);
+void initialize_vcr(void);
+
+#define VCR_HACK
+#ifdef VCR_HACK
+int vcopyrect = 0;
+
+/*
+ * vcr_map is a pattern of horizontal offsets for vertical scanlines
+ * within a column of changed tiles. 15 is in the middle of the tile,
+ * 0 the left edge, 31 the right edge, etc. It is kind of a recursive
+ * bisection of the tile.
+ */
+int vcr_map[] = {
+ 15, 0, 31, 7, 23, 3, 27, 11, 19,
+ 1, 5, 9, 13, 17, 21, 25, 29,
+ 2, 4, 6, 8, 10, 12, 14, 16,
+ 18, 20, 22, 24, 26, 28, 30
+};
+
+/*
+ * VCR_DEPTH says how far into the vcr_map[] pattern we consider
+ * e.g. 5 means we consider offsets: 15, 0, 31, 7, 23.
+ */
+#define VCR_DEPTH 32
+//int vcr_depth = VCR_DEPTH;
+int vcr_depth = 9;
+
+/*
+ * fbd_old and fbd_new are the vertical "scan lines" of fb data.
+ * The "40" is just an index into which column (x value) of tiles it
+ * corresponds to.
+ * The VCR_DEPTH is an index for which of the above vcr_map[] offsets.
+ * The 1024 is how tall the display can possibly be (i.e. 1280x1024)
+ *
+ * fdb_old contains framebuffer pixel data before the copy_tiles() update.
+ * fdb_new contains framebuffer pixel data after the copy_tiles() update.
+ *
+ * By comparing these vectors with one shifted by a vertical offset,
+ * we can look for the offset that gives a long run of perfect coincidence
+ * of the fb pixel data. If a coincidence found, then we have a verticle
+ * offset for a potential copyRegion transfer (if we find a number >
+ * 1 of adjacent scanlines with the same offset to form a rectangle).
+ *
+ */
+void ***fbd_old;
+void ***fbd_new;
+char ***fbd_old8;
+char ***fbd_new8;
+short ***fbd_old16;
+short ***fbd_new16;
+int ***fbd_old32;
+int ***fbd_new32;
+
+/* smaller temporary ones to improve horrendous I/O (i.e. fewer pages) */
+void **fbt_old;
+void **fbt_new;
+char **fbt_old8;
+char **fbt_new8;
+short **fbt_old16;
+short **fbt_new16;
+int **fbt_old32;
+int **fbt_new32;
+//int fbd_old[40][VCR_DEPTH][1024];
+//int fbd_new[40][VCR_DEPTH][1024];
+
+sraRegionPtr vcr_change_region = NULL;
+sraRegionPtr vcr_mod_region = NULL;
+
+#endif
+
/* -- cleanup.c -- */
/*
* Exiting and error handling routines
@@ -1350,6 +1443,7 @@ void clean_up_exit (int ret) {
static void interrupted (int sig) {
exit_sig = sig;
if (exit_flag) {
+ fprintf(stderr, "extra[%d] signal: %d\n", exit_flag, sig);
exit_flag++;
if (use_threads) {
usleep2(250 * 1000);
@@ -1366,6 +1460,7 @@ static void interrupted (int sig) {
}
if (sig == SIGINT) {
shut_down = 1;
+ fprintf(stderr, "interrupted: set shut_down flag for SIGINT\n");
return;
}
@@ -1386,6 +1481,10 @@ static void interrupted (int sig) {
autorepeat(1);
}
+if (getenv("GDB")) {
+ fprintf(stderr, "getc> ");
+ getc(stdin);
+}
if (sig) {
exit(2);
}
@@ -1515,6 +1614,31 @@ int get_window_size(Window win, int *x, int *y) {
}
}
+int bs_w = 0;
+void remove_backingstore_and_saveunders(Window win) {
+ int i, nchild;
+ Window root, parent;
+ Window *child_list;
+ XSetWindowAttributes sattr;
+ for (i=0; i< bs_w; i++) {
+ fprintf(stderr, " ");
+ }
+ bs_w += 2;
+ fprintf(stderr, "0x%lx\n", win);
+ sattr.save_under = False;
+ XChangeWindowAttributes(dpy, win, CWSaveUnder, &sattr);
+
+ if (XQueryTree(dpy, win, &root, &parent, &child_list, &nchild)) {
+ if (child_list && nchild) {
+ for (i=0; i<nchild; i++) {
+ Window twin = child_list[i];
+ remove_backingstore_and_saveunders(twin);
+ }
+ }
+ XFree(child_list);
+ }
+ bs_w -= 2;
+}
/* signal handlers */
void initialize_signals(void) {
signal(SIGHUP, interrupted);
@@ -1948,6 +2072,7 @@ static int check_access(char *addr) {
} else {
chk = p;
}
+if (0) fprintf(stderr, "chk: %s\n", chk);
q = strstr(addr, chk);
if (chk[strlen(chk)-1] != '.') {
@@ -2633,11 +2758,13 @@ static void reverse_connect(char *str) {
p = strtok(NULL, ", \t\r\n");
if (p) {
t = 0;
+ rfbLog("reverse_connect: start btw.\n");
while (t < sleep_between_host) {
usleep(dt * 1000);
rfbPE(screen, -1);
t += dt;
}
+ rfbLog("reverse_connect: end btw.\n");
}
}
free(tmp);
@@ -2659,12 +2786,14 @@ static void reverse_connect(char *str) {
t = sleep_max - sleep_min;
tot = sleep_min + ((n-1) * t) / (n_max-1);
+ rfbLog("reverse_connect: start sleeping.\n");
t = 0;
while (t < tot) {
rfbPE(screen, -1);
usleep(dt * 1000);
t += dt;
}
+ rfbLog("reverse_connect: end sleeping.\n");
}
/*
@@ -4104,6 +4233,50 @@ void initialize_modtweak(void) {
}
}
}
+if (0) {
+ if (debug_keyboard) {
+ int kc, g, l;
+ KeySym ks;
+ fprintf(stderr, "keycodes[] and modifiers[]:\n");
+ for (keysym = 0; keysym < 0x100; keysym++) {
+ char *str = XKeysymToString(keysym);
+ fprintf(stderr, "keysym 0x%02lx code=%03d/%03d index=%3d %s\n",
+ keysym, keycodes[keysym], XKeysymToKeycode(dpy, keysym),
+ (int) modifiers[keysym], str ? str : "null");
+ }
+ for (kc = 0; kc < 0x100; kc++) {
+ unsigned int state = 0;
+ int put = 0;
+ for (g = 1; g <= 4; g++) {
+ for (l = 1; l <= 4; l++) {
+ unsigned int ms;
+ ks = XkbKeycodeToKeysym(dpy, kc, g - 1, l - 1);
+ ms = XkbKeysymToModifiers(dpy, ks);
+ if (ks != NoSymbol) {
+ char *str = XKeysymToString(ks);
+ fprintf(stderr, "%03d G%d L%d mods=%3d 0x%04lx %s\n",
+ kc, g, l, (int) ms, ks, str ? str : "null");
+ put = 1;
+ }
+ }
+ }
+ fprintf(stderr, " %03d --\n", kc);
+ while (state < 256) {
+ unsigned int mods;
+ if (XkbLookupKeySym(dpy, kc, state, &mods, &ks)) {
+ char *str = XKeysymToString(ks);
+ fprintf(stderr, " %03d 0x%lx/%s", state,
+ ks, bitprint(state, 8));
+ fprintf(stderr, "/%s", bitprint(mods, 8));
+ fprintf(stderr, "/%s %s\n", bitprint(state & mods, 8),
+ str ? str : "null");
+ }
+ state++;
+ }
+ if (put) fprintf(stderr, "\n");
+ }
+ }
+}
left_shift_code = XKeysymToKeycode(dpy, XK_Shift_L);
right_shift_code = XKeysymToKeycode(dpy, XK_Shift_R);
@@ -5005,6 +5178,7 @@ int handle_subwin_resize(char *msg) {
int new_x, new_y;
int i, check = 10, ms = 250; /* 2.5 secs... */
+if (0) fprintf(stderr, "IN handle_subwin_resize('%s')\n", msg);
if (! subwin) {
return 0; /* hmmm... */
}
@@ -5042,6 +5216,7 @@ int handle_subwin_resize(char *msg) {
}
}
+if (0) fprintf(stderr, "IN handle_subwin_resize('%s')\n", msg);
rfbLog("subwin 0x%lx new size: x: %d -> %d, y: %d -> %d\n",
subwin, dpy_x, new_x, dpy_y, new_y);
rfbLog("calling handle_xrandr_change() for resizing\n");
@@ -5102,6 +5277,7 @@ int check_xrandr_event(char *msg) {
if (! xrandr || ! xrandr_present) {
return 0;
}
+if (0) fprintf(stderr, "IN check_xrandr_event('%s')\n", msg);
if (XCheckTypedEvent(dpy, xrandr_base_event_type +
RRScreenChangeNotify, &xev)) {
int do_change;
@@ -5148,9 +5324,11 @@ int check_xrandr_event(char *msg) {
XDisplayWidth(dpy, scr), XDisplayHeight(dpy, scr));
rfbLog("check_xrandr_event(): returning control to"
" caller...\n");
+if (0) fprintf(stderr, "OUT-%d check_xrandr_event('%s')\n", do_change, msg);
return do_change;
}
#endif
+if (0) fprintf(stderr, "OUT-0 check_xrandr_event('%s')\n", msg);
return 0;
}
@@ -5243,6 +5421,9 @@ static void selection_request(XEvent *ev) {
} else {
length = 0;
}
+rfbLog("selection_request: owner=0x%x requestor=0x%x sel=%d targ=%d prop=%d\n",
+ req_event->owner, req_event->requestor, req_event->selection,
+ req_event->target, req_event->property);
/* the window may have gone away, so trap errors */
trapped_xerror = 0;
@@ -6486,6 +6667,22 @@ char *process_remote_cmd(char *cmd, int stringonly) {
rfbLog("process_remote_cmd: disable -forever mode.\n");
connect_once = 1;
+ } else if (strstr(p, "timeout") == p) {
+ int to;
+ COLON_CHECK("timeout:")
+ if (query) {
+ snprintf(buf, bufn, "ans=%s%s%d", p, co,
+ first_conn_timeout);
+ goto qry;
+ }
+ p += strlen("timeout:");
+ to = atoi(p);
+ if (to > 0 ) {
+ to = -to;
+ }
+ first_conn_timeout = to;
+ rfbLog("process_remote_cmd: set -timeout to %d\n", -to);
+
} else if (!strcmp(p, "deny") || !strcmp(p, "lock")) {
if (query) {
snprintf(buf, bufn, "ans=%s:%d", p, deny_all);
@@ -7062,9 +7259,7 @@ char *process_remote_cmd(char *cmd, int stringonly) {
goto qry;
}
rfbLog("process_remote_cmd: enabling -repeat mode.\n");
- if (no_autorepeat) {
- autorepeat(1);
- }
+ autorepeat(1); /* restore initial setting */
no_autorepeat = 0;
} else if (!strcmp(p, "norepeat")) {
@@ -7073,11 +7268,10 @@ char *process_remote_cmd(char *cmd, int stringonly) {
goto qry;
}
rfbLog("process_remote_cmd: enabling -norepeat mode.\n");
- if (! no_autorepeat && client_count) {
- no_autorepeat = 1;
- autorepeat(0);
- }
no_autorepeat = 1;
+ if (client_count) {
+ autorepeat(0); /* disable if any clients */
+ }
} else if (!strcmp(p, "fb")) {
if (query) {
@@ -7887,6 +8081,14 @@ char *process_remote_cmd(char *cmd, int stringonly) {
} else if (!strcmp(p, "desktopname")) {
snprintf(buf, bufn, "aro=%s:%s", p,
NONUL(rfb_desktop_name));
+ } else if (!strcmp(p, "http_url")) {
+ if (screen->httpListenSock > -1) {
+ snprintf(buf, bufn, "aro=%s:http://%s:%d", p,
+ NONUL(screen->thisHost), screen->httpPort);
+ } else {
+ snprintf(buf, bufn, "aro=%s:%s", p,
+ "http_not_active");
+ }
} else if (!strcmp(p, "auth")) {
snprintf(buf, bufn, "aro=%s:%s", p, NONUL(auth_file));
} else if (!strcmp(p, "rootshift")) {
@@ -8317,6 +8519,7 @@ void setup_cursors(void) {
first = 0;
if (screen) {
+ RFBUNDRAWCURSOR(screen);
screen->cursor = NULL;
LOCK(screen->cursorMutex);
}
@@ -8683,6 +8886,8 @@ int get_xfixes_cursor(int init) {
}
}
+ RFBUNDRAWCURSOR(screen);
+
/* we need to create the cursor and overwrite oldest */
use = oldest;
if (cursors[use]->rfb) {
@@ -8762,7 +8967,9 @@ int get_xfixes_cursor(int init) {
}
if (n_opaque >= alpha_frac * n_alpha) {
thresh = alpha_threshold;
+fprintf(stderr, "OK thresh: %d/%d\n", n_opaque, n_alpha);
} else {
+ int o_opaque = n_opaque;
n_opaque = 0;
for (i=255; i>=0; i--) {
n_opaque += histo[i];
@@ -8771,6 +8978,8 @@ int get_xfixes_cursor(int init) {
break;
}
}
+fprintf(stderr, "changed thresh: %d -> %d [%d->%d]/%d\n",
+ alpha_threshold, thresh, o_opaque, n_opaque, n_alpha);
}
i = 0;
@@ -8977,7 +9186,7 @@ int get_which_cursor(void) {
XErrorHandler old_handler;
int mode = 0;
- if (drag_in_progress) {
+ if (drag_in_progress || button_mask) {
return -1;
}
@@ -9062,6 +9271,7 @@ int get_which_cursor(void) {
return which;
}
+#if OLD_TREE
/*
* Some utilities for marking the little cursor patch region as
* modified, etc.
@@ -9074,12 +9284,11 @@ void mark_cursor_patch_modified(rfbScreenInfoPtr s, int old) {
return;
}
- /* TODO Karl: is this needed any longer? */
- /* if (old) {
- /* use oldCursor pos *//*
+ if (old) {
+ /* use oldCursor pos */
curx = s->oldCursorX;
cury = s->oldCursorY;
- } else */ {
+ } else {
curx = s->cursorX;
cury = s->cursorY;
}
@@ -9101,6 +9310,7 @@ void mark_cursor_patch_modified(rfbScreenInfoPtr s, int old) {
rfbMarkRectAsModified(s, x1, y1, x1+x2, y1+y2);
}
+#endif
void set_cursor_was_changed(rfbScreenInfoPtr s) {
rfbClientIteratorPtr iter;
@@ -9235,7 +9445,10 @@ void cursor_position(int x, int y) {
rfbClientIteratorPtr iter;
rfbClientPtr cl;
int cnt = 0, nonCursorPosUpdates_clients = 0;
- int x_old, y_old, x_in = x, y_in = y;
+ int x_in = x, y_in = y;
+#if OLD_TREE
+ int x_old, y_old;
+#endif
/* x and y are current positions of X11 pointer on the X11 display */
if (!screen) {
@@ -9252,16 +9465,27 @@ void cursor_position(int x, int y) {
if (x == screen->cursorX && y == screen->cursorY) {
return;
}
- /* TODO Karl: do we really need x_old,y_old? */
- /*
+
+#if OLD_TREE
x_old = screen->oldCursorX;
y_old = screen->oldCursorY;
- */
+
+ if (screen->cursorIsDrawn) {
+ rfbUndrawCursor(screen);
+ }
LOCK(screen->cursorMutex);
+ if (! screen->cursorIsDrawn) {
+ screen->cursorX = x;
+ screen->cursorY = y;
+ }
+ UNLOCK(screen->cursorMutex);
+#else
+ LOCK(screen->cursorMutex);
screen->cursorX = x;
screen->cursorY = y;
UNLOCK(screen->cursorMutex);
+#endif
iter = rfbGetClientIterator(screen);
while( (cl = rfbClientIteratorNext(iter)) ) {
@@ -9296,13 +9520,13 @@ void cursor_position(int x, int y) {
}
rfbReleaseClientIterator(iter);
- /* TODO Karl: do we need x_old, y_old? */
- /*
+#if OLD_TREE
if (nonCursorPosUpdates_clients && show_cursor) {
if (x_old != x || y_old != y) {
mark_cursor_patch_modified(screen, 0);
}
- }*/
+ }
+#endif
if (debug_pointer && cnt) {
rfbLog("cursor_position: sent position x=%3d y=%3d to %d"
@@ -9310,12 +9534,27 @@ void cursor_position(int x, int y) {
}
}
+#if !OLD_TREE
void set_rfb_cursor(int which) {
- int workaround = 1; /* if rfbSetCursor does not mark modified */
-#if OLD_TREE
- workaround = 2;
-#endif
+ if (! show_cursor) {
+ return;
+ }
+ if (! screen) {
+ return;
+ }
+
+ if (!cursors[which] || !cursors[which]->rfb) {
+ rfbLog("non-existent cursor: which=%d\n", which);
+ return;
+ } else {
+ rfbSetCursor(screen, cursors[which]->rfb);
+ }
+}
+
+#else
+
+void set_rfb_cursor(int which) {
if (! show_cursor) {
return;
@@ -9324,7 +9563,7 @@ void set_rfb_cursor(int which) {
return;
}
- if (workaround && screen->cursor) {
+ if (screen->cursor) {
int all_are_cursor_pos = 1;
rfbClientIteratorPtr iter;
rfbClientPtr cl;
@@ -9349,27 +9588,21 @@ void set_rfb_cursor(int which) {
rfbLog("non-existent cursor: which=%d\n", which);
return;
} else {
- rfbSetCursor(screen, cursors[which]->rfb);
+ rfbSetCursor(screen, cursors[which]->rfb, FALSE);
}
- /* TODO Karl: is this still necessary? */
- /* this is a 2nd workaround for rfbSetCursor() */
- if (workaround > 1) {
- if (screen->underCursorBuffer == NULL &&
- screen->underCursorBufferLen != 0) {
- LOCK(screen->cursorMutex);
- screen->underCursorBufferLen = 0;
- UNLOCK(screen->cursorMutex);
- }
- }
-
- /* TODO Karl: is this still necessary? */
- if (workaround) {
- set_cursor_was_changed(screen);
+ if (screen->underCursorBuffer == NULL &&
+ screen->underCursorBufferLen != 0) {
+ LOCK(screen->cursorMutex);
+ screen->underCursorBufferLen = 0;
+ UNLOCK(screen->cursorMutex);
}
+ set_cursor_was_changed(screen);
}
+#endif
void set_no_cursor(void) {
+ RFBUNDRAWCURSOR(screen);
set_rfb_cursor(CURS_EMPTY);
}
@@ -9497,6 +9730,8 @@ void set_colormap(int reset) {
/* XXX XQueryTree somehow? */
XQueryPointer(dpy, c, &r, &c, &rx, &ry, &wx, &wy, &m);
if (c && XGetWindowAttributes(dpy, c, &attr)) {
+ if (debug) fprintf(stderr, "child: %d 0x%x cmap: 0x%x map_installed: %d\n",
+ tries, (int) c, (int) attr.colormap, attr.map_installed);
if (attr.colormap && attr.map_installed) {
cmap = attr.colormap;
vis = attr.visual;
@@ -9546,6 +9781,7 @@ void set_colormap(int reset) {
}
if (diffs && ! first) {
+ if (debug) fprintf(stderr, "set_colormap: %d changed colormap entries.\n", diffs);
if (! all_clients_initialized()) {
rfbLog("set_colormap: warning: sending cmap "
"with uninitialized clients.\n");
@@ -9999,6 +10235,9 @@ XImage *initialize_xdisplay_fb(void) {
usleep(250 * 1000);
goto again;
}
+ if (no_su) {
+ remove_backingstore_and_saveunders(window);
+ }
if (use_snapfb) {
initialize_snap_fb();
}
@@ -10644,6 +10883,14 @@ void blackout_tiles(void) {
* to simplify things drop down to single copy mode, no vcr, etc...
*/
single_copytile = 1;
+#ifdef VCR_HACK
+#if 0
+ if (vcopyrect) {
+ rfbLog("disabling vertical copyrect due to blackouts\n");
+ vcopyrect = 0;
+ }
+#endif
+#endif
/* loop over all tiles. */
for (ty=0; ty < ntiles_y; ty++) {
@@ -10825,6 +11072,7 @@ void initialize_xinerama (void) {
/* max len is 10000x10000+10000+10000 (23 chars) per geometry */
rcnt = (int) sraRgnCountRects(black_region);
+ fprintf(stderr, "xinerama: rcnt=%d\n", rcnt);
bstr = (char *) malloc(30 * (rcnt+1) * sizeof(char));
tstr = (char *) malloc(30 * sizeof(char));
bstr[0] = '\0';
@@ -10851,6 +11099,7 @@ void initialize_xinerama (void) {
sprintf(tstr, "%dx%d+%d+%d,", w, h, x, y);
strcat(bstr, tstr);
}
+ fprintf(stderr, "xinerama: bstr: %s\n", bstr);
initialize_blackouts(bstr);
free(bstr);
@@ -10963,6 +11212,47 @@ typedef struct tile_change_region {
/* array to hold the tiles region_t-s. */
static region_t *tile_region;
+/* for measurements: */
+static int gap_got, gap_tot, isl_got, isl_tot, noretry;
+static int hints_used, hint_cnt;
+static int wrote_copy_tile_header = 0;
+static int scan_cnt = 0, scan_cnt2 = 0;
+static double scan_ave = 0, scan_ave2 = 0;
+static int memcmp_scan = 0, memcmp_copy = 0, memcpy_copy = 0;
+static int xget_scan = 0, xget_copy = 0;
+static int scale_data = 0;
+
+#if defined(__sun)
+static long long memcpy_copy_time, memcmp_copy_time, memcmp_scan_time;
+static long long copy_tile_time, xshmget_scan_time, xshmget_copy_time;
+static long long scale_time;
+static hrtime_t beg, end;
+static hrtime_t beg2, end2;
+#define BEG_FAC 1000000000
+#define BEG if(debug) {beg = gethrtime();}
+#define BEG2 if(debug) {beg2 = gethrtime();}
+#define END(x) if(debug) {end = gethrtime(); x += (long long) (end - beg);}
+#define END2(x) if(debug) {end2 = gethrtime(); x += (long long) (end2 - beg2);}
+
+#else
+/* not very fast or accurate */
+static double memcpy_copy_time, memcmp_copy_time, memcmp_scan_time;
+static double copy_tile_time, xshmget_scan_time, xshmget_copy_time;
+static double scale_time;
+static double doub1 = 0.0, doub2 = 0.0;
+static double beg, end;
+static double beg2, end2;
+#define BEG_FAC 1
+#define BEG if(debug) {beg = dtime(&doub1);}
+#define BEG2 if(debug) {beg2 = dtime(&doub2);}
+#define END(x) if(debug) {end = dtime(&doub1); x += (end);}
+#define END2(x) if(debug) {end2 = dtime(&doub2); x += (end2);}
+#endif
+
+#ifdef VCR_HACK
+static int vcr_shift[VCR_DEPTH];/* vcr_map[]*pixelsize, use in copytile */
+static int vcr_cnt = 0; /* for statistics. */
+#endif
/*
* setup tile numbers and allocate the tile and hint arrays:
@@ -11245,6 +11535,11 @@ void initialize_polling_images(void) {
fs_frac = 1.1;
fs_factor = 0;
}
+ if (debug) {
+ int fs_tmp = fs_factor ? fs_factor : 1;
+ rfbLog("fs_factor: %d shm: %d\n", fs_factor,
+ (bpp/8) * dpy_x * (dpy_y/fs_tmp) );
+ }
if (! fs_factor) {
rfbLog("warning: fullscreen updates are disabled.\n");
} else {
@@ -11399,7 +11694,82 @@ static void hint_updates(void) {
in_run = 0;
}
}
+ hint_cnt = hint_count;
+
+#ifdef VCR_HACK
+ if (vcopyrect && vcr_change_region != NULL) {
+ static char **pic = NULL;
+ int tx2, ty2, x2, y2;
+ sraRegionPtr tmp_region;
+
+ if (pic == NULL) {
+ int n;
+ pic = (char **) malloc(ntiles_x * sizeof(char *));
+ for (n=0; n < ntiles_x; n++) {
+ pic[n] = (char *) malloc(ntiles_y * sizeof(char));
+ }
+ }
+ for (ty2=0; ty2 < ntiles_y; ty2++) {
+ for (tx2=0; tx2 < ntiles_x; tx2++) {
+ char c = ' ';
+ n = tx2 + ty2 * ntiles_x;
+
+ if (tile_has_diff[n]) {
+ c = 'X';
+ } else if (tile_tried[n]) {
+ c = 't';
+ }
+ x2 = tx2 * tile_x;
+ y2 = ty2 * tile_y;
+
+ tmp_region = (sraRegionPtr)
+ sraRgnCreateRect(x2, y2, x2 + tile_x, y2 + tile_y);
+ if (sraRgnAnd(tmp_region, vcr_change_region)) {
+ if (c == 'X') {
+ c = '-';
+ } else if (c == 't') {
+ c = '_';
+ } else {
+ c = '.';
+ }
+ }
+ pic[tx2][ty2] = c;
+ sraRgnDestroy(tmp_region);
+ }
+ }
+ fprintf(stderr, "\n");
+ for (ty2=0; ty2 < ntiles_y; ty2++) {
+ for (tx2=0; tx2 < ntiles_x; tx2++) {
+ fprintf(stderr, "%c", pic[tx2][ty2]);
+ }
+ fprintf(stderr, "\n");
+ }
+ fprintf(stderr, "\n");
+ fprintf(stderr, "vcr_change_region: 0x%x Rects: %d ", (int) vcr_change_region, (int) sraRgnCountRects(vcr_change_region));
+ fprintf(stderr, "vcr_mod_region: 0x%x Rects: %d ", (int) vcr_mod_region, (int) sraRgnCountRects(vcr_mod_region));
+ for (i=0; i < hint_count; i++) {
+ int x = hint_list[i].x;
+ int y = hint_list[i].y;
+ int w = hint_list[i].w;
+ int h = hint_list[i].h;
+ tmp_region = (sraRegionPtr)
+ sraRgnCreateRect(x, y, x + w, y + h);
+ sraRgnSubtract(tmp_region, vcr_change_region);
+ if (!sraRgnEmpty(tmp_region)) {
+ fprintf(stderr, "M");
+ rfbMarkRegionAsModified(screen, tmp_region);
+ } else {
+ fprintf(stderr, "_");
+ }
+ sraRgnDestroy(tmp_region);
+ }
+ fprintf(stderr, "\n");
+ sraRgnDestroy(vcr_change_region);
+ vcr_change_region = NULL;
+ return;
+ }
+#endif /* VCR_HACK */
for (i=0; i < hint_count; i++) {
/* pass update info to vnc: */
@@ -11581,6 +11951,7 @@ static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) {
int shrink; /* whether shrinking or expanding */
static int constant_weights = -1, cnt = 0;
+BEG
if (scale_fac <= 1.0) {
shrink = 1;
} else {
@@ -11688,6 +12059,8 @@ static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) {
constant_weights = 1;
}
}
+fprintf(stderr, " scale dx: %.15f\n", dx);
+fprintf(stderr, " scale dy: %.15f\n", dy);
}
/* set these all to 1.0 to begin with */
wx = 1.0;
@@ -11741,6 +12114,7 @@ static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) {
I2 = I1 + 1; /* simple interpolation */
ddx = x1 - I1;
}
+//if (first) fprintf(stderr, " I1=%d I2=%d J1=%d J2=%d\n", I1, I2, J1, J2);
/* Zero out accumulators for next pixel average: */
for (b=0; b<4; b++) {
@@ -11851,6 +12225,12 @@ static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) {
w = wx * wy;
wtot += w;
+#if 0
+if (cnt % 37 == 0)
+ fprintf(stderr, " w=%15.12f wx=%15.12f wy=%15.12f wtot=%8.3f "
+ "i=%3d j=%3d idx=%8.3f jdy=%8.3f I=%3d J=%3d\n",
+ w, wx, wy, wtot, i, j, i * dx, j * dy, I, J);
+#endif
/*
* We average the unsigned char value
@@ -11876,6 +12256,7 @@ static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) {
pixave[2] += w*(us & main_blue_mask);
}
src += Bpp;
+scale_data += Bpp;
}
}
@@ -11902,6 +12283,7 @@ static void scale_and_mark_rect(int X1, int Y1, int X2, int Y2) {
dest += Bpp;
}
}
+END(scale_time)
mark_rect_as_modified(i1, j1, i2, j2, 1);
}
@@ -11966,6 +12348,7 @@ static int copy_tiles(int tx, int ty, int nt) {
char *src, *dst, *s_src, *s_dst, *m_src, *m_dst;
char *h_src, *h_dst;
+BEG2
if (! first_line) {
/* allocate arrays first time in. */
int n = ntiles_x + 1;
@@ -12009,11 +12392,14 @@ static int copy_tiles(int tx, int ty, int nt) {
}
X_LOCK;
+BEG
XRANDR_SET_TRAP_RET(-1, "copy_tile-set");
/* read in the whole tile run at once: */
copy_image(tile_row[nt], x, y, size_x, size_y);
XRANDR_CHK_TRAP_RET(-1, "copy_tile-chk");
+xget_copy += size_x * size_y * pixelsize;
+END(xshmget_copy_time)
X_UNLOCK;
if (blackouts && tile_blackout[n].cover == 1) {
@@ -12036,6 +12422,7 @@ static int copy_tiles(int tx, int ty, int nt) {
w = (x2 - x1) * pixelsize;
s = x1 * pixelsize;
+//fprintf(stderr, "rbo: %d w=%d s=%d x=%d-%d y=%d-%d b=%d\n", n, w, s, x1, x2, y1, y2, b);
for (line = 0; line < size_y; line++) {
if (y1 <= line && line < y2) {
memset(b_dst + s, fill, (size_t) w);
@@ -12054,6 +12441,63 @@ static int copy_tiles(int tx, int ty, int nt) {
for (t=1; t <= nt; t++) {
first_line[t] = -1;
}
+BEG
+#ifdef VCR_HACK
+/*
+ * This is the great copyrect hunt macro. See the comments in copytile()
+ * for the general description. The only difference here in copy_tiles()
+ * is we have more than one horizontal tile index, tx+(t-1), to deal
+ * with.
+ */
+ {int k;
+ for (k=0; k < vcr_depth; k++) {
+ vcr_shift[k] = vcr_map[k]*pixelsize;
+ }
+ }
+#define VCR_FB0(DST,SRC) \
+ if (vcopyrect) { \
+ int k, yl = y + line; \
+ if (bpp == 32) { \
+ for (k=0; k < vcr_depth; k++) { \
+ memcpy(fbd_old32[tx+(t-1)][k]+yl, \
+ ((DST)+vcr_shift[k]), 4); \
+ memcpy(fbd_new32[tx+(t-1)][k]+yl, \
+ ((SRC)+vcr_shift[k]), 4); \
+ } \
+ } else if (bpp == 16) { /* XXX */ \
+ for (k=0; k < vcr_depth; k++) { \
+ memcpy(fbd_old16[tx+(t-1)][k]+yl, \
+ ((DST)+vcr_shift[k]), 2); \
+ memcpy(fbd_new16[tx+(t-1)][k]+yl, \
+ ((SRC)+vcr_shift[k]), 2); \
+ } \
+ } else if (bpp == 8) { /* XXX */ \
+ for (k=0; k < vcr_depth; k++) { \
+ memcpy(fbd_old8[tx+(t-1)][k]+yl, \
+ ((DST)+vcr_shift[k]), 1); \
+ memcpy(fbd_new8[tx+(t-1)][k]+yl, \
+ ((SRC)+vcr_shift[k]), 1); \
+ } \
+ } \
+ vcr_cnt++; \
+ }
+
+#define VCR_FB(DST,SRC) \
+ if (vcopyrect) { \
+ int k, yl = y + line; \
+ if (bpp == 32) { \
+ for (k=0; k < vcr_depth; k++) { \
+ memcpy(fbt_old32[(t-1)*tile_x + k]+(yl % tile_y), \
+ ((DST)+vcr_shift[k]), 4); \
+ memcpy(fbt_new32[(t-1)*tile_x + k]+(yl % tile_y), \
+ ((SRC)+vcr_shift[k]), 4); \
+ } \
+ } \
+ vcr_cnt++; \
+ }
+#else
+#define VCR_FB(DST,SRC)
+#endif /* VCR_HACK */
/* find the first line with difference: */
w1 = width1 * pixelsize;
@@ -12077,10 +12521,13 @@ static int copy_tiles(int tx, int ty, int nt) {
if (memcmp(s_dst + off, s_src + off, len)) {
first_line[t] = line;
}
+ else { VCR_FB(s_dst + off, s_src + off); }
+ memcmp_copy += len;
}
s_src += tile_row[nt]->bytes_per_line;
s_dst += main_bytes_per_line;
}
+END(memcmp_copy_time)
/* see if there were any differences for any tile: */
first_min = -1;
@@ -12097,6 +12544,7 @@ static int copy_tiles(int tx, int ty, int nt) {
for (t=1; t <= nt; t++) {
tile_has_diff[n+(t-1)] = 0;
}
+END2(copy_tile_time)
return(0);
} else {
/*
@@ -12113,6 +12561,7 @@ static int copy_tiles(int tx, int ty, int nt) {
}
}
+BEG
m_src = src + (tile_row[nt]->bytes_per_line * size_y);
m_dst = dst + (main_bytes_per_line * size_y);
@@ -12144,9 +12593,11 @@ static int copy_tiles(int tx, int ty, int nt) {
} else {
len = w1;
}
+ memcmp_copy += len;
if (memcmp(m_dst + off, m_src + off, len)) {
last_line[t] = line;
}
+ else {VCR_FB(m_dst + off, m_src + off); }
}
}
@@ -12199,6 +12650,7 @@ static int copy_tiles(int tx, int ty, int nt) {
dx = dx1;
}
+ memcmp_copy += (2 - left_diff[t] - right_diff[t]) * dw;
if (! left_diff[t] && memcmp(h_dst + off,
h_src + off, dw)) {
left_diff[t] = 1;
@@ -12211,17 +12663,50 @@ static int copy_tiles(int tx, int ty, int nt) {
h_src += tile_row[nt]->bytes_per_line;
h_dst += main_bytes_per_line;
}
+END(memcmp_copy_time)
/* now finally copy the difference to the rfb framebuffer: */
+BEG
s_src = src + tile_row[nt]->bytes_per_line * first_min;
s_dst = dst + main_bytes_per_line * first_min;
+#ifdef VCR_HACK
+ if (! vcopyrect) {
+#endif
for (line = first_min; line <= last_max; line++) {
/* for I/O speed we do not do this tile by tile */
memcpy(s_dst, s_src, size_x * pixelsize);
+ memcpy_copy += size_x * pixelsize;
s_src += tile_row[nt]->bytes_per_line;
s_dst += main_bytes_per_line;
}
+#ifdef VCR_HACK
+ } else {
+ w1 = width1 * pixelsize;
+ w2 = width2 * pixelsize;
+
+ for (line = first_min; line <= last_max; line++) {
+ for (t=1; t <= nt; t++) {
+ if (first_line[t] == -1) {
+ continue;
+ }
+ off = (t-1) * w1;
+ if (t == nt) {
+ len = w2; /* possible short tile */
+ } else {
+ len = w1;
+ }
+/* here VCR_FB must be done before the memcpy otherwise there'd be no diffs */
+VCR_FB(s_dst + off, s_src + off);
+ memcpy(s_dst + off, s_src + off, len);
+ memcpy_copy += len;
+ }
+ s_src += tile_row[nt]->bytes_per_line;
+ s_dst += main_bytes_per_line;
+ }
+ }
+#endif /* VCR_HACK */
+END(memcpy_copy_time)
/* record all the info in the region array for this tile: */
for (t=1; t <= nt; t++) {
@@ -12248,7 +12733,23 @@ static int copy_tiles(int tx, int ty, int nt) {
tile_copied[n+s] = 1;
}
+#ifdef VCR_HACK
+ if (vcopyrect) {
+ int k, ps = pixelsize;
+ if (bpp == 32) {
+ for (t=1; t <= nt; t++) {
+ for (k=0; k < vcr_depth; k++) {
+ memcpy(fbd_old32[tx+(t-1)][k] + y,
+ fbt_old32[(t-1)*tile_x + k], tile_y * ps);
+ memcpy(fbd_new32[tx+(t-1)][k] + y,
+ fbt_new32[(t-1)*tile_x + k], tile_y * ps);
+ }
+ }
+ } /* XXX */
+ }
+#endif
+END2(copy_tile_time)
return(1);
}
@@ -12364,6 +12865,9 @@ static int copy_all_tile_runs(void) {
}
}
}
+ if (ntcnt) {
+// fprintf(stderr, " ntave: %.1f\n", ((double) ntave)/ntcnt);
+ }
return diffs;
}
@@ -12396,6 +12900,8 @@ static int copy_tiles_backward_pass(void) {
tile_has_diff[m] = 2;
ct = copy_tiles(x, y-1, 1);
if (ct < 0) return ct; /* fatal */
+ } else {
+ noretry++; /* only for statistics */
}
}
@@ -12406,6 +12912,8 @@ static int copy_tiles_backward_pass(void) {
tile_has_diff[m] = 2;
ct = copy_tiles(x-1, y, 1);
if (ct < 0) return ct; /* fatal */
+ } else {
+ noretry++;
}
}
}
@@ -12461,6 +12969,7 @@ static int gap_try(int x, int y, int *run, int *saw, int along_x) {
*saw = 1;
return 0;
}
+ gap_tot += *run;
for (i=1; i <= *run; i++) { /* iterate thru the run. */
if (along_x) {
@@ -12473,11 +12982,16 @@ static int gap_try(int x, int y, int *run, int *saw, int along_x) {
m = xt + yt * ntiles_x;
if (tile_tried[m]) { /* do not repeat tiles */
+ gap_tot--;
+ noretry++;
continue;
}
ct = copy_tiles(xt, yt, 1);
if (ct < 0) return ct; /* fatal */
+ if (tile_has_diff[m]) {
+ gap_got++;
+ }
}
*run = 0;
*saw = 1;
@@ -12540,6 +13054,7 @@ static int island_try(int x, int y, int u, int v, int *run) {
/* found a discontinuity */
if (tile_tried[m]) {
+ noretry++;
return 0;
} else if (*run < grow_fill) {
return 0;
@@ -12547,6 +13062,10 @@ static int island_try(int x, int y, int u, int v, int *run) {
ct = copy_tiles(u, v, 1);
if (ct < 0) return ct; /* fatal */
+ isl_tot++;
+ if (tile_has_diff[m]) {
+ isl_got++;
+ }
}
return 1;
}
@@ -12686,10 +13205,84 @@ int copy_snap(void) {
rfbLog("copy_snap: time for -snapfb snapshot: %.3f sec\n", dt);
first = 0;
}
+ fprintf(stderr, "copy_snap: %.3f sec\n", dt);
return 0;
}
+/* profiling routines */
+static void do_stats(void) {
+ static double t = 0;
+ if (t == 0) {
+ dtime(&t);
+ }
+#ifdef VCR_HACK
+ if (vcr_cnt && scan_count == NSCAN - 1) {
+ // fprintf(stderr, "vcr_cnt: %d\n", vcr_cnt);
+ vcr_cnt = 0;
+ }
+#endif
+ if ( scan_count == 0 ) {
+ hints_used = 0;
+ gap_got = 0; gap_tot = 0;
+ isl_got = 0; isl_tot = 0;
+ noretry = 0;
+ } else if ( debug && scan_count == NSCAN - 1 ) {
+ int ave = (int) (1000 * (scan_ave/scan_cnt));
+ int ave2 = (int) (1000 * (scan_ave2/scan_cnt2));
+ scan_ave = 0; scan_cnt = 0;
+ scan_ave2 = 0; scan_cnt2 = 0;
+ fprintf(stderr, "All pix %.2fs (s4u aves: all: %dms scan: "
+ "%dms). tiles: %4d hints:%3d retry:%3d gaps:%3d/%-3d "
+ "isl:%3d/%-3d nap_ok=%d\n",
+ dtime(&t), ave, ave2, nap_diff_count, hints_used, noretry,
+ gap_got, gap_tot - gap_got, isl_got, isl_tot - isl_got,
+ nap_ok);
+ wrote_copy_tile_header = 0;
+ }
+}
+
+/*
+ * debugging: print out a picture of the tiles.
+ */
+static void print_tiles(void) {
+ /* hack for viewing tile diffs on the screen. */
+ static char *prev = NULL;
+ int n, x, y, ms = 1500;
+
+ ms = 1;
+
+ if (! prev) {
+ prev = (char *) malloc((size_t) (ntiles * sizeof(char)));
+ for (n=0; n < ntiles; n++) {
+ prev[n] = 0;
+ }
+ }
+ fprintf(stderr, " ");
+ for (x=0; x < ntiles_x; x++) {
+ fprintf(stderr, "%1d", x % 10);
+ }
+ fprintf(stderr, "\n");
+ n = 0;
+ for (y=0; y < ntiles_y; y++) {
+ fprintf(stderr, "%2d ", y);
+ for (x=0; x < ntiles_x; x++) {
+ if (tile_has_diff[n]) {
+ fprintf(stderr, "X");
+ } else if (prev[n]) {
+ fprintf(stderr, "o");
+ } else {
+ fprintf(stderr, ".");
+ }
+ n++;
+ }
+ fprintf(stderr, "\n");
+ }
+ for (n=0; n < ntiles; n++) {
+ prev[n] = tile_has_diff[n];
+ }
+ usleep(ms * 1000);
+}
/*
* Utilities for managing the "naps" to cut down on amount of polling.
@@ -12880,6 +13473,9 @@ static int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src,
x1 = tile_blackout[n].bo[b].x1 - x;
x2 = tile_blackout[n].bo[b].x2 - x;
+//fprintf(stderr, "cmpskip[%d]: n=%3d X=%3d Y=%3d y=%d-%d w=%2d ps=%2d "
+// "beg=%2d end=%2d x=%d-%d\n", b, n, x, y, y1, y2, w, pixelsize,
+// beg, end, x1, x2);
if (y1 > y || y >= y2) {
continue;
}
@@ -12932,25 +13528,33 @@ static int scan_display(int ystart, int rescan) {
/* grab the horizontal scanline from the display: */
X_LOCK;
+BEG
XRANDR_SET_TRAP_RET(-1, "scan_display-set");
copy_image(scanline, 0, y, 0, 0);
XRANDR_CHK_TRAP_RET(-1, "scan_display-chk");
+xget_scan += main_bytes_per_line;
+END(xshmget_scan_time)
X_UNLOCK;
/* for better memory i/o try the whole line at once */
src = scanline->data;
dst = main_fb + y * main_bytes_per_line;
+BEG
if (whole_line && ! memcmp(dst, src, main_bytes_per_line)) {
/* no changes anywhere in scan line */
+ memcmp_scan += main_bytes_per_line;
nodiffs = 1;
if (! rescan) {
+END(memcmp_scan_time)
y += NSCAN;
continue;
}
}
+END(memcmp_scan_time)
x = 0;
+BEG
while (x < dpy_x) {
n = (x/tile_x) + (y/tile_y) * ntiles_x;
@@ -12995,14 +13599,34 @@ static int scan_display(int ystart, int rescan) {
tile_count++;
}
}
+ } else {
+ memcmp_scan += w * pixelsize;
}
x += NSCAN;
}
y += NSCAN;
+END(memcmp_scan_time)
}
return tile_count;
}
+#if 0
+void check_key_down(void) {
+ double t = 0.0;
+ if (last_keyboard_input < 0) {
+ rfbCFD(screen, 1000);
+ if (last_keyboard_input) {
+ fprintf(stderr, "key *SWITCH*\n");
+ }
+ }
+ dtime(&t);
+ if (last_keyboard_input < 0) {
+ fprintf(stderr, "key DOWN: %3d %12.6f\n", -last_keyboard_input, t - 1089481179.0);
+ } else {
+ fprintf(stderr, "key up: %3d %12.6f\n", +last_keyboard_input, t - 1089481179.0);
+ }
+}
+#endif
/*
* toplevel for the scanning, rescanning, and applying the heuristics.
@@ -13014,6 +13638,32 @@ int scan_for_updates(int count_only) {
double frac1 = 0.1; /* tweak parameter to try a 2nd scan_display() */
double frac2 = 0.35; /* or 3rd */
double frac3 = 0.02; /* do scan_display() again after copy_tiles() */
+ double t = 0, t2 = 0, dt2;
+ double d1, d2, d3, d4, d = 0;
+ int full = 0;
+ int gap_g, gap_t, isl_g, isl_t, gap_n, isl_n, tdiff;
+
+ memcmp_scan = 0; memcmp_copy = 0; memcpy_copy = 0;
+ xget_scan = 0; xget_copy = 0;
+ memcpy_copy_time = 0;
+ memcmp_copy_time = 0;
+ memcmp_scan_time = 0;
+ xshmget_copy_time = 0;
+ xshmget_scan_time = 0;
+ copy_tile_time = 0;
+ scale_time = 0;
+ scale_data = 0;
+ dtime(&t2);
+ dtime(&d);
+
+ do_stats();
+ if (debug) {
+ dtime(&t);
+ }
+ if (debug && scan_count == 0) {
+ fflush(stderr);
+ fflush(stdout);
+ }
for (i=0; i < ntiles; i++) {
tile_has_diff[i] = 0;
tile_tried[i] = 0;
@@ -13061,6 +13711,7 @@ int scan_for_updates(int count_only) {
nap_set(tile_count);
+ dt2 = dtime(&t2);
if (fs_factor && frac1 >= fs_frac) {
/* make frac1 < fs_frac if fullscreen updates are enabled */
frac1 = fs_frac/2.0;
@@ -13082,11 +13733,13 @@ int scan_for_updates(int count_only) {
tile_count = scan_display(scanlines[cp], 1);
SCAN_FATAL(tile_count);
+ dt2 += dtime(&t2);
if (tile_count >= (1 + frac2) * tile_count_old) {
/* on a roll... do a 3rd scan */
cp = (NSCAN - scan_count + 7) % NSCAN;
tile_count = scan_display(scanlines[cp], 1);
SCAN_FATAL(tile_count);
+ dt2 += dtime(&t2);
}
}
scan_in_progress = 0;
@@ -13114,11 +13767,16 @@ int scan_for_updates(int count_only) {
if (use_threads && pointer_mode != 1) {
pointer(-1, 0, 0, NULL);
}
+ /* go finish the stats collecting, etc */
+ full = 1;
+ tile_diffs = tile_count;
+ goto finish;
nap_check(tile_count);
return tile_count;
}
}
scan_in_progress = 0;
+ dtime(&d);
/* copy all tiles with differences from display to rfb framebuffer: */
fb_copy_in_progress = 1;
@@ -13141,6 +13799,7 @@ int scan_for_updates(int count_only) {
} else {
tile_diffs = copy_all_tile_runs();
}
+ d1 = dtime(&d);
SCAN_FATAL(tile_diffs);
/*
@@ -13165,18 +13824,43 @@ int scan_for_updates(int count_only) {
tile_diffs = copy_tiles_additional_pass();
SCAN_FATAL(tile_diffs);
}
+ d2 = dtime(&d);
+ isl_n = noretry;
+ isl_g = isl_got;
+ isl_t = isl_tot;
/* Given enough tile diffs, try the islands: */
if (grow_fill && tile_diffs > 4) {
tile_diffs = grow_islands();
}
SCAN_FATAL(tile_diffs);
+ d3 = dtime(&d);
+
+ isl_n = noretry - isl_n;
+ isl_g = isl_got - isl_g;
+ isl_t = isl_tot - isl_t;
+
+ gap_n = noretry;
+ gap_g = gap_got;
+ gap_t = gap_tot;
/* Given enough tile diffs, try the gaps: */
if (gaps_fill && tile_diffs > 4) {
tile_diffs = fill_tile_gaps();
}
SCAN_FATAL(tile_diffs);
+ d4 = dtime(&d);
+
+ gap_n = noretry - gap_n;
+ gap_g = gap_got - gap_g;
+ gap_t = gap_tot - gap_t;
+
+ if (0) print_tiles();
+#ifdef VCR_HACK
+ if (vcopyrect) {
+ do_vcr();
+ }
+#endif
fb_copy_in_progress = 0;
if (use_threads && pointer_mode != 1) {
@@ -13207,6 +13891,138 @@ int scan_for_updates(int count_only) {
ping_clients(tile_diffs);
}
+finish:
+
+ tdiff = 0;
+ for (i=0; i < ntiles; i++) {
+ if (tile_has_diff[i]) {
+ tdiff++;
+ }
+ }
+ if (debug) {
+ double dt = dtime(&t);
+
+ hints_used += hint_cnt;
+ scan_ave += dt;
+ scan_cnt++;
+ scan_ave2 += dt2;
+ scan_cnt2++;
+
+ if (tdiff >= 4) {
+ double rat = dt / (tdiff ? tdiff : 1);
+ double libvnc = (double) libvnc_time / BEG_FAC;
+
+ if (full) {
+ double rat2 = dt / ntiles;
+ double rat3 = dpy_x * dpy_y * (bpp/8) / (dt - dt2);
+
+
+ rat3 /= 1000000;
+ rat3 *= 2; /* both XShmGetImage and memcpy to fb */
+ fprintf(stderr, "fullscreen: %6.3f %4d %4d %4.1f ms "
+ "-- (%.3f) T/ntiles %.2f ms rate: %5.1f MB/s "
+ "vnc: %.3f/%d\n",
+ dt, tile_count, tdiff, 1000*rat, dt2, 1000*rat2,
+ rat3, libvnc, libvnc_count);
+ } else {
+ /*
+ * dt = full time
+ * dt2 = scan_display (sum for both if applicable)
+ * d1 = copy_all_tiles
+ * d2 = copy_tiles_backward_pass
+ * d3 = grow_islands
+ * d4 = fill_tile_gaps
+ * memcmp_scan number of bytes; memcmp_scan_time ns
+ * memcpy_copy number of bytes; memcpy_copy_time ns
+ * memcmp_copy number of bytes; memcmp_copy_time ns
+ */
+ double mrat1 = (memcmp_scan) / (dt2);
+ double mrat2 = (memcpy_copy) / (d1 + d2 + d3 + d4);
+ double mrat3 = (memcmp_copy) / (d1 + d2 + d3 + d4);
+ double mrat4, mrat5, mrat6, mrat7;
+ double time4, time5, time6, time7;
+ double xrat1, xrat2;
+ double xshm_scan, xshm_copy;
+ double scale_tm, scale_amt;
+ double ct_time;
+
+ /* convert to (overall func. call) MB/sec */
+ mrat1 = mrat1 / 1000000; /* scanline memcmp */
+ mrat2 = mrat2 / 1000000; /* copytile memcpy */
+ mrat3 = mrat3 / 1000000; /* copytile memcmp */
+
+ /* now work out more accurate rates MB/sec */
+ time4 = (double) memcpy_copy_time / BEG_FAC;
+ mrat4 = memcpy_copy / time4;
+ mrat4 = mrat4 / 1000000; /* copytile memcpy */
+
+ time5 = (double) memcmp_copy_time / BEG_FAC;
+ mrat5 = memcmp_copy / time5;
+ mrat5 = mrat5 / 1000000; /* copytile memcmp */
+
+ time6 = (double) memcmp_scan_time / BEG_FAC;
+ mrat6 = memcmp_scan / time6;
+ mrat6 = mrat6 / 1000000; /* scanline memcmp */
+
+ /* total time in copytile() */
+ ct_time = (double) copy_tile_time / BEG_FAC;
+ /* total xshmgetimage copytile */
+ xshm_copy = (double) xshmget_copy_time / BEG_FAC;
+ /* total xshmgetimage scanline */
+ xshm_scan = (double) xshmget_scan_time / BEG_FAC;
+
+ /* total scale_and_mark time */
+ scale_tm = (double) scale_time / BEG_FAC;
+ scale_amt = (double) scale_data / 1000000;
+ time7 = (double) scale_time / BEG_FAC;
+ if (time7 == 0.0) time7 = 1.0;
+ mrat7 = scale_data / time7;
+ mrat7 = mrat7 / 1000000; /* scale_and_mark rate */
+
+
+ xrat1 = xget_scan / (1000000 * xshm_scan);
+ xrat2 = xget_copy / (1000000 * xshm_copy);
+
+ if (! wrote_copy_tile_header) {
+ fprintf(stderr, "---------- Time tlcnt tldif "
+ " T/tld -- (Tscan) - Tcopy Tisl Tgap R "
+ "Tcp2/cp1 Tisl/cp Tgap/cp Y/N-retry "
+ "Y/N-retry\n");
+ wrote_copy_tile_header = 1;
+ }
+ fprintf(stderr, "copy_tile: %6.3f %4d %4d %4.1f ms --"
+ " (%.3f) - %.3f %.3f %.3f R (%.3f) %.3f %.3f"
+ " isl=%d/%d-%d\tgap=%d/%d-%d\n "
+ "# scanline: cmp=%7d rate=%5.1f MB/s mcmp=%.4f"
+ " | xshm=%.4f st=%.4f xt/st=%.2f xrate_s=%5.1f "
+ "MB/s\n "
+ "# copytile: cmp=%7d rate=%5.1f MB/s mcmp=%.4f"
+ " | vnc: %.4f/%03d scale: %.4f %5.2f MB %5.1f MB/s\n "
+ " cpy=%7d rate=%5.1f MB/s mcpy=%.4f"
+ " | xshm=%.4f ct=%.4f xt/ct=%.2f xrate_c=%5.1f "
+ "MB/s\n",
+ dt, tile_count, tdiff, 1000*rat, dt2,
+ d1 + d2, d3, d4,
+ d2/d1, d3/(d1+d2), d4/(d1+d2),
+ isl_g, isl_t - isl_g, isl_n,
+ gap_g, gap_t - gap_g, gap_n,
+ memcmp_scan, mrat6, time6,
+ xshm_scan, dt2, xshm_scan/dt2, xrat1,
+ memcmp_copy, mrat5, time5,
+ libvnc, libvnc_count,
+ scale_tm, scale_amt, mrat7,
+ memcpy_copy, mrat4, time4,
+ xshm_copy, ct_time, xshm_copy/ct_time, xrat2
+ );
+ if (0 && isl_g < 5 && isl_t - isl_g > 30 ) {
+ print_tiles();
+ }
+ }
+ libvnc_time = 0;
+ libvnc_count = 0;
+ }
+ }
+ /* end of profile timing junk */
nap_check(tile_diffs);
return tile_diffs;
@@ -13244,9 +14060,13 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, pid_t parent) {
rfbLogEnable(0);
if (! client_connect_file) {
dpy = XOpenDisplay(x11vnc_xdisplay);
+ if (! dpy && ! x11vnc_xdisplay) {
+ x11vnc_xdisplay = strdup(":0");
+ dpy = XOpenDisplay(x11vnc_xdisplay);
+ }
if (! dpy) {
- fprintf(stderr, "gui: could not open display: %s\n",
- x11vnc_xdisplay);
+ fprintf(stderr, "gui: could not open "
+ "display: %s\n", NONUL(x11vnc_xdisplay));
exit(1);
}
scr = DefaultScreen(dpy);
@@ -13254,6 +14074,7 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, pid_t parent) {
initialize_vnc_connect_prop();
}
usleep(1000*1000);
+ fprintf(stderr, "\n");
for (i=0; i<try_max; i++) {
usleep(sleep*1000);
fprintf(stderr, "gui: pinging %s try=%d ...\n",
@@ -13293,11 +14114,11 @@ void run_gui(char *gui_xdisplay, int connect_to_x11vnc, pid_t parent) {
while (p) {
char *try;
struct stat sbuf;
- char *wishes[] = {"wish", "wish8.3", "wish8.4"};
+ char *wishes[] = {"wish", "wish8.3", "wish8.4", "wish8.5",
+ "wish8.0"};
int nwishes = 3, i;
- /* strlen("wish8.4") is 7 */
- try = (char *)malloc(strlen(p) + 1 + 7 + 1);
+ try = (char *)malloc(strlen(p) + 1 + strlen("wish8.4") + 1);
for (i=0; i<nwishes; i++) {
sprintf(try, "%s/%s", p, wishes[i]);
if (stat(try, &sbuf) == 0) {
@@ -13490,7 +14311,9 @@ static void check_user_input2(double dt) {
double quick_spin_fac = 0.40;
double grind_spin_time = 0.175;
+ int gb = 1;
+ if (gb) fprintf(stderr, "\n GOT dt: %.3f gpi: %d\n", dt, got_pointer_input);
dtime(&tm);
g = g_in = got_pointer_input;
@@ -13519,12 +14342,15 @@ static void check_user_input2(double dt) {
XFlush(dpy);
spin += dtime(&tm);
+ if (gb) fprintf(stderr, " sp=%.3f ", spin);
if (spin > quick_spin_fac * dt) {
/* get out if spin time comparable to last scan time */
+ if (gb) fprintf(stderr, " SPIN-OUT: %.3f qsf * dt: %.3f", spin, quick_spin_fac * dt);
break;
}
if (got_pointer_input > g) {
+ if (gb) fprintf(stderr, "-%d", got_pointer_input - g_in);
g = got_pointer_input;
if (eaten++ < max_eat) {
continue;
@@ -13533,10 +14359,13 @@ static void check_user_input2(double dt) {
miss++;
}
if (miss > 1) { /* 1 means out on 2nd miss */
+ if (gb) fprintf(stderr, " MISS-BRK: %.3f", spin);
break;
}
}
+ if (gb && eaten >= max_eat) fprintf(stderr, " +MAX_EAT");
+ if (gb) fprintf(stderr, "\n");
/*
* Probably grinding with a lot of fb I/O if dt is this large.
@@ -13572,14 +14401,17 @@ static void check_user_input2(double dt) {
g = got_pointer_input;
miss = 0;
+ if (gb) fprintf(stderr, " GRIND ms: %d ", ms);
for (i=0; i<split; i++) {
usleep(ms * 1000);
+ if (gb) fprintf(stderr, "*");
if (show_multiple_cursors) {
rfbPE(screen, 1000);
} else {
rfbCFD(screen, 1000);
}
spin += dtime(&tm);
+ if (gb) fprintf(stderr, "%d", got_pointer_input - g_in);
if (got_pointer_input > g) {
XFlush(dpy);
miss = 0;
@@ -13594,6 +14426,8 @@ static void check_user_input2(double dt) {
break;
}
}
+ if (gb && i == split) fprintf(stderr, " +MAX_GR");
+ if (gb) fprintf(stderr, " spin: %.3f\n", spin);
}
}
@@ -13607,13 +14441,16 @@ static void check_user_input3(double dt, double dtr, int tile_diffs) {
int gcnt, ginput;
static int first = 1;
+ static int gb = 1;
if (first) {
char *p = getenv("SPIN");
if (p) {
double junk;
sscanf(p, "%lf,%lf", &dt_cut, &junk);
+ gb = 1;
}
+fprintf(stderr, " dt_cut: %f \n", dt_cut);
first = 0;
}
@@ -13621,6 +14458,7 @@ static void check_user_input3(double dt, double dtr, int tile_diffs) {
return;
}
+if (gb) fprintf(stderr, "\n GOT dt: %.3f gpi: %d\n", dt, got_pointer_input);
if (dt < dt_cut) {
dt = dt_cut; /* this is to try to avoid early exit */
@@ -13654,6 +14492,7 @@ static void check_user_input3(double dt, double dtr, int tile_diffs) {
dtm = dtime(&tm);
spin += dtm;
+if (gb) fprintf(stderr, " dtm=%.4f", dtm);
if (got_pointer_input == g) {
if (last_was_miss) {
@@ -13671,9 +14510,11 @@ static void check_user_input3(double dt, double dtr, int tile_diffs) {
if (spin > spin_max) {
/* get out if spin time over limit */
+if (gb) fprintf(stderr, " SPIN-OUT: %.4f", spin);
break;
} else if (got_pointer_input > g) {
+if (gb) fprintf(stderr, ">>%d/dtp=%.4f, ", got_pointer_input - g_in, tm - to); to = tm;
/* received some input, flush to display. */
got_input = 1;
g = got_pointer_input;
@@ -13682,9 +14523,11 @@ static void check_user_input3(double dt, double dtr, int tile_diffs) {
X_UNLOCK;
} else if (--allowed_misses <= 0) {
/* too many misses */
+if (gb) fprintf(stderr, ">>*M\nMISS-BRK: %.4f", spin);
break;
} else if (consecutive_misses >=3) {
/* too many misses */
+if (gb) fprintf(stderr, ">>*M\nMISS-CONS: %.4f", spin);
break;
} else {
/* these are misses */
@@ -13697,9 +14540,12 @@ static void check_user_input3(double dt, double dtr, int tile_diffs) {
* will batch them.
*/
wms = 50;
+if (gb) fprintf(stderr, ">>*M-FST, ");
} else if (button_mask) {
wms = 10;
+if (gb) fprintf(stderr, ">>*M, ");
} else {
+if (gb) fprintf(stderr, ">>*M, ");
}
if (wms) {
usleep(wms * 1000);
@@ -13714,6 +14560,7 @@ static void check_user_input3(double dt, double dtr, int tile_diffs) {
}
}
+if (gb) fprintf(stderr, "\n");
drag_in_progress = 0;
}
@@ -13729,6 +14576,7 @@ int fb_update_sent(int *count) {
}
rfbReleaseClientIterator(i);
if (sent != last_count) {
+ if (0) fprintf(stderr, "\n***FB_UPDATE_SENT***\n");
rc = 1;
}
if (count != NULL) {
@@ -13740,6 +14588,7 @@ int fb_update_sent(int *count) {
static void check_user_input4(double dt, double dtr, int tile_diffs) {
+static int gb = 1;
int g, g_in, i, ginput, gcnt, tmp;
int last_was_miss, consecutive_misses;
int min_frame_size = 10; /* 10 tiles */
@@ -13763,7 +14612,9 @@ static void check_user_input4(double dt, double dtr, int tile_diffs) {
char *p = getenv("SPIN");
if (p) {
sscanf(p, "%lf,%lf,%lf,%lf", &dt_cut, &Tfac_r, &Tfac_v, &Tfac_n);
+ gb = 1;
}
+ fprintf(stderr, "dt_cut: %f Tfac_r/r: %f/%f Tdelay: %f\n", dt_cut, Tfac_r, Tfac_v, Tdelay);
first = 0;
ssec = time(0);
}
@@ -13819,11 +14670,16 @@ static void check_user_input4(double dt, double dtr, int tile_diffs) {
}
/* damn, they didn't push our frame! */
iter++;
+ if (gb && iter == 1) fprintf(stderr, "PUSH_FRAME:");
+ if (gb) fprintf(stderr, " %d", iter);
+// measure_send_rates(1);
rfbPE(screen, rfb_wait_ms * 1000);
+// measure_send_rates(0);
push_spin += dtime(&tp);
}
if (iter) {
+ if (gb) fprintf(stderr, "\n");
X_LOCK;
XFlush(dpy);
X_UNLOCK;
@@ -13836,6 +14692,7 @@ static void check_user_input4(double dt, double dtr, int tile_diffs) {
* when we first enter we require some pointer input
*/
if (!got_pointer_input) {
+ if (gb && dtr > 0.05) fprintf(stderr, "-- dt: %.3f dtr: %.3f\n", dt, dtr);
return;
}
@@ -13864,6 +14721,13 @@ static void check_user_input4(double dt, double dtr, int tile_diffs) {
rpe_last = to = tc = tm; /* last time we did rfbPE() */
g = g_in = got_pointer_input;
+ if (gb) {
+ fprintf(stderr, "\n GOT dt: %.3f dtr: %.3f gpi: %d dt_min: %.3f"
+ " dt_max: %.3f TD= %d Ttiletm: %.3f"
+ " now: %.3f vnccpu_rate: %.2f KB/sec screen_rate: %.2f MB/sec net_rate: %.2f KB/sec Delay: %.4f sec \n",
+ dt, dtr, got_pointer_input, dt_min, dt_max,
+ tile_diffs, Ttile * tile_diffs, tm - ssec, vnccpu_rate / 1000, screen_rate / 1000000, net_rate/1000, Tdelay);
+ }
tile_diffs = 0; /* reset our knowlegde of tile_diffs to zero */
while (1) {
@@ -13885,7 +14749,9 @@ static void check_user_input4(double dt, double dtr, int tile_diffs) {
if ( (gcnt == 1 && got_pointer_input > g) || tm-tc > 2*dt_min) {
tile_diffs = scan_for_updates(1);
tc = tm;
+ if (gb) fprintf(stderr, " NewTD%s=%d/%.3f", tile_diffs > 10 ? "*" : "", tile_diffs, spin);
}
+ if (gb) fprintf(stderr, " dtm%s=%.4f", dtm >= 0.05 ? "*" : "", dtm);
if (got_pointer_input == g) {
if (last_was_miss) {
@@ -13900,6 +14766,7 @@ static void check_user_input4(double dt, double dtr, int tile_diffs) {
if (tile_diffs > min_frame_size && spin > Ttile * tile_diffs + Tdelay) {
/* we think we can push the frame */
+ if (gb) fprintf(stderr, "\n ##FRAME-OUT: %.4f Btile: %d del: %.3f", spin, Btile * tile_diffs, tm - ssec);
push_frame = 1;
fb_update_sent(&update_count);
break;
@@ -13911,9 +14778,11 @@ static void check_user_input4(double dt, double dtr, int tile_diffs) {
X_LOCK;
XFlush(dpy);
X_UNLOCK;
+ if (gb) fprintf(stderr, "++%d/dtp=%.4f, ", got_pointer_input - g_in, tm - to); to = tm;
} else if (consecutive_misses >= 2) {
/* too many misses in a row */
+ if (gb) fprintf(stderr, ">>*M\nMISS-CONS: %.4f del: %.3f", spin, tm - ssec);
break;
} else {
@@ -13927,13 +14796,17 @@ static void check_user_input4(double dt, double dtr, int tile_diffs) {
* of them for the next read.
*/
wms = 50;
+ if (gb) fprintf(stderr, ">>*M-FST, ");
} else if (button_mask) {
wms = 10;
+ if (gb) fprintf(stderr, ">>*M-DRG, ");
} else {
wms = 0;
+ if (gb) fprintf(stderr, ">>*M, ");
}
if (wms) {
+ if (gb) fprintf(stderr, "wms=%d, ", wms);
usleep(wms * 1000);
}
}
@@ -13944,6 +14817,7 @@ static void check_user_input4(double dt, double dtr, int tile_diffs) {
rfbCFD(screen, rfb_wait_ms * 1000);
}
}
+ if (gb) fprintf(stderr, "\n");
drag_in_progress = 0;
}
@@ -14166,6 +15040,8 @@ void measure_send_rates(int init) {
ClientData *cd = (ClientData *) cl->clientData;
tmp2 = 0.0;
dtime(&tmp2);
+fprintf(stderr, "client num rects init=%d: req: %d mod: %d time: %.3f\n", init,
+ (int) sraRgnCountRects(cl->requestedRegion), (int) sraRgnCountRects(cl->modifiedRegion), tmp2);
if (init) {
continue;
}
@@ -14244,6 +15120,7 @@ if (init) {
dbr = rbs - cd->set_raw_bytes;
cmp_rate = db/dt;
raw_rate = dbr/dt;
+fprintf(stderr, "RATE: %11.2f RAW: %11.2f dt: %.3f B: %7d R: %7d\n", cmp_rate, raw_rate, dt, db, dbr);
if (dbr > min_width * min_width * bpp/8) {
cd->sample++;
if (cd->sample >= RATE_SAMPLES) {
@@ -14266,7 +15143,11 @@ void rfbPE(rfbScreenInfoPtr scr, long usec) {
return;
}
if (! use_threads) {
+BEG
+measure_send_rates(1);
rfbProcessEvents(scr, usec);
+measure_send_rates(0);
+END(libvnc_time); libvnc_count++;
}
}
@@ -14275,7 +15156,9 @@ void rfbCFD(rfbScreenInfoPtr scr, long usec) {
return;
}
if (! use_threads) {
+BEG
rfbCheckFds(scr, usec);
+END(libvnc_time); libvnc_count++;
}
}
@@ -14285,6 +15168,7 @@ void rfbCFD(rfbScreenInfoPtr scr, long usec) {
static void watch_loop(void) {
int cnt = 0, tile_diffs = 0;
double dt = 0.0, dtr = 0.0;
+ time_t start = time(0);
if (use_threads) {
rfbRunEventLoop(screen, -1, TRUE);
@@ -14299,7 +15183,9 @@ static void watch_loop(void) {
if (! use_threads) {
double tm = 0.0;
dtime(&tm);
+// measure_send_rates(1);
rfbPE(screen, -1);
+// measure_send_rates(0);
dtr = dtime(&tm);
fb_update_sent(NULL);
@@ -14327,11 +15213,24 @@ static void watch_loop(void) {
check_connect_inputs();
check_padded_fb();
+ if (first_conn_timeout < 0) {
+ start = time(0);
+ first_conn_timeout = -first_conn_timeout;
+ }
if (! screen || ! screen->clientHead) {
/* waiting for a client */
+ if (first_conn_timeout) {
+ if (time(0) - start > first_conn_timeout) {
+ rfbLog("No client after %d secs.\n",
+ first_conn_timeout);
+ shut_down = 1;
+ continue;
+ }
+ }
usleep(200 * 1000);
continue;
}
+ first_conn_timeout = 0;
if (nofb) {
/* no framebuffer polling needed */
@@ -14362,6 +15261,7 @@ static void watch_loop(void) {
double tm = 0.0;
dtime(&tm);
+ RFBUNDRAWCURSOR(screen);
if (use_snapfb) {
int t, tries = 5;
copy_snap();
@@ -14451,6 +15351,12 @@ static void print_help(void) {
" shifts a root view to it: this shows SaveUnders menus,\n"
" etc, although they will be clipped if they extend beyond\n"
" the window.\n"
+#if 0
+"-nosu Intended for use with -id windowid. Follow the window\n"
+" tree down and *irreversibly* disable BackingStore and\n"
+" SaveUnders for all windows. The hope is this will show\n"
+" the popups and menus in -id mode. Use with caution.\n"
+#endif
"-flashcmap In 8bpp indexed color, let the installed colormap flash\n"
" as the pointer moves from window to window (slow).\n"
"-notruecolor For 8bpp displays, force indexed color (i.e. a colormap)\n"
@@ -14521,6 +15427,8 @@ static void print_help(void) {
" disconnects, opposite of -forever. This is the Default.\n"
"-forever Keep listening for more connections rather than exiting\n"
" as soon as the first client(s) disconnect. Same as -many\n"
+"-timeout n Exit unless a client connects within the first n seconds\n"
+" of startup.\n"
"-inetd Launched by inetd(1): stdio instead of listening socket.\n"
" Note: if you are not redirecting stderr to a log file\n"
" (via shell 2> or -o option) you must also specify the\n"
@@ -14799,9 +15707,9 @@ static void print_help(void) {
" with -nocursor, and also some values of the \"mode\"\n"
" option below.\n"
" \n"
-" Note that under XFIXES cursors with transparency\n"
-" (alpha channel) will not be exactly represented and\n"
-" so Overlay may be preferred. See also the -alphacut\n"
+" Note that under XFIXES cursors with transparency (alpha\n"
+" channel) will not be exactly represented and one may\n"
+" find Overlay may be preferable. See also the -alphacut\n"
" and -alphafrac options below as fudge factors to try\n"
" to improve the situation for cursors with transparency\n"
" for a given theme.\n"
@@ -14860,14 +15768,14 @@ static void print_help(void) {
" black background). Specify this option to remove the\n"
" alpha factor. (useful for light colored semi-transparent\n"
" cursors).\n"
-"-alphablend In XFIXES mode send cursor alpha channel data to\n"
-" libvncserver. The blending effect will only be\n"
-" visible in -nocursorshape mode or for clients with\n"
-" cursorshapeupdates turned off. (However there is a\n"
-" hack for 32bpp with depth 24, it uses the extra 8 bits\n"
-" to store cursor transparency for use with a hacked\n"
-" vncviewer that applies the transparency locally.\n"
-" See the FAQ for more info).\n"
+"-noalphablend In XFIXES mode do not send cursor alpha channel data\n"
+" to libvncserver. The default is to send it. The\n"
+" alphablend effect will only be visible in -nocursorshape\n"
+" mode or for clients with cursorshapeupdates turned\n"
+" off. (However there is a hack for 32bpp with depth 24,\n"
+" it uses the extra 8 bits to store cursor transparency\n"
+" for use with a hacked vncviewer that applies the\n"
+" transparency locally. See the FAQ for more info).\n"
"\n"
"-nocursorshape Do not use the TightVNC CursorShapeUpdates extension\n"
" even if clients support it. See -cursor above.\n"
@@ -15131,6 +16039,9 @@ static void print_help(void) {
" noshared disable -shared mode.\n"
" forever enable -forever mode.\n"
" noforever disable -forever mode.\n"
+" timeout:n reset -timeout to n, if there are\n"
+" currently no clients, exit unless one\n"
+" connects in the next n secs.\n"
" deny deny any new connections, same as \"lock\"\n"
" nodeny allow new connections, same as \"unlock\"\n"
" connect:host do reverse connection to host, \"host\"\n"
@@ -15214,8 +16125,8 @@ static void print_help(void) {
" alphafrac:f set -alphafrac to f.\n"
" alpharemove enable -alpharemove mode.\n"
" noalpharemove disable -alpharemove mode.\n"
-" alphablend enable -alphablend mode.\n"
-" noalphablend disable -alphablend mode.\n"
+" alphablend disable -noalphablend mode.\n"
+" noalphablend enable -noalphablend mode.\n"
" cursorshape disable -nocursorshape mode.\n"
" nocursorshape enable -nocursorshape mode.\n"
" cursorpos disable -nocursorpos mode.\n"
@@ -15307,8 +16218,8 @@ static void print_help(void) {
" nowaitmapped flashcmap noflashcmap truecolor notruecolor\n"
" overlay nooverlay overlay_cursor overlay_yescursor\n"
" nooverlay_nocursor nooverlay_cursor nooverlay_yescursor\n"
-" overlay_nocursor visual scale viewonly noviewonly\n"
-" shared noshared forever noforever once deny lock nodeny\n"
+" overlay_nocursor visual scale viewonly noviewonly shared\n"
+" noshared forever noforever once timeout deny lock nodeny\n"
" unlock connect allowonce allow localhost nolocalhost\n"
" accept gone shm noshm flipbyteorder noflipbyteorder\n"
" onetile noonetile blackout xinerama noxinerama xrandr\n"
@@ -15330,16 +16241,16 @@ static void print_help(void) {
" noalwaysshared nevershared noalwaysshared dontdisconnect\n"
" nodontdisconnect desktop noremote\n"
"\n"
-" aro= display vncdisplay desktopname auth rootshift\n"
-" scale_str scaled_x scaled_y scale_numer scale_denom\n"
-" scale_fac scaling_noblend scaling_nomult4 scaling_pad\n"
-" scaling_interpolate inetd safer unsafe passwdfile\n"
-" using_shm logfile o rc norc h help V version lastmod\n"
-" bg sigpipe threads clients client_count pid ext_xtest\n"
-" ext_xkb ext_xshm ext_xinerama ext_overlay ext_xfixes\n"
-" ext_xdamage ext_xrandr rootwin num_buttons button_mask\n"
-" mouse_x mouse_y bpp depth indexed_color dpy_x dpy_y\n"
-" rfbauth passwd\n"
+" aro= display vncdisplay desktopname http_url auth\n"
+" rootshift scale_str scaled_x scaled_y scale_numer\n"
+" scale_denom scale_fac scaling_noblend scaling_nomult4\n"
+" scaling_pad scaling_interpolate inetd safer unsafe\n"
+" passwdfile using_shm logfile o rc norc h help V version\n"
+" lastmod bg sigpipe threads clients client_count pid\n"
+" ext_xtest ext_xkb ext_xshm ext_xinerama ext_overlay\n"
+" ext_xfixes ext_xdamage ext_xrandr rootwin num_buttons\n"
+" button_mask mouse_x mouse_y bpp depth indexed_color\n"
+" dpy_x dpy_y rfbauth passwd\n"
"\n"
"-sync By default -remote commands are run asynchronously, that\n"
" is, the request is posted and the program immediately\n"
@@ -15393,6 +16304,25 @@ static void print_help(void) {
"These options are passed to libvncserver:\n"
"\n"
;
+//" It also sets -xwarppointer, use -noxwarppointer to undo.\n"
+ char help2[] =
+"but first, here are some experimental ones (your version may not have them):\n"
+"\n"
+"-d Turn on debugging and stats output.\n"
+"-naptile n Cutoff/max number of tile changes per poll to permit\n"
+" a nap between polls. Use 0 to disable. Default %d\n"
+"-napfac n Factor by which to multiply the wait ms (see -wait)\n"
+" to get the nap time. Default: %d times waitms\n"
+"-napmax time Maximum time in ms for a nap. Default: %d\n"
+#ifdef VCR_HACK
+"-vcr Vertical CopyRect. Enable an experimental hack to detect\n"
+" vertical displacements (i.e. scrolls) and send them\n"
+" using the very efficient CopyRect encoding. UNSTABLE!\n"
+#endif
+"\n"
+"These options are passed to libvncserver:\n"
+"\n"
+;
/* have both our help and rfbUsage to stdout for more(1), etc. */
dup2(1, 2);
fprintf(stderr, help, lastmod,
@@ -15417,6 +16347,9 @@ static void print_help(void) {
tile_fuzz,
""
);
+ if (getenv("X11VNC_STD_HELP") == NULL) {
+ fprintf(stderr, help2, naptile, napfac, napmax);
+ }
rfbUsage();
exit(1);
@@ -15722,6 +16655,9 @@ static void check_rcfile(int argc, char **argv) {
exit(1);
}
}
+ for (i=0; i < argc2; i++) {
+// fprintf(stderr, "argv2[%d] \"%s\"\n", i, argv2[i]);
+ }
}
int main(int argc, char* argv[]) {
@@ -15816,6 +16752,8 @@ int main(int argc, char* argv[]) {
}
} else if (!strcmp(arg, "-waitmapped")) {
subwin_wait_mapped = 1;
+ } else if (!strcmp(arg, "-nosu")) {
+ no_su = 1;
} else if (!strcmp(arg, "-flashcmap")) {
flash_cmap = 1;
} else if (!strcmp(arg, "-notruecolor")) {
@@ -15842,6 +16780,9 @@ int main(int argc, char* argv[]) {
connect_once = 1;
} else if (!strcmp(arg, "-many") || !strcmp(arg, "-forever")) {
connect_once = 0;
+ } else if (!strcmp(arg, "-timeout")) {
+ CHECK_ARGC
+ first_conn_timeout = atoi(argv[++i]);
} else if (!strcmp(arg, "-inetd")) {
inetd = 1;
} else if (!strcmp(arg, "-connect")) {
@@ -15993,8 +16934,8 @@ int main(int argc, char* argv[]) {
alpha_frac = atof(argv[++i]);
} else if (!strcmp(arg, "-alpharemove")) {
alpha_remove = 1;
- } else if (!strcmp(arg, "-alphablend")) {
- alpha_blend = 1;
+ } else if (!strcmp(arg, "-noalphablend")) {
+ alpha_blend = 0;
} else if (!strcmp(arg, "-nocursorshape")) {
cursor_shape_updates = 0;
} else if (!strcmp(arg, "-cursorpos")) {
@@ -16113,6 +17054,21 @@ int main(int argc, char* argv[]) {
safe_remote_only = 1;
} else if (!strcmp(arg, "-deny_all")) {
deny_all = 1;
+ } else if (!strcmp(arg, "-d") || !strcmp(arg, "-debug")) {
+ debug = 1;
+ } else if (!strcmp(arg, "-naptile")) {
+ CHECK_ARGC
+ naptile = atoi(argv[++i]);
+ } else if (!strcmp(arg, "-napfac")) {
+ CHECK_ARGC
+ napfac = atoi(argv[++i]);
+ } else if (!strcmp(arg, "-napmax")) {
+ CHECK_ARGC
+ napmax = atoi(argv[++i]);
+#ifdef VCR_HACK
+ } else if (!strcmp(arg, "-vcr")) {
+ vcopyrect = 1;
+#endif
} else if (!strcmp(arg, "-httpdir")) {
CHECK_ARGC
http_dir = strdup(argv[++i]);
@@ -16381,6 +17337,7 @@ int main(int argc, char* argv[]) {
fprintf(stderr, " viewonly: %d\n", view_only);
fprintf(stderr, " shared: %d\n", shared);
fprintf(stderr, " conn_once: %d\n", connect_once);
+ fprintf(stderr, " timeout: %d\n", first_conn_timeout);
fprintf(stderr, " inetd: %d\n", inetd);
fprintf(stderr, " connect: %s\n", client_connect
? client_connect : "null");
@@ -16409,7 +17366,7 @@ int main(int argc, char* argv[]) {
fprintf(stderr, " logfile: %s\n", logfile ? logfile
: "null");
fprintf(stderr, " logappend: %d\n", logfile_append);
- fprintf(stderr, " rc_file: %s\n", rc_rcfile ? rc_rcfile
+ fprintf(stderr, " rc_file: \%s\n", rc_rcfile ? rc_rcfile
: "null");
fprintf(stderr, " norc: %d\n", rc_norc);
fprintf(stderr, " bg: %d\n", bg);
@@ -16455,6 +17412,8 @@ int main(int argc, char* argv[]) {
fprintf(stderr, " sb: %d\n", screen_blank);
fprintf(stderr, " sigpipe: %s\n", sigpipe
? sigpipe : "null");
+ fprintf(stderr, " nap t-f-m: %d/%d/%d\n", naptile, napfac,
+ napmax);
fprintf(stderr, " threads: %d\n", use_threads);
fprintf(stderr, " fs_frac: %.2f\n", fs_frac);
fprintf(stderr, " gaps_fill: %d\n", gaps_fill);
@@ -16467,6 +17426,7 @@ int main(int argc, char* argv[]) {
fprintf(stderr, " noremote: %d\n", !accept_remote_cmds);
fprintf(stderr, " safemode: %d\n", safe_remote_only);
fprintf(stderr, " deny_all: %d\n", deny_all);
+ fprintf(stderr, " debug: %d\n", debug);
fprintf(stderr, "\n");
rfbLog("x11vnc version: %s\n", lastmod);
} else {
@@ -16514,6 +17474,26 @@ int main(int argc, char* argv[]) {
dpy = XOpenDisplay("");
}
+ if (! dpy && ! use_dpy && ! getenv("DISPLAY")) {
+ int i, s = 4;
+ rfbLog("\a\n");
+ rfbLog("*** XOpenDisplay failed. No -display or DISPLAY.\n");
+ rfbLog("*** Trying \":0\" in %d seconds. Press Ctrl-C to"
+ " abort.\n", s);
+ rfbLog("*** ");
+ for (i=1; i<=s; i++) {
+ fprintf(stderr, "%d ", i);
+ sleep(1);
+ }
+ fprintf(stderr, "\n");
+ use_dpy = ":0";
+ dpy = XOpenDisplay(use_dpy);
+ if (dpy) {
+ rfbLog("*** XOpenDisplay of \":0\" successful.\n");
+ }
+ rfbLog("\n");
+ }
+
if (! dpy) {
rfbLog("XOpenDisplay failed (%s)\n", use_dpy ? use_dpy:"null");
exit(1);
@@ -16760,6 +17740,11 @@ int main(int argc, char* argv[]) {
initialize_signals();
+#ifdef VCR_HACK
+ if (vcopyrect) {
+ initialize_vcr();
+ }
+#endif
initialize_speeds();
@@ -16813,3 +17798,1009 @@ int main(int argc, char* argv[]) {
#undef argv
}
+/* -- vcr.c -- */
+
+/* ######################################################################## */
+/* experiment to look for vertical copy rect changes */
+#ifdef VCR_HACK
+
+/*
+ * vcr_send()
+ * Takes the copyrect info (currently limited to a single column of
+ * changed tiles) and schedules the CopyRegion with libvncserver.
+ */
+static void vcr_send(int x0, int y0, int x1, int y1, int del) {
+ sraRegionPtr copy_region;
+
+ copy_region = (sraRegionPtr) sraRgnCreateRect(x0, y0, x1, y1);
+ rfbScheduleCopyRegion(screen, copy_region, 0, del);
+ sraRgnDestroy(copy_region);
+}
+
+/*
+ * vcr_flush2()
+ * Current hack to try to force libvncserver to flush the copyRegion
+ * changes. It splits up the deferUpdateTime into time slices and
+ * tries to force the rfbSendUpdateBuf for each connected client.
+ *
+ * mode = 0 means just try to flush all the copyRegion changes.
+ * mode = 1 means try to flush both the copyRegion and modifiedRegion changes.
+ */
+static void vcr_flush2(int mode) {
+ int k1, k2, j, n, nfac = 10;
+ rfbClientIteratorPtr i;
+ rfbClientPtr cl;
+
+ fprintf(stderr, "vcr_flush2 ");
+
+ /* break up the time into ~nfac slices. */
+ n = screen->deferUpdateTime / nfac;
+
+ for (j=0; j < nfac + 3; j++) {
+ /* loop over each time slice */
+
+ fprintf(stderr, ".");
+ usleep(n * 1000);
+
+ /* give rfbProcessEvents a shot. */
+ rfbPE(screen, 0);
+
+ /*
+ * loop over connected clients and examine
+ * their copyRegion/modifiedRegion regions
+ * if they exist, try to flush them.
+ */
+ i = rfbGetClientIterator(screen);
+ k1 = 0;
+ k2 = 0;
+ while( (cl = rfbClientIteratorNext(i)) ) {
+ /* check modifiedRegion */
+ if (sraRgnEmpty(cl->modifiedRegion)) {
+ fprintf(stderr, " MOD=empty ");
+ } else {
+ fprintf(stderr, " MOD=NOT ");
+ if (mode == 1) {
+ rfbSendUpdateBuf(cl);
+ }
+ k2++;
+ }
+
+ /* check copyRegion */
+ if (sraRgnEmpty(cl->copyRegion)) {
+ fprintf(stderr, " CR=empty ");
+ } else {
+ fprintf(stderr, " CR=NOT ");
+ rfbSendUpdateBuf(cl);
+ k1++;
+ }
+ }
+ rfbReleaseClientIterator(i);
+
+ if (mode == 0) {
+ if (k1 == 0) {
+ break;
+ }
+ } else if (mode == 1) {
+ if (k1 == 0 && k2 == 0) {
+ break;
+ }
+ }
+ }
+ fprintf(stderr, " k1=%d/k2=%d\n", k1, k2);
+}
+
+/*
+ * vcr_flush1()
+ * simple try; didn't work.
+static void vcr_flush1(int mode) {
+ rfbPE(screen, 0);
+}
+ */
+
+/* flush wrapper */
+static void vcr_flush(int mode) {
+ vcr_flush2(mode);
+}
+
+/*
+ * A structure to describe a discovered vertical translation within
+ * a pair of old/new vertical scanlines.
+ */
+typedef struct displacement {
+ int runlen; /* how long the "best" concidence run was */
+ int longruns; /* how many "long" runs we found altogether */
+ int disp; /* the verticle displacement of the best run */
+ int top; /* the top (smallest y-pixel position) */
+ int mid; /* the middle y-pixel position */
+ int bot; /* the bottom (highest y-pixel position) */
+} disp_t;
+
+/*
+ * A structure for the actual copyrect we find for a bunch of adjacent
+ * vertical scanlines with the same offest del.
+ *
+ * Currently used for a copyrect only within one column of changed
+ * tiles. libvncserver seems to be pretty good at gluing them
+ * together horizontally, so we don't bother, but we could use
+ * this for that too, x1 - x0 would just be bigger.
+ */
+typedef struct copyrect {
+ int x0;
+ int y0;
+ int x1;
+ int y1;
+ int del;
+} copyrect_t;
+
+/*
+ * vcr_run()
+ * Given a column (at tile column x) of n_run changed tiles with tile
+ * column y-values y_run[n_run], try to find the offset with optimal
+ * pixel coincidence/overlap.
+ *
+ * Optimal usually means the set of scanlines with same offset giving
+ * the longest run of coincidence. But see suggested_disp below...
+ *
+ * If suggested_disp != 0, that means that vertical displacement is
+ * highly preferred, presumably being the results found from vcr_run
+ * for neighboring columns of changed tiles. suggested_disp is a hint
+ * from do_vcr().
+ *
+ * The optimal displacement copyrect is for the tile column is returned
+ * in the copyrect_t cr.
+ */
+static int vcr_run(int *y_run, int x, int n_run, copyrect_t *cr,
+ int suggested_disp) {
+ /* parameter to skip short columns of changed tiles */
+ int tile_run_min = 4;
+
+ /* minimum number of coincident y-pixels to be accepted */
+ int match_run_min = 3 * tile_y;
+
+ /* variables for the search */
+ int x0, y0, yd, del, prev_del;
+ int run_up, run_dn, run;
+ int col, n0;
+ int x_left, x_right;
+ int y_top, y_bot;
+ int i, best;
+ int y_min, y_max, y_mid;
+
+ /* tmp pointers to the old and new vertical scanline fb data */
+// int *fb_old;
+// int *fb_new;
+ char *fb_old8;
+ char *fb_new8;
+ short *fb_old16;
+ short *fb_new16;
+ int *fb_old32;
+ int *fb_new32;
+
+ /* we need a disp_t for each vertical scanline in the tile column */
+ disp_t verts[VCR_DEPTH];
+
+ if (suggested_disp) {
+ fprintf(stderr, "IN vcr_run col=%2d/%3d row=%2d/%3d tn=%2d nr=%2d pref=%3d\n",
+ x, x * tile_x, y_run[0], y_run[0] * tile_y, y_run[n_run-1], n_run, suggested_disp);
+ }
+
+ if (! suggested_disp) {
+ /* get out if the run is too short */
+ if (n_run < tile_run_min) {
+ if (suggested_disp) fprintf(stderr, "OUT vcr_run A\n");
+ return 0;
+ }
+ } else {
+ /* be more tolerant of short columns if suggested_disp given */
+ if (n_run < tile_run_min/2) {
+ if (suggested_disp) fprintf(stderr, "OUT vcr_run B\n");
+ return 0;
+ }
+ match_run_min /= 2;
+ }
+
+ /* initialize each vert scanline to "nothing found" */
+ for (col=0; col < vcr_depth; col++) {
+ verts[col].runlen = 0;
+ verts[col].disp = 0;
+ verts[col].top = -1;
+ verts[col].mid = -1;
+ verts[col].bot = -1;
+
+ verts[col].longruns = 0;
+ }
+ /*
+ * best will be the run length (number of coincident pixels) for
+ * for out "best find" so far.
+ */
+ best = -1;
+
+ /* we start out in the middle of the tile column and work outwards */
+ n0 = n_run/2; /* y-tile # in run */
+ y0 = y_run[n0] * tile_y; /* pixel position on screen */
+
+ /* little shift to y-middle of a tile if n_run is not even */
+ if (n_run % 2 != 0) {
+ y0 += tile_y/2;
+ }
+
+ /* horizontal pixel position of left edge of tile column */
+ x0 = x * tile_x;
+
+ /* lowest possible y of the tile column */
+ y_min = y_run[0] * tile_y;
+ /* highest possible y of the tile column */
+ y_max = (y_run[n_run-1] + 1) * tile_y;
+
+ fprintf(stderr, " vcr_run: x== %d\n", x);
+
+ /*
+ * Loop over each vertical scanline, using the vcr_map pattern
+ * for the order.
+ */
+ for (col=0; col < vcr_depth; col++) {
+ /*
+ * Make pointers to offsets in the before/after vertical
+ * scanline fb data for the desired scanline.
+ * (Note: the whole scanline need not be up to date,
+ * but it is up to date for the changed tile column
+ * considered here)
+ */
+ if (bpp == 32) {
+ fb_old32 = fbd_old32[x][col];
+ fb_new32 = fbd_new32[x][col];
+ } else if (bpp == 16) {
+ fb_old16 = fbd_old16[x][col];
+ fb_new16 = fbd_new16[x][col];
+ } else if (bpp == 8) {
+ fb_old8 = fbd_old8[x][col];
+ fb_new8 = fbd_new8[x][col];
+ }
+
+ /* start at the middle y-value */
+ y_mid = y0;
+
+ /*
+ * check if a previous scanline found a displacment
+ * with high coincidence. store it in prev_del.
+ * also use its y_mid value.
+ */
+ prev_del = 0;
+ for (i = col - 1; i >= 0; i--) {
+ if (verts[i].runlen > 0) {
+ y_mid = verts[i].mid;
+ prev_del = verts[i].disp;
+ break;
+ }
+ }
+
+ /*
+ * Now loop over all possible displacements between
+ * the old and new vertical scanlines.
+ * That is, y_mid + del < y_max and y_mid - del >
+ * y_min for relative displacement del.
+ *
+ * We work out way out +/- from y_mid (trying to avoid
+ * ambiguities at the top or bottom of the tile column).
+ */
+
+ for (del = 1; y_mid+del < y_max || y_mid-del > y_min; del++) {
+ int i;
+ for (i=0; i <= 1; i++) {
+ /* this is just the +/- plus/minux del aspect */
+ int d = (1 - 2*i) * del;
+
+ if (prev_del != 0 && d != prev_del) {
+ /*
+ * If we have a previous del, we want
+ * to stick to it to greatly shorten
+ * the time spent in this loop.
+ *
+ * But if we have a suggested_disp we
+ * let that drop through.
+ */
+ if (d != suggested_disp) {
+ continue;
+ }
+ }
+
+ /*
+ * Possible speedup: use longruns as a big
+ * clue the scanlines are basically constant
+ * (e.g. lies on a solid root background).
+ */
+ if (suggested_disp && d != suggested_disp
+ && verts[col].longruns > 4) {
+ continue;
+ }
+
+ /*
+ * yd will be the displaced midpoint for the
+ * new fb fb_new.
+ *
+ * y_mid will be the midpoint of the old fb
+ * fb_old.
+ */
+ yd = y_mid + d;
+
+ if (yd <= y_min || yd >= y_max) {
+ /* out of range for fb_new */
+ continue;
+ }
+
+ /*
+ * Loop upwards from these midpoints, but break
+ * out as soon as there is a pixel difference.
+ * (i.e. break out at the high-end of the
+ * coincidence)
+ */
+ if (bpp == 32) {
+ for (run_up = 0; yd+run_up < y_max
+ && y_mid+run_up < y_max; run_up++) {
+ if ( *(fb_old32 + (y_mid+run_up))
+ != *(fb_new32 + (yd+run_up))) {
+ break;
+ }
+ }
+ }
+ /*
+ * Loop downwards from these midpoints, but break
+ * out as soon as there is a pixel difference.
+ * (i.e. break out at the low-end of the
+ * coincidence)
+ *
+ * Note: for 16bpp we really check two pixels
+ * at a time, for 8bpp we check 4 at a time.
+ */
+ if (bpp == 32) {
+ for (run_dn =-1; yd+run_dn > y_min
+ && y_mid+run_dn > y_min; run_dn--) {
+ if ( *(fb_old32 + (y_mid+run_dn))
+ != *(fb_new32 + (yd+run_dn))) {
+ break;
+ }
+ }
+ }
+
+ /* compute the total number of coincident pixels */
+ run = run_up - run_dn - 1;
+
+ if (run > match_run_min) {
+ /*
+ * It is long enough, add to the tally
+ * of long runs.
+ */
+ verts[col].longruns++;
+
+ /*
+ * Now check if it is the longest one
+ * so far or matches the suggested_disp.
+ *
+ * TODO: what if d == suggested_disp is
+ * overridden later?
+ */
+ if (run > verts[col].runlen
+ || d == suggested_disp) {
+ if (run > best) {
+ /* best for any scanline */
+ best = run;
+ }
+
+ /* record the best for this scanline */
+ verts[col].runlen = run;
+ verts[col].disp = d;
+ verts[col].top = y_mid + run_dn;
+ verts[col].mid = y_mid;
+ verts[col].bot = y_mid + run_up;
+ }
+ }
+ }
+ }
+ }
+
+ if (best < 0) {
+ /* did not find anything. */
+ fprintf(stderr, "vcr_run return 0, no best\n");
+ return 0;
+ }
+
+ /*
+ * Now, not all of the coincidences in the vertical scanlines
+ * may be the same. The may start and stop at different y-values.
+ *
+ * And (we hope not, but) a single displacement may not apply
+ * to all of the vertical scanlines.
+ *
+ * So we loop over the scanlines and try to find
+ * the minimal/optimal set that applies to most of them.
+ *
+ * The result will be the basis of the copyrect rectangle
+ * we send to libvncserver.
+ */
+
+ x_left = -1; /* furthest left scanline x position */
+ x_right = -1; /* furthest right scanline x position */
+ y_top = -1; /* y-bound from the top (small y) */
+ y_bot = -1; /* y-bound from the bottom (large y) */
+ del = 0; /* the vertical displacement found */
+
+ for (col=0; col < vcr_depth; col++) {
+ if (verts[col].runlen < 1) {
+ /* no concidence found for this scan line */
+ continue;
+ }
+ if (del == 0) {
+ /* use the first one... */
+ del = verts[col].disp;
+ } else if (del != verts[col].disp) {
+ /*
+ * skip if not equal to first one
+ * XXX improve
+ */
+ continue;
+ }
+ if (y_top < 0 || verts[col].top > y_top) {
+ /* trim y_top to include this scanline */
+ y_top = verts[col].top;
+ }
+ if (y_bot < 0 || verts[col].bot < y_bot) {
+ /* trim y_bot to include this scanline */
+ y_bot = verts[col].bot;
+ }
+ if (x_left < 0 || vcr_map[col] < x_left ) {
+ /* hmm, correct?... */
+ x_left = vcr_map[col];
+ }
+ if (x_right < 0 || vcr_map[col] > x_right ) {
+ /* hmm, correct?... */
+ x_right = vcr_map[col];
+ }
+
+ fprintf(stderr, " vcr_run: m_match: del=%4d run=%3d ymin=%3d ymid=%3d ymax=%3d lruns=%3d col=%d\n",
+ verts[col].disp, verts[col].runlen, verts[col].top, verts[col].mid, verts[col].bot, verts[col].longruns, vcr_map[col]);
+ }
+
+ if (del == 0 || x_left == -1 || x_right == -1 || y_top == -1 || y_bot == -1) {
+ /* not everything agreed/made sense */
+ return 0;
+ }
+
+ if (x_left == x_right || y_top == y_bot) {
+ /* only one scanline or no y span (line/point not a rectangle) */
+ return 0;
+ }
+ fprintf(stderr, " vcr_run: x_left=%2d x_right=%2d y_top=%3d y_bot=%3d\n", x_left, x_right, y_top, y_bot);
+
+ /*
+ * Finally, create the copyrect_t.
+ * XXX these may still have off by 1 pixel errors...
+ */
+ if (del > 0) {
+ /* new fb is displaced downward from old fb */
+ cr->x0 = x0 + x_left;
+ cr->y0 = y_top + del + 1;
+ cr->x1 = x0 + x_right + 1;
+ cr->y1 = y_bot + del;
+ cr->del = del;
+ } else {
+ /* new fb is displaced upward from old fb */
+ cr->x0 = x0 + x_left;
+ cr->y0 = y_top + del + 1;
+ cr->x1 = x0 + x_right + 1;
+ cr->y1 = y_bot + del;
+ cr->del = del;
+ }
+ return 1;
+}
+
+#define WMAX 40 /* max number of horizontal tiles */
+#define YMAX 40 /* max number of vertical tiles */
+
+/*
+ * char fbd_old[ntile_x][tile_x * (bpp/8)][dpy_y];
+ */
+void initialize_vcr(void) {
+ int i, j;
+
+ if (bpp == 24) {
+ rfbLog("initialize_vcr: disabling -vcr in 24bpp mode\n");
+ vcopyrect = 0;
+ return;
+ }
+ if (dpy_x % tile_x != 0) {
+ rfbLog("initialize_vcr: disabling -vcr: display width is not "
+ "a multiple of %d\n", tile_x);
+ vcopyrect = 0;
+ return;
+ }
+ if (dpy_y % tile_y != 0) {
+ rfbLog("initialize_vcr: disabling -vcr: display height is not "
+ "a multiple of %d\n", tile_y);
+ vcopyrect = 0;
+ return;
+ }
+
+ if (bpp == 8) {
+ fbd_old8 = (char ***) malloc(ntiles_x * sizeof(char **));
+ fbd_new8 = (char ***) malloc(ntiles_x * sizeof(char **));
+
+ for (i=0; i < ntiles_x; i++) {
+ fbd_old8[i] = (char **) malloc(tile_x*sizeof(char *));
+ fbd_new8[i] = (char **) malloc(tile_x*sizeof(char *));
+
+ for (j=0; j < tile_x; j++) {
+ size_t n = (size_t) dpy_y * sizeof(char *);
+ fbd_old8[i][j] = (char *) malloc(n);
+ fbd_new8[i][j] = (char *) malloc(n);
+ }
+ }
+
+ /* temp array for one tile row */
+ fbt_old8 = (char **) malloc(dpy_x * sizeof(char *));
+ fbt_new8 = (char **) malloc(dpy_x * sizeof(char *));
+ for (i=0; i < dpy_x; i++) {
+ size_t n = (size_t) tile_y * sizeof(char *);
+ fbt_old8[i] = (char *) malloc(n);
+ fbt_new8[i] = (char *) malloc(n);
+ }
+
+ } else if (bpp == 16) {
+ fbd_old16 = (short ***) malloc(ntiles_x * sizeof(short **));
+ fbd_new16 = (short ***) malloc(ntiles_x * sizeof(short **));
+
+ for (i=0; i < ntiles_x; i++) {
+ fbd_old16[i] = (short **)malloc(tile_x*sizeof(short *));
+ fbd_new16[i] = (short **)malloc(tile_x*sizeof(short *));
+
+ for (j=0; j < tile_x; j++) {
+ size_t n = (size_t) dpy_y * sizeof(short *);
+ fbd_old16[i][j] = (short *) malloc(n);
+ fbd_new16[i][j] = (short *) malloc(n);
+ }
+ }
+
+ /* temp array for one tile row */
+ fbt_old16 = (short **) malloc(dpy_x * sizeof(short *));
+ fbt_new16 = (short **) malloc(dpy_x * sizeof(short *));
+ for (i=0; i < dpy_x; i++) {
+ size_t n = (size_t) tile_y * sizeof(short *);
+ fbt_old16[i] = (short *) malloc(n);
+ fbt_new16[i] = (short *) malloc(n);
+ }
+
+ } else if (bpp == 32) {
+ fbd_old32 = (int ***) malloc(ntiles_x * sizeof(int **));
+ fbd_new32 = (int ***) malloc(ntiles_x * sizeof(int **));
+
+ for (i=0; i < ntiles_x; i++) {
+ fbd_old32[i] = (int **) malloc(tile_x*sizeof(int *));
+ fbd_new32[i] = (int **) malloc(tile_x*sizeof(int *));
+
+ for (j=0; j < tile_x; j++) {
+ size_t n = (size_t) dpy_y * sizeof(int *);
+ fbd_old32[i][j] = (int *) malloc(n);
+ fbd_new32[i][j] = (int *) malloc(n);
+ }
+ }
+
+ /* temp array for one tile row */
+ fbt_old32 = (int **) malloc(dpy_x * sizeof(int *));
+ fbt_new32 = (int **) malloc(dpy_x * sizeof(int *));
+ for (i=0; i < dpy_x; i++) {
+ size_t n = (size_t) tile_y * sizeof(int *);
+ fbt_old32[i] = (int *) malloc(n);
+ fbt_new32[i] = (int *) malloc(n);
+ }
+
+ } else {
+ vcopyrect = 0;
+ }
+ if (getenv("VCR_DEPTH")) {
+ vcr_depth = atoi(getenv("VCR_DEPTH"));
+ fprintf(stderr, "reset vcr_depth to: %d\n", vcr_depth);
+ } else {
+ fprintf(stderr, "vcr_depth is: %d\n", vcr_depth);
+ }
+}
+
+/*
+ * do_vcr()
+ * Top level routine for the great vertical copyrect hunt.
+ *
+ * It is called shortly after the copy_tiles
+ * calls finish, so the vertical scan line framebuffer pixel
+ * data (old and new) is up to date.
+ *
+ * It only deals with tiles, looking for vertical runs of
+ * changed (or tried) ones. It passes off the actual
+ * fb pixel coincidence checking to vcr_run() and records
+ * wnat vcr_run finds.
+ *
+ * Finally, it determines the copyrects that need to be
+ * sent to libvncserver, sends them, tries to flush, etc.
+ */
+void do_vcr(void) {
+ int x, y, n;
+ int dx, pm, x_cm = 0, y_cm = 0, n_cm = 0;
+ int got, in_run = 0, thd = 0, tt = 0;
+ int cpr_cnt = 0, suggested_disp;
+ int tile_tot = 0, tile_vcr = 0;
+ static int vcr_sleep = -1;
+
+ /*
+ * y_run is an array that holds the tile y indexes
+ * for a vertical run of adjacent changed tiles.
+ */
+ int y_run[YMAX];
+
+ /*
+ * some info for each column, x_has_diff[] says the
+ * column has a tile diff or tried tile somewhere
+ *
+ * disps[] records the displacement found by
+ * vcr_run for this column (XXX: more than one?)
+ *
+ */
+ int x_has_diff[WMAX], disps[WMAX];
+
+ /* we store the found copyrects here: */
+ copyrect_t cpr[4*WMAX], cr;
+
+
+ /* zero our arrays. */
+ for (x=0; x < ntiles_x; x++) {
+ x_has_diff[x] = 0;
+ disps[x] = 0;
+ }
+
+ /*
+ * Try to find the "center of mass" of the region of changed
+ * tiles. Makes the most sense if the changed tiles are
+ * limited to one window (or subregion of a window). Think
+ * of a scroll. We are trying to find the middle of the
+ * changed region and then work our way out from there.
+ *
+ * The thought is we have a better chance of discovering
+ * the "true" vertical displacement if we start in the middle
+ * rather than at the edges. Even if there is clutter
+ * around the scrolled region, this could still get us into
+ * the interior of it.
+ */
+ for (x=0; x < ntiles_x; x++) {
+ for (y=0; y < ntiles_y; y++) {
+ n = x + y * ntiles_x;
+ if (tile_has_diff[n] || tile_tried[n]) {
+ /*
+ * note that this column has a diff,
+ * and accumulate the cm stuff.
+ */
+ x_has_diff[x]++;
+ x_cm += x;
+ y_cm += y;
+ n_cm++;
+ }
+ }
+ }
+
+ if (! n_cm) {
+ /* no changed or tried tiles. */
+ return;
+ }
+
+ /*
+ * Compute center of mass. These are tile indexes, not
+ * pixel indexes, btw.
+ *
+ * We currently only use x_cm the "center of mass" in the
+ * horizontal direction. We compute y_cm but don't use it yet
+ */
+ x_cm = x_cm / n_cm;
+ y_cm = y_cm / n_cm;
+
+ fprintf(stderr, "\ndo_vcr() x_cm: %d y_cm: %d\n", x_cm, y_cm);
+
+ /* work our way outward from x_cm, dx is the displacement */
+ for (dx=0; dx <= ntiles_x; dx++) {
+
+ /* we go +/- (plus or minus) dx */
+ for (pm=0; pm <= 1; pm++) {
+ int x2, dx2, dx2_best;
+
+ if (dx == 0 && pm == 1) {
+ /* just do dx = 0 once. */
+ continue;
+ }
+
+ /* tile x index: */
+ x = x_cm + (1 - 2*pm) * dx;
+
+ if (x < 0 || x >= ntiles_x) {
+ /* out of range... */
+ continue;
+ }
+
+ /*
+ * Loop over previously tried columns of tiles looking for
+ * a preferred y-displacement. This will be used to speed
+ * up the search (later columns will aim for the same
+ * vertical translation... keep thinking of a scroll.)
+ */
+ suggested_disp = 0;
+ dx2_best = -1;
+ for (x2=0; x2 < ntiles_x; x2++) {
+ if (! disps[x2]) {
+ /*
+ * column with nothing found or
+ * not yet examined.
+ */
+ continue;
+ }
+
+ dx2 = x - x2;
+ if (dx2 < 0) {
+ dx2 = -dx2;
+ }
+
+ if (dx2_best == -1 || dx2 < dx2_best) {
+ suggested_disp = disps[x2];
+ dx2_best = dx2;
+ }
+ }
+
+ /*
+ * Now loop down thru the column looking for
+ * changed/tried tiles that are adjacent (along y).
+ * A set of these will be called a "run".
+ */
+ got = 0;
+ in_run = 0;
+ thd = 0;
+ tt = 0;
+ for (y=0; y <= ntiles_y; y++) {
+ int changed = 0, end = 0;
+ n = x + y * ntiles_x;
+
+ if (y == ntiles_y) {
+ end = 1;
+ } else if (tile_has_diff[n] || tile_tried[n]) {
+ changed = 1;
+ tile_tot++;
+ }
+
+ if (changed) {
+ got++;
+ if (tile_has_diff[n]) {
+ thd++;
+ }
+ if (tile_tried[n]) {
+ tt++;
+ }
+ if (! in_run) {
+ /* start of a run */
+ in_run = 1;
+ } else {
+ /* continuation of a run */
+ in_run++;
+ }
+ /* store the y tile number */
+ y_run[in_run - 1] = y;
+ } else {
+ /* either tile w/o diff or special end case */
+ if (! in_run) {
+ continue;
+ }
+ /* this could be the end of a run */
+ if (thd <= tt/10) {
+ /* not enough have real differences */
+ ;
+ } else if (vcr_run(y_run, x, in_run, &cr,
+ suggested_disp)) {
+ /*
+ * otherwise we called vcr_run
+ * to analyse the run. And it
+ * found one. Record it.
+ */
+ cpr[cpr_cnt].x0 = cr.x0;
+ cpr[cpr_cnt].y0 = cr.y0;
+ cpr[cpr_cnt].x1 = cr.x1;
+ cpr[cpr_cnt].y1 = cr.y1;
+ cpr[cpr_cnt].del = cr.del;
+ cpr_cnt++;
+ disps[x] = cr.del;
+
+ tile_vcr += (cr.y1 - cr.y0)/tile_y;
+ }
+
+ if(got > 3) fprintf(stderr,
+ " do_vcr: run: x: %d pm=%d dx=%d got=%d thd=%d tt=%d in_run=%d\n",
+ x, pm, dx, got, thd, tt, in_run);
+
+ /* get ready for a new run */
+ got = 0;
+ in_run = 0;
+ thd = 0;
+ tt = 0;
+ }
+ }
+ }
+ }
+
+ if (tile_vcr) fprintf(stderr, " do_vcr: tile_vcr/tile_tot: %d/%d\n", tile_vcr, tile_tot);
+
+ if (cpr_cnt) {
+ /* we got some copyrects! */
+
+ int i, j, ndel, del_shift[100], del_cnt[100];
+ int willdo = 0, min_cnt = 4;
+ int x, y, n;
+ sraRegionPtr tmp_region, mod_region;
+
+ /*
+ * There there is too much clutter from other tiles w/o
+ * a vcr, bail out to try to avoid painting errors.
+ */
+ if (tile_vcr < 0.5 * tile_tot) {
+ fprintf(stderr, "bad tile_vcr SNR.\n");
+ return;
+ }
+
+ /*
+ * First tally and do some bookkeepping regarding the
+ * different y-displacements. Hopefully most of the
+ * time there will be just one displacement.
+ *
+ * One has to take some care... if we send libvncserver
+ * different displacements, it may treat some of them
+ * as modifiedRegions instead of copyRegions.
+ */
+ ndel = 0;
+ for (i=0; i<cpr_cnt; i++) {
+ int got = 0;
+ int d = cpr[i].del;
+ for (j=0; j < ndel; j++) {
+ if (del_shift[j] == d) {
+ /*
+ * a duplicate with the same del
+ * record it.
+ */
+ del_cnt[j]++;
+
+ if (del_cnt[j] >= min_cnt) {
+ /* we know we have least one */
+ willdo = 1;
+ }
+ got = 1;
+ }
+ }
+ if (! got) {
+ /* no dup, so set it */
+ del_cnt[ndel] = 1;
+ del_shift[ndel++] = d;
+ }
+ }
+ fprintf(stderr, "\n");
+ if (! willdo) {
+ fprintf(stderr, "no willdo, return\n");
+ return;
+ }
+
+ /* now use willdo to count number of different dels */
+ willdo = 0;
+ for (j=0; j < ndel; j++) {
+ int d = del_shift[j];
+ fprintf(stderr, "del: %d/%d del_cnt: %d\n",
+ d, ndel, del_cnt[j]);
+ if (del_cnt[j] >= min_cnt) {
+ willdo++;
+ }
+ }
+ fprintf(stderr, "willdo number of dels: %d\n", willdo);
+
+ /*
+ * We noted above that we will do at least one copyrect.
+ * So we prepare a region of all of the changed/tried
+ * tiles that we can subtract the copyRegion from, etc.
+ */
+ mod_region = (sraRegionPtr) sraRgnCreate();
+ for (x=0; x < ntiles_x; x++) {
+ for (y=0; y < ntiles_y; y++) {
+ n = x + y * ntiles_x;
+ if (! tile_has_diff[n] && ! tile_tried[n]) {
+ continue;
+ }
+ /* XXX optimize this somehow? */
+ tmp_region = (sraRegionPtr)
+ sraRgnCreateRect(x * tile_x, y * tile_x,
+ (x+1) * tile_x, (y+1) * tile_y);
+
+ sraRgnOr(mod_region, tmp_region);
+ sraRgnDestroy(tmp_region);
+ }
+ }
+ fprintf(stderr, "\n");
+
+ /*
+ * vcr_change_region will be the region corresponding to
+ * all of our discovered copyrects.
+ */
+ if (vcr_change_region) {
+ sraRgnDestroy(vcr_change_region);
+ }
+ vcr_change_region = (sraRegionPtr) sraRgnCreate();
+
+ if (vcr_mod_region) {
+ sraRgnDestroy(vcr_mod_region);
+ }
+ vcr_mod_region = NULL;
+
+ /*
+ * Now we go over the different del's (hopefully just
+ * one) and send the copyrects with the same del out to
+ * libvncserver and try to XXX
+ */
+
+ for (j=0; j < ndel; j++) {
+ int d = del_shift[j];
+ if (del_cnt[j] < min_cnt) {
+ /* too short */
+ continue;
+ }
+ for (i=0; i<cpr_cnt; i++) {
+ if (cpr[i].del != d) {
+ continue;
+ }
+ tmp_region = (sraRegionPtr)
+ sraRgnCreateRect(cpr[i].x0,
+ cpr[i].y0 + cpr[i].del, cpr[i].x1,
+ cpr[i].y1 + cpr[i].del);
+ /*
+ * subtract this from our modifiedRegion
+ * (see below).
+ */
+ sraRgnSubtract(mod_region, tmp_region);
+ sraRgnOr(vcr_change_region, tmp_region);
+ sraRgnDestroy(tmp_region);
+
+ /* tell libvncserver about the copyrect. */
+ vcr_send(cpr[i].x0, cpr[i].y0, cpr[i].x1,
+ cpr[i].y1, cpr[i].del);
+
+ fprintf(stderr, "del: %d x0=%3d y0=%3d x1=%3d y1=%3d\n",
+ cpr[i].del, cpr[i].x0, cpr[i].y0, cpr[i].x1, cpr[i].y1);
+
+ }
+ if (willdo > 1) {
+ /* if more than 1 delta, must flush each one */
+ vcr_flush(0);
+ }
+ }
+
+ /*
+ * tell libvncserver to now flush the modified region
+ * outside of the copyrect region.
+ */
+ fprintf(stderr, "rfbMarkRegionAsModified\n");
+ rfbMarkRegionAsModified(screen, mod_region);
+ fprintf(stderr, "vcr_flush for mod_region\n");
+
+ vcr_flush(1);
+ vcr_mod_region = (sraRegionPtr) sraRgnCreateRgn(mod_region);
+
+ sraRgnDestroy(mod_region);
+ rfbPE(screen, 0);
+
+ /* hack to sleep */
+ if (vcr_sleep < 0 || vcr_sleep == 1) {
+ if (getenv("VCR_SLEEP") != NULL) {
+ vcr_sleep = 1;
+ fprintf(stderr, "sleep...\n"); sleep(atoi(getenv("VCR_SLEEP")));
+ } else {
+ vcr_sleep = 0;
+ }
+ }
+ fprintf(stderr, "done...\n");
+ }
+}
+#endif /* VCR_HACK */
+/* ######################################################################## */
+