diff options
author | runge <runge> | 2005-01-24 03:52:47 +0000 |
---|---|---|
committer | runge <runge> | 2005-01-24 03:52:47 +0000 |
commit | d2a0e40e1b9bf6e76d230e96d1ccfe912998a720 (patch) | |
tree | 6e0e67eec738de58bf3d26e278c91c1b55c4f2ab /x11vnc/x11vnc.c | |
parent | 6fb3752bf23af0d2fc683986374e716a3eb88bb1 (diff) | |
download | libtdevnc-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.c | 2141 |
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 */ +/* ######################################################################## */ + |