diff options
author | Christian Beier <dontmind@freeshell.org> | 2014-09-03 20:54:39 +0200 |
---|---|---|
committer | Christian Beier <dontmind@freeshell.org> | 2014-09-03 20:54:39 +0200 |
commit | 498d222976975f53dea885cfe43ef0f805abd412 (patch) | |
tree | bac684fbde46fdc3e4cc3817616816b71bb67f9f /x11vnc/scan.c | |
parent | 8d2db0486dcc167f1b02d4454ebf4624ce03e1de (diff) | |
download | libtdevnc-498d222976975f53dea885cfe43ef0f805abd412.tar.gz libtdevnc-498d222976975f53dea885cfe43ef0f805abd412.zip |
Remove x11vnc subdir.
The new x11vnc repo is at https://github.com/LibVNC/x11vnc.
Diffstat (limited to 'x11vnc/scan.c')
-rw-r--r-- | x11vnc/scan.c | 3687 |
1 files changed, 0 insertions, 3687 deletions
diff --git a/x11vnc/scan.c b/x11vnc/scan.c deleted file mode 100644 index 1fb7883..0000000 --- a/x11vnc/scan.c +++ /dev/null @@ -1,3687 +0,0 @@ -/* - Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com> - All rights reserved. - -This file is part of x11vnc. - -x11vnc is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -x11vnc is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with x11vnc; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA -or see <http://www.gnu.org/licenses/>. - -In addition, as a special exception, Karl J. Runge -gives permission to link the code of its release of x11vnc with the -OpenSSL project's "OpenSSL" library (or with modified versions of it -that use the same license as the "OpenSSL" library), and distribute -the linked executables. You must obey the GNU General Public License -in all respects for all of the code used other than "OpenSSL". If you -modify this file, you may extend this exception to your version of the -file, but you are not obligated to do so. If you do not wish to do -so, delete this exception statement from your version. -*/ - -/* -- scan.c -- */ - -#include "x11vnc.h" -#include "xinerama.h" -#include "xwrappers.h" -#include "xdamage.h" -#include "xrandr.h" -#include "win_utils.h" -#include "8to24.h" -#include "screen.h" -#include "pointer.h" -#include "cleanup.h" -#include "unixpw.h" -#include "screen.h" -#include "macosx.h" -#include "userinput.h" - -/* - * routines for scanning and reading the X11 display for changes, and - * for doing all the tile work (shm, etc). - */ -void initialize_tiles(void); -void free_tiles(void); -void shm_delete(XShmSegmentInfo *shm); -void shm_clean(XShmSegmentInfo *shm, XImage *xim); -void initialize_polling_images(void); -void scale_rect(double factor_x, double factor_y, int blend, int interpolate, int Bpp, - char *src_fb, int src_bytes_per_line, char *dst_fb, int dst_bytes_per_line, - int Nx, int Ny, int nx, int ny, int X1, int Y1, int X2, int Y2, int mark); -void scale_and_mark_rect(int X1, int Y1, int X2, int Y2, int mark); -void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force); -int copy_screen(void); -int copy_snap(void); -void nap_sleep(int ms, int split); -void set_offset(void); -int scan_for_updates(int count_only); -void rotate_curs(char *dst_0, char *src_0, int Dx, int Dy, int Bpp); -void rotate_coords(int x, int y, int *xo, int *yo, int dxi, int dyi); -void rotate_coords_inverse(int x, int y, int *xo, int *yo, int dxi, int dyi); - -static void set_fs_factor(int max); -static char *flip_ximage_byte_order(XImage *xim); -static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, - char *name); -static void create_tile_hint(int x, int y, int tw, int th, hint_t *hint); -static void extend_tile_hint(int x, int y, int tw, int th, hint_t *hint); -static void save_hint(hint_t hint, int loc); -static void hint_updates(void); -static void mark_hint(hint_t hint); -static int copy_tiles(int tx, int ty, int nt); -static int copy_all_tiles(void); -static int copy_all_tile_runs(void); -static int copy_tiles_backward_pass(void); -static int copy_tiles_additional_pass(void); -static int gap_try(int x, int y, int *run, int *saw, int along_x); -static int fill_tile_gaps(void); -static int island_try(int x, int y, int u, int v, int *run); -static int grow_islands(void); -static void blackout_regions(void); -static void nap_set(int tile_cnt); -static void nap_check(int tile_cnt); -static void ping_clients(int tile_cnt); -static int blackout_line_skip(int n, int x, int y, int rescan, - int *tile_count); -static int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src, - int w, int pixelsize); -static int scan_display(int ystart, int rescan); - - -/* array to hold the hints: */ -static hint_t *hint_list; - -/* nap state */ -int nap_ok = 0; -static int nap_diff_count = 0; - -static int scan_count = 0; /* indicates which scan pattern we are on */ -static int scan_in_progress = 0; - - -typedef struct tile_change_region { - /* start and end lines, along y, of the changed area inside a tile. */ - unsigned short first_line, last_line; - short first_x, last_x; - /* info about differences along edges. */ - unsigned short left_diff, right_diff; - unsigned short top_diff, bot_diff; -} region_t; - -/* array to hold the tiles region_t-s. */ -static region_t *tile_region; - - - - -/* - * setup tile numbers and allocate the tile and hint arrays: - */ -void initialize_tiles(void) { - - ntiles_x = (dpy_x - 1)/tile_x + 1; - ntiles_y = (dpy_y - 1)/tile_y + 1; - ntiles = ntiles_x * ntiles_y; - - tile_has_diff = (unsigned char *) - calloc((size_t) (ntiles * sizeof(unsigned char)), 1); - tile_has_xdamage_diff = (unsigned char *) - calloc((size_t) (ntiles * sizeof(unsigned char)), 1); - tile_row_has_xdamage_diff = (unsigned char *) - calloc((size_t) (ntiles_y * sizeof(unsigned char)), 1); - tile_tried = (unsigned char *) - calloc((size_t) (ntiles * sizeof(unsigned char)), 1); - tile_copied = (unsigned char *) - calloc((size_t) (ntiles * sizeof(unsigned char)), 1); - tile_blackout = (tile_blackout_t *) - calloc((size_t) (ntiles * sizeof(tile_blackout_t)), 1); - tile_region = (region_t *) calloc((size_t) (ntiles * sizeof(region_t)), 1); - - tile_row = (XImage **) - calloc((size_t) ((ntiles_x + 1) * sizeof(XImage *)), 1); - tile_row_shm = (XShmSegmentInfo *) - calloc((size_t) ((ntiles_x + 1) * sizeof(XShmSegmentInfo)), 1); - - /* there will never be more hints than tiles: */ - hint_list = (hint_t *) calloc((size_t) (ntiles * sizeof(hint_t)), 1); -} - -void free_tiles(void) { - if (tile_has_diff) { - free(tile_has_diff); - tile_has_diff = NULL; - } - if (tile_has_xdamage_diff) { - free(tile_has_xdamage_diff); - tile_has_xdamage_diff = NULL; - } - if (tile_row_has_xdamage_diff) { - free(tile_row_has_xdamage_diff); - tile_row_has_xdamage_diff = NULL; - } - if (tile_tried) { - free(tile_tried); - tile_tried = NULL; - } - if (tile_copied) { - free(tile_copied); - tile_copied = NULL; - } - if (tile_blackout) { - free(tile_blackout); - tile_blackout = NULL; - } - if (tile_region) { - free(tile_region); - tile_region = NULL; - } - if (tile_row) { - free(tile_row); - tile_row = NULL; - } - if (tile_row_shm) { - free(tile_row_shm); - tile_row_shm = NULL; - } - if (hint_list) { - free(hint_list); - hint_list = NULL; - } -} - -/* - * silly function to factor dpy_y until fullscreen shm is not bigger than max. - * should always work unless dpy_y is a large prime or something... under - * failure fs_factor remains 0 and no fullscreen updates will be tried. - */ -static int fs_factor = 0; - -static void set_fs_factor(int max) { - int f, fac = 1, n = dpy_y; - - fs_factor = 0; - if ((bpp/8) * dpy_x * dpy_y <= max) { - fs_factor = 1; - return; - } - for (f=2; f <= 101; f++) { - while (n % f == 0) { - n = n / f; - fac = fac * f; - if ( (bpp/8) * dpy_x * (dpy_y/fac) <= max ) { - fs_factor = fac; - return; - } - } - } -} - -static char *flip_ximage_byte_order(XImage *xim) { - char *order; - if (xim->byte_order == LSBFirst) { - order = "MSBFirst"; - xim->byte_order = MSBFirst; - xim->bitmap_bit_order = MSBFirst; - } else { - order = "LSBFirst"; - xim->byte_order = LSBFirst; - xim->bitmap_bit_order = LSBFirst; - } - return order; -} - -/* - * set up an XShm image, or if not using shm just create the XImage. - */ -static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, - char *name) { - - XImage *xim; - static int reported_flip = 0; - int db = 0; - - shm->shmid = -1; - shm->shmaddr = (char *) -1; - *ximg_ptr = NULL; - - if (nofb) { - return 1; - } - - X_LOCK; - - if (! using_shm || xform24to32 || raw_fb) { - /* we only need the XImage created */ - xim = XCreateImage_wr(dpy, default_visual, depth, ZPixmap, - 0, NULL, w, h, raw_fb ? 32 : BitmapPad(dpy), 0); - - X_UNLOCK; - - if (xim == NULL) { - rfbErr("XCreateImage(%s) failed.\n", name); - if (quiet) { - fprintf(stderr, "XCreateImage(%s) failed.\n", - name); - } - return 0; - } - if (db) fprintf(stderr, "shm_create simple %d %d\t%p %s\n", w, h, (void *)xim, name); - xim->data = (char *) malloc(xim->bytes_per_line * xim->height); - if (xim->data == NULL) { - rfbErr("XCreateImage(%s) data malloc failed.\n", name); - if (quiet) { - fprintf(stderr, "XCreateImage(%s) data malloc" - " failed.\n", name); - } - return 0; - } - if (flip_byte_order) { - char *order = flip_ximage_byte_order(xim); - if (! reported_flip && ! quiet) { - rfbLog("Changing XImage byte order" - " to %s\n", order); - reported_flip = 1; - } - } - - *ximg_ptr = xim; - return 1; - } - - if (! dpy) { - X_UNLOCK; - return 0; - } - - xim = XShmCreateImage_wr(dpy, default_visual, depth, ZPixmap, NULL, - shm, w, h); - - if (xim == NULL) { - rfbErr("XShmCreateImage(%s) failed.\n", name); - if (quiet) { - fprintf(stderr, "XShmCreateImage(%s) failed.\n", name); - } - X_UNLOCK; - return 0; - } - - *ximg_ptr = xim; - -#if LIBVNCSERVER_HAVE_XSHM - shm->shmid = shmget(IPC_PRIVATE, - xim->bytes_per_line * xim->height, IPC_CREAT | 0777); - - if (shm->shmid == -1) { - rfbErr("shmget(%s) failed.\n", name); - rfbLogPerror("shmget"); - - XDestroyImage(xim); - *ximg_ptr = NULL; - - X_UNLOCK; - return 0; - } - - shm->shmaddr = xim->data = (char *) shmat(shm->shmid, 0, 0); - - if (shm->shmaddr == (char *)-1) { - rfbErr("shmat(%s) failed.\n", name); - rfbLogPerror("shmat"); - - XDestroyImage(xim); - *ximg_ptr = NULL; - - shmctl(shm->shmid, IPC_RMID, 0); - shm->shmid = -1; - - X_UNLOCK; - return 0; - } - - shm->readOnly = False; - - if (! XShmAttach_wr(dpy, shm)) { - rfbErr("XShmAttach(%s) failed.\n", name); - XDestroyImage(xim); - *ximg_ptr = NULL; - - shmdt(shm->shmaddr); - shm->shmaddr = (char *) -1; - - shmctl(shm->shmid, IPC_RMID, 0); - shm->shmid = -1; - - X_UNLOCK; - return 0; - } -#endif - - X_UNLOCK; - return 1; -} - -void shm_delete(XShmSegmentInfo *shm) { -#if LIBVNCSERVER_HAVE_XSHM - if (getenv("X11VNC_SHM_DEBUG")) fprintf(stderr, "shm_delete: %p\n", (void *) shm); - if (shm != NULL && shm->shmaddr != (char *) -1) { - shmdt(shm->shmaddr); - } - if (shm != NULL && shm->shmid != -1) { - shmctl(shm->shmid, IPC_RMID, 0); - } - if (shm != NULL) { - shm->shmaddr = (char *) -1; - shm->shmid = -1; - } -#else - if (!shm) {} -#endif -} - -void shm_clean(XShmSegmentInfo *shm, XImage *xim) { - int db = 0; - - if (db) fprintf(stderr, "shm_clean: called: %p\n", (void *)xim); - X_LOCK; -#if LIBVNCSERVER_HAVE_XSHM - if (shm != NULL && shm->shmid != -1 && dpy) { - if (db) fprintf(stderr, "shm_clean: XShmDetach_wr\n"); - XShmDetach_wr(dpy, shm); - } -#endif - if (xim != NULL) { - if (! raw_fb_back_to_X) { /* raw_fb hack */ - if (xim->bitmap_unit != -1) { - if (db) fprintf(stderr, "shm_clean: XDestroyImage %p\n", (void *)xim); - XDestroyImage(xim); - } else { - if (xim->data) { - if (db) fprintf(stderr, "shm_clean: free xim->data %p %p\n", (void *)xim, (void *)(xim->data)); - free(xim->data); - xim->data = NULL; - } - } - } - xim = NULL; - } - X_UNLOCK; - - shm_delete(shm); -} - -void initialize_polling_images(void) { - int i, MB = 1024 * 1024; - - /* set all shm areas to "none" before trying to create any */ - scanline_shm.shmid = -1; - scanline_shm.shmaddr = (char *) -1; - scanline = NULL; - fullscreen_shm.shmid = -1; - fullscreen_shm.shmaddr = (char *) -1; - fullscreen = NULL; - snaprect_shm.shmid = -1; - snaprect_shm.shmaddr = (char *) -1; - snaprect = NULL; - for (i=1; i<=ntiles_x; i++) { - tile_row_shm[i].shmid = -1; - tile_row_shm[i].shmaddr = (char *) -1; - tile_row[i] = NULL; - } - - /* the scanline (e.g. 1280x1) shared memory area image: */ - - if (! shm_create(&scanline_shm, &scanline, dpy_x, 1, "scanline")) { - clean_up_exit(1); - } - - /* - * the fullscreen (e.g. 1280x1024/fs_factor) shared memory area image: - * (we cut down the size of the shm area to try avoid and shm segment - * limits, e.g. the default 1MB on Solaris) - */ - if (UT.sysname && strstr(UT.sysname, "Linux")) { - set_fs_factor(10 * MB); - } else { - set_fs_factor(1 * MB); - } - if (fs_frac >= 1.0) { - fs_frac = 1.1; - fs_factor = 0; - } - if (! fs_factor) { - rfbLog("warning: fullscreen updates are disabled.\n"); - } else { - if (! shm_create(&fullscreen_shm, &fullscreen, dpy_x, - dpy_y/fs_factor, "fullscreen")) { - clean_up_exit(1); - } - } - if (use_snapfb) { - if (! fs_factor) { - rfbLog("warning: disabling -snapfb mode.\n"); - use_snapfb = 0; - } else if (! shm_create(&snaprect_shm, &snaprect, dpy_x, - dpy_y/fs_factor, "snaprect")) { - clean_up_exit(1); - } - } - - /* - * for copy_tiles we need a lot of shared memory areas, one for - * each possible run length of changed tiles. 32 for 1024x768 - * and 40 for 1280x1024, etc. - */ - - tile_shm_count = 0; - for (i=1; i<=ntiles_x; i++) { - if (! shm_create(&tile_row_shm[i], &tile_row[i], tile_x * i, - tile_y, "tile_row")) { - if (i == 1) { - clean_up_exit(1); - } - rfbLog("shm: Error creating shared memory tile-row for" - " len=%d,\n", i); - rfbLog("shm: reverting to -onetile mode. If this" - " problem persists\n"); - rfbLog("shm: try using the -onetile or -noshm options" - " to limit\n"); - rfbLog("shm: shared memory usage, or run ipcrm(1)" - " to manually\n"); - rfbLog("shm: delete unattached shm segments.\n"); - single_copytile_count = i; - single_copytile = 1; - } - tile_shm_count++; - if (single_copytile && i >= 1) { - /* only need 1x1 tiles */ - break; - } - } - if (verbose) { - if (using_shm && ! xform24to32) { - rfbLog("created %d tile_row shm polling images.\n", - tile_shm_count); - } else { - rfbLog("created %d tile_row polling images.\n", - tile_shm_count); - } - } -} - -/* - * A hint is a rectangular region built from 1 or more adjacent tiles - * glued together. Ultimately, this information in a single hint is sent - * to libvncserver rather than sending each tile separately. - */ -static void create_tile_hint(int x, int y, int tw, int th, hint_t *hint) { - int w = dpy_x - x; - int h = dpy_y - y; - - if (w > tw) { - w = tw; - } - if (h > th) { - h = th; - } - - hint->x = x; - hint->y = y; - hint->w = w; - hint->h = h; -} - -static void extend_tile_hint(int x, int y, int tw, int th, hint_t *hint) { - int w = dpy_x - x; - int h = dpy_y - y; - - if (w > tw) { - w = tw; - } - if (h > th) { - h = th; - } - - if (hint->x > x) { /* extend to the left */ - hint->w += hint->x - x; - hint->x = x; - } - if (hint->y > y) { /* extend upward */ - hint->h += hint->y - y; - hint->y = y; - } - - if (hint->x + hint->w < x + w) { /* extend to the right */ - hint->w = x + w - hint->x; - } - if (hint->y + hint->h < y + h) { /* extend downward */ - hint->h = y + h - hint->y; - } -} - -static void save_hint(hint_t hint, int loc) { - /* simply copy it to the global array for later use. */ - hint_list[loc].x = hint.x; - hint_list[loc].y = hint.y; - hint_list[loc].w = hint.w; - hint_list[loc].h = hint.h; -} - -/* - * Glue together horizontal "runs" of adjacent changed tiles into one big - * rectangle change "hint" to be passed to the vnc machinery. - */ -static void hint_updates(void) { - hint_t hint; - int x, y, i, n, ty, th, tx, tw; - int hint_count = 0, in_run = 0; - - hint.x = hint.y = hint.w = hint.h = 0; - - for (y=0; y < ntiles_y; y++) { - for (x=0; x < ntiles_x; x++) { - n = x + y * ntiles_x; - - if (tile_has_diff[n]) { - ty = tile_region[n].first_line; - th = tile_region[n].last_line - ty + 1; - - tx = tile_region[n].first_x; - tw = tile_region[n].last_x - tx + 1; - if (tx < 0) { - tx = 0; - tw = tile_x; - } - - if (! in_run) { - create_tile_hint( x * tile_x + tx, - y * tile_y + ty, tw, th, &hint); - in_run = 1; - } else { - extend_tile_hint( x * tile_x + tx, - y * tile_y + ty, tw, th, &hint); - } - } else { - if (in_run) { - /* end of a row run of altered tiles: */ - save_hint(hint, hint_count++); - in_run = 0; - } - } - } - if (in_run) { /* save the last row run */ - save_hint(hint, hint_count++); - in_run = 0; - } - } - - for (i=0; i < hint_count; i++) { - /* pass update info to vnc: */ - mark_hint(hint_list[i]); - } -} - -/* - * kludge, simple ceil+floor for non-negative doubles: - */ -#define CEIL(x) ( (double) ((int) (x)) == (x) ? \ - (double) ((int) (x)) : (double) ((int) (x) + 1) ) -#define FLOOR(x) ( (double) ((int) (x)) ) - -/* - * Scaling: - * - * For shrinking, a destination (scaled) pixel will correspond to more - * than one source (i.e. main fb) pixel. Think of an x-y plane made with - * graph paper. Each unit square in the graph paper (i.e. collection of - * points (x,y) such that N < x < N+1 and M < y < M+1, N and M integers) - * corresponds to one pixel in the unscaled fb. There is a solid - * color filling the inside of such a square. A scaled pixel has width - * 1/scale_fac, e.g. for "-scale 3/4" the width of the scaled pixel - * is 1.333. The area of this scaled pixel is 1.333 * 1.333 (so it - * obviously overlaps more than one source pixel, each which have area 1). - * - * We take the weight an unscaled pixel (source) contributes to a - * scaled pixel (destination) as simply proportional to the overlap area - * between the two pixels. One can then think of the value of the scaled - * pixel as an integral over the portion of the graph paper it covers. - * The thing being integrated is the color value of the unscaled source. - * That color value is constant over a graph paper square (source pixel), - * and changes discontinuously from one unit square to the next. - * - -Here is an example for -scale 3/4, the solid lines are the source pixels -(graph paper unit squares), while the dotted lines denote the scaled -pixels (destination pixels): - - 0 1 4/3 2 8/3 3 4=12/3 - |---------|--.------|------.--|---------|. - | | . | . | |. - | A | . B | . | |. - | | . | . | |. - | | . | . | |. - 1 |---------|--.------|------.--|---------|. - 4/3|.........|.........|.........|.........|. - | | . | . | |. - | C | . D | . | |. - | | . | . | |. - 2 |---------|--.------|------.--|---------|. - | | . | . | |. - | | . | . | |. - 8/3|.........|.........|.........|.........|. - | | . | . | |. - 3 |---------|--.------|------.--|---------|. - -So we see the first scaled pixel (0 < x < 4/3 and 0 < y < 4/3) mostly -overlaps with unscaled source pixel "A". The integration (averaging) -weights for this scaled pixel are: - - A 1 - B 1/3 - C 1/3 - D 1/9 - - * - * The Red, Green, and Blue color values must be averaged over separately - * otherwise you can get a complete mess (except in solid regions), - * because high order bits are averaged differently from the low order bits. - * - * So the algorithm is roughly: - * - * - Given as input a rectangle in the unscaled source fb with changes, - * find the rectangle of pixels this affects in the scaled destination fb. - * - * - For each of the affected scaled (dest) pixels, determine all of the - * unscaled (source) pixels it overlaps with. - * - * - Average those unscaled source values together, weighted by the area - * overlap with the destination pixel. Average R, G, B separately. - * - * - Take this average value and convert to a valid pixel value if - * necessary (e.g. rounding, shifting), and then insert it into the - * destination framebuffer as the pixel value. - * - * - On to the next destination pixel... - * - * ======================================================================== - * - * For expanding, e.g. -scale 1.1 (which we don't think people will do - * very often... or at least so we hope, the framebuffer can become huge) - * the situation is reversed and the destination pixel is smaller than a - * "graph paper" unit square (source pixel). Some destination pixels - * will be completely within a single unscaled source pixel. - * - * What we do here is a simple 4 point interpolation scheme: - * - * Let P00 be the source pixel closest to the destination pixel but with - * x and y values less than or equal to those of the destination pixel. - * (for simplicity, think of the upper left corner of a pixel defining the - * x,y location of the pixel, the center would work just as well). So it - * is the source pixel immediately to the upper left of the destination - * pixel. Let P10 be the source pixel one to the right of P00. Let P01 - * be one down from P00. And let P11 be one down and one to the right - * of P00. They form a 2x2 square we will interpolate inside of. - * - * Let V00, V10, V01, and V11 be the color values of those 4 source - * pixels. Let dx be the displacement along x the destination pixel is - * from P00. Note: 0 <= dx < 1 by definition of P00. Similarly let - * dy be the displacement along y. The weighted average for the - * interpolation is: - * - * V_ave = V00 * (1 - dx) * (1 - dy) - * + V10 * dx * (1 - dy) - * + V01 * (1 - dx) * dy - * + V11 * dx * dy - * - * Note that the weights (1-dx)*(1-dy) + dx*(1-dy) + (1-dx)*dy + dx*dy - * automatically add up to 1. It is also nice that all the weights are - * positive (unsigned char stays unsigned char). The above formula can - * be motivated by doing two 1D interpolations along x: - * - * VA = V00 * (1 - dx) + V10 * dx - * VB = V01 * (1 - dx) + V11 * dx - * - * and then interpolating VA and VB along y: - * - * V_ave = VA * (1 - dy) + VB * dy - * - * VA - * v |<-dx->| - * -- V00 ------ V10 - * dy | | - * -- | o...|... "o" denotes the position of the desired - * ^ | . | . destination pixel relative to the P00 - * | . | . source pixel. - * V10 ----.- V11 . - * ........ - * | - * VB - * - * - * Of course R, G, B averages are done separately as in the shrinking - * case. This gives reasonable results, and the implementation for - * shrinking can simply be used with different choices for weights for - * the loop over the 4 pixels. - */ - -void scale_rect(double factor_x, double factor_y, int blend, int interpolate, int Bpp, - char *src_fb, int src_bytes_per_line, char *dst_fb, int dst_bytes_per_line, - int Nx, int Ny, int nx, int ny, int X1, int Y1, int X2, int Y2, int mark) { -/* - * Notation: - * "i" an x pixel index in the destination (scaled) framebuffer - * "j" a y pixel index in the destination (scaled) framebuffer - * "I" an x pixel index in the source (un-scaled, i.e. main) framebuffer - * "J" a y pixel index in the source (un-scaled, i.e. main) framebuffer - * - * Similarly for nx, ny, Nx, Ny, etc. Lowercase: dest, Uppercase: source. - */ - int i, j, i1, i2, j1, j2; /* indices for scaled fb (dest) */ - int I, J, I1, I2, J1, J2; /* indices for main fb (source) */ - - double w, wx, wy, wtot; /* pixel weights */ - - double x1, y1, x2, y2; /* x-y coords for destination pixels edges */ - double dx, dy; /* size of destination pixel */ - double ddx=0, ddy=0; /* for interpolation expansion */ - - char *src, *dest; /* pointers to the two framebuffers */ - - - unsigned short us = 0; - unsigned char uc = 0; - unsigned int ui = 0; - - int use_noblend_shortcut = 1; - int shrink; /* whether shrinking or expanding */ - static int constant_weights = -1, mag_int = -1; - static int last_Nx = -1, last_Ny = -1, cnt = 0; - static double last_factor = -1.0; - int b, k; - double pixave[4]; /* for averaging pixel values */ - - if (factor_x <= 1.0 && factor_y <= 1.0) { - shrink = 1; - } else { - shrink = 0; - } - - /* - * N.B. width and height (real numbers) of a scaled pixel. - * both are > 1 (e.g. 1.333 for -scale 3/4) - * they should also be equal but we don't assume it. - * - * This new way is probably the best we can do, take the inverse - * of the scaling factor to double precision. - */ - dx = 1.0/factor_x; - dy = 1.0/factor_y; - - /* - * There is some speedup if the pixel weights are constant, so - * let's special case these. - * - * If scale = 1/n and n divides Nx and Ny, the pixel weights - * are constant (e.g. 1/2 => equal on 2x2 square). - */ - if (factor_x != last_factor || Nx != last_Nx || Ny != last_Ny) { - constant_weights = -1; - mag_int = -1; - last_Nx = Nx; - last_Ny = Ny; - last_factor = factor_x; - } - if (constant_weights < 0 && factor_x != factor_y) { - constant_weights = 0; - mag_int = 0; - - } else if (constant_weights < 0) { - int n = 0; - - constant_weights = 0; - mag_int = 0; - - for (i = 2; i<=128; i++) { - double test = ((double) 1)/ i; - double diff, eps = 1.0e-7; - diff = factor_x - test; - if (-eps < diff && diff < eps) { - n = i; - break; - } - } - if (! blend || ! shrink || interpolate) { - ; - } else if (n != 0) { - if (Nx % n == 0 && Ny % n == 0) { - static int didmsg = 0; - if (mark && ! didmsg) { - didmsg = 1; - rfbLog("scale_and_mark_rect: using " - "constant pixel weight speedup " - "for 1/%d\n", n); - } - constant_weights = 1; - } - } - - n = 0; - for (i = 2; i<=32; i++) { - double test = (double) i; - double diff, eps = 1.0e-7; - diff = factor_x - test; - if (-eps < diff && diff < eps) { - n = i; - break; - } - } - if (! blend && factor_x > 1.0 && n) { - mag_int = n; - } - } - - if (mark && factor_x > 1.0 && blend) { - /* - * kludge: correct for interpolating blurring leaking - * up or left 1 destination pixel. - */ - if (X1 > 0) X1--; - if (Y1 > 0) Y1--; - } - - /* - * find the extent of the change the input rectangle induces in - * the scaled framebuffer. - */ - - /* Left edges: find largest i such that i * dx <= X1 */ - i1 = FLOOR(X1/dx); - - /* Right edges: find smallest i such that (i+1) * dx >= X2+1 */ - i2 = CEIL( (X2+1)/dx ) - 1; - - /* To be safe, correct any overflows: */ - i1 = nfix(i1, nx); - i2 = nfix(i2, nx) + 1; /* add 1 to make a rectangle upper boundary */ - - /* Repeat above for y direction: */ - j1 = FLOOR(Y1/dy); - j2 = CEIL( (Y2+1)/dy ) - 1; - - j1 = nfix(j1, ny); - j2 = nfix(j2, ny) + 1; - - /* - * special case integer magnification with no blending. - * vision impaired magnification usage is interested in this case. - */ - if (mark && ! blend && mag_int && Bpp != 3) { - int jmin, jmax, imin, imax; - - /* outer loop over *source* pixels */ - for (J=Y1; J < Y2; J++) { - jmin = J * mag_int; - jmax = jmin + mag_int; - for (I=X1; I < X2; I++) { - /* extract value */ - src = src_fb + J*src_bytes_per_line + I*Bpp; - if (Bpp == 4) { - ui = *((unsigned int *)src); - } else if (Bpp == 2) { - us = *((unsigned short *)src); - } else if (Bpp == 1) { - uc = *((unsigned char *)src); - } - imin = I * mag_int; - imax = imin + mag_int; - /* inner loop over *dest* pixels */ - for (j=jmin; j<jmax; j++) { - dest = dst_fb + j*dst_bytes_per_line + imin*Bpp; - for (i=imin; i<imax; i++) { - if (Bpp == 4) { - *((unsigned int *)dest) = ui; - } else if (Bpp == 2) { - *((unsigned short *)dest) = us; - } else if (Bpp == 1) { - *((unsigned char *)dest) = uc; - } - dest += Bpp; - } - } - } - } - goto markit; - } - - /* set these all to 1.0 to begin with */ - wx = 1.0; - wy = 1.0; - w = 1.0; - - /* - * Loop over destination pixels in scaled fb: - */ - for (j=j1; j<j2; j++) { - y1 = j * dy; /* top edge */ - if (y1 > Ny - 1) { - /* can go over with dy = 1/scale_fac */ - y1 = Ny - 1; - } - y2 = y1 + dy; /* bottom edge */ - - /* Find main fb indices covered by this dest pixel: */ - J1 = (int) FLOOR(y1); - J1 = nfix(J1, Ny); - - if (shrink && ! interpolate) { - J2 = (int) CEIL(y2) - 1; - J2 = nfix(J2, Ny); - } else { - J2 = J1 + 1; /* simple interpolation */ - ddy = y1 - J1; - } - - /* destination char* pointer: */ - dest = dst_fb + j*dst_bytes_per_line + i1*Bpp; - - for (i=i1; i<i2; i++) { - - x1 = i * dx; /* left edge */ - if (x1 > Nx - 1) { - /* can go over with dx = 1/scale_fac */ - x1 = Nx - 1; - } - x2 = x1 + dx; /* right edge */ - - cnt++; - - /* Find main fb indices covered by this dest pixel: */ - I1 = (int) FLOOR(x1); - if (I1 >= Nx) I1 = Nx - 1; - - if (! blend && use_noblend_shortcut) { - /* - * The noblend case involves no weights, - * and 1 pixel, so just copy the value - * directly. - */ - src = src_fb + J1*src_bytes_per_line + I1*Bpp; - if (Bpp == 4) { - *((unsigned int *)dest) - = *((unsigned int *)src); - } else if (Bpp == 2) { - *((unsigned short *)dest) - = *((unsigned short *)src); - } else if (Bpp == 1) { - *(dest) = *(src); - } else if (Bpp == 3) { - /* rare case */ - for (k=0; k<=2; k++) { - *(dest+k) = *(src+k); - } - } - dest += Bpp; - continue; - } - - if (shrink && ! interpolate) { - I2 = (int) CEIL(x2) - 1; - if (I2 >= Nx) I2 = Nx - 1; - } else { - I2 = I1 + 1; /* simple interpolation */ - ddx = x1 - I1; - } - - /* Zero out accumulators for next pixel average: */ - for (b=0; b<4; b++) { - pixave[b] = 0.0; /* for RGB weighted sums */ - } - - /* - * wtot is for accumulating the total weight. - * It should always sum to 1/(scale_fac * scale_fac). - */ - wtot = 0.0; - - /* - * Loop over source pixels covered by this dest pixel. - * - * These "extra" loops over "J" and "I" make - * the cache/cacheline performance unclear. - * For example, will the data brought in from - * src for j, i, and J=0 still be in the cache - * after the J > 0 data have been accessed and - * we are at j, i+1, J=0? The stride in J is - * main_bytes_per_line, and so ~4 KB. - * - * Typical case when shrinking are 2x2 loop, so - * just two lines to worry about. - */ - for (J=J1; J<=J2; J++) { - /* see comments for I, x1, x2, etc. below */ - if (constant_weights) { - ; - } else if (! blend) { - if (J != J1) { - continue; - } - wy = 1.0; - - /* interpolation scheme: */ - } else if (! shrink || interpolate) { - if (J >= Ny) { - continue; - } else if (J == J1) { - wy = 1.0 - ddy; - } else if (J != J1) { - wy = ddy; - } - - /* integration scheme: */ - } else if (J < y1) { - wy = J+1 - y1; - } else if (J+1 > y2) { - wy = y2 - J; - } else { - wy = 1.0; - } - - src = src_fb + J*src_bytes_per_line + I1*Bpp; - - for (I=I1; I<=I2; I++) { - - /* Work out the weight: */ - - if (constant_weights) { - ; - } else if (! blend) { - /* - * Ugh, PseudoColor colormap is - * bad news, to avoid random - * colors just take the first - * pixel. Or user may have - * specified :nb to fraction. - * The :fb will force blending - * for this case. - */ - if (I != I1) { - continue; - } - wx = 1.0; - - /* interpolation scheme: */ - } else if (! shrink || interpolate) { - if (I >= Nx) { - continue; /* off edge */ - } else if (I == I1) { - wx = 1.0 - ddx; - } else if (I != I1) { - wx = ddx; - } - - /* integration scheme: */ - } else if (I < x1) { - /* - * source left edge (I) to the - * left of dest left edge (x1): - * fractional weight - */ - wx = I+1 - x1; - } else if (I+1 > x2) { - /* - * source right edge (I+1) to the - * right of dest right edge (x2): - * fractional weight - */ - wx = x2 - I; - } else { - /* - * source edges (I and I+1) completely - * inside dest edges (x1 and x2): - * full weight - */ - wx = 1.0; - } - - w = wx * wy; - wtot += w; - - /* - * We average the unsigned char value - * instead of char value: otherwise - * the minimum (char 0) is right next - * to the maximum (char -1)! This way - * they are spread between 0 and 255. - */ - if (Bpp == 4) { - /* unroll the loops, can give 20% */ - pixave[0] += w * ((unsigned char) *(src )); - pixave[1] += w * ((unsigned char) *(src+1)); - pixave[2] += w * ((unsigned char) *(src+2)); - pixave[3] += w * ((unsigned char) *(src+3)); - } else if (Bpp == 2) { - /* - * 16bpp: trickier with green - * split over two bytes, so we - * use the masks: - */ - us = *((unsigned short *) src); - pixave[0] += w*(us & main_red_mask); - pixave[1] += w*(us & main_green_mask); - pixave[2] += w*(us & main_blue_mask); - } else if (Bpp == 1) { - pixave[0] += w * - ((unsigned char) *(src)); - } else { - for (b=0; b<Bpp; b++) { - pixave[b] += w * - ((unsigned char) *(src+b)); - } - } - src += Bpp; - } - } - - if (wtot <= 0.0) { - wtot = 1.0; - } - wtot = 1.0/wtot; /* normalization factor */ - - /* place weighted average pixel in the scaled fb: */ - if (Bpp == 4) { - *(dest ) = (char) (wtot * pixave[0]); - *(dest+1) = (char) (wtot * pixave[1]); - *(dest+2) = (char) (wtot * pixave[2]); - *(dest+3) = (char) (wtot * pixave[3]); - } else if (Bpp == 2) { - /* 16bpp / 565 case: */ - pixave[0] *= wtot; - pixave[1] *= wtot; - pixave[2] *= wtot; - us = (main_red_mask & (int) pixave[0]) - | (main_green_mask & (int) pixave[1]) - | (main_blue_mask & (int) pixave[2]); - *( (unsigned short *) dest ) = us; - } else if (Bpp == 1) { - *(dest) = (char) (wtot * pixave[0]); - } else { - for (b=0; b<Bpp; b++) { - *(dest+b) = (char) (wtot * pixave[b]); - } - } - dest += Bpp; - } - } - markit: - if (mark) { - mark_rect_as_modified(i1, j1, i2, j2, 1); - } -} - -/* - Framebuffers data flow: - - General case: - -------- -------- -------- -------- - ----- |8to24_fb| |main_fb | |snap_fb | | X | - |rfbfb| <== | | <== | | <== | | <== | Server | - ----- -------- -------- -------- -------- - (to vnc) (optional) (usu = rfbfb) (optional) (read only) - - 8to24_fb mode will create side fbs: poll24_fb and poll8_fb for - bookkeepping the different regions (merged into 8to24_fb). - - Normal case: - -------- -------- - |main_fb | | X | - |= rfb_fb| <== | Server | - -------- -------- - - Scaling case: - -------- -------- - ----- |main_fb | | X | - |rfbfb| <== | | <== | Server | - ----- -------- -------- - - Webcam/video case: - -------- -------- -------- - |main_fb | |snap_fb | | Video | - | | <== | | <== | device | - -------- -------- -------- - -If we ever do a -rr rotation/reflection tran, it probably should -be done after any scaling (need a rr_fb for intermediate results) - --rr option: transformation: - - none x -> x; - y -> y; - - x x -> w - x - 1; - y -> y; - - y x -> x; - x -> h - y - 1; - - xy x -> w - x - 1; - y -> h - y - 1; - - +90 x -> h - y - 1; - y -> x; - - +90x x -> y; - y -> x; - - +90y x -> h - y - 1; - y -> w - x - 1; - - -90 x -> y; - y -> w - x - 1; - -some aliases: - - xy: yx, +180, -180, 180 - +90: 90 - +90x: 90x - +90y: 90y - -90: +270, 270 - */ - -void scale_and_mark_rect(int X1, int Y1, int X2, int Y2, int mark) { - char *dst_fb, *src_fb = main_fb; - int dst_bpl, Bpp = bpp/8, fac = 1; - - if (!screen || !rfb_fb || !main_fb) { - return; - } - if (! screen->serverFormat.trueColour) { - /* - * PseudoColor colormap... blending leads to random colors. - * User can override with ":fb" - */ - if (scaling_blend == 1) { - /* :fb option sets it to 2 */ - if (default_visual->class == StaticGray) { - /* - * StaticGray can be blended OK, otherwise - * user can disable with :nb - */ - ; - } else { - scaling_blend = 0; - } - } - } - - if (cmap8to24 && cmap8to24_fb) { - src_fb = cmap8to24_fb; - if (scaling) { - if (depth <= 8) { - fac = 4; - } else if (depth <= 16) { - fac = 2; - } - } - } - dst_fb = rfb_fb; - dst_bpl = rfb_bytes_per_line; - - scale_rect(scale_fac_x, scale_fac_y, scaling_blend, scaling_interpolate, fac * Bpp, - src_fb, fac * main_bytes_per_line, dst_fb, dst_bpl, dpy_x, dpy_y, - scaled_x, scaled_y, X1, Y1, X2, Y2, mark); -} - -void rotate_coords(int x, int y, int *xo, int *yo, int dxi, int dyi) { - int xi = x, yi = y; - int Dx, Dy; - - if (dxi >= 0) { - Dx = dxi; - Dy = dyi; - } else if (scaling) { - Dx = scaled_x; - Dy = scaled_y; - } else { - Dx = dpy_x; - Dy = dpy_y; - } - - /* ncache?? */ - - if (rotating == ROTATE_NONE) { - *xo = xi; - *yo = yi; - } else if (rotating == ROTATE_X) { - *xo = Dx - xi - 1; - *yo = yi; - } else if (rotating == ROTATE_Y) { - *xo = xi; - *yo = Dy - yi - 1; - } else if (rotating == ROTATE_XY) { - *xo = Dx - xi - 1; - *yo = Dy - yi - 1; - } else if (rotating == ROTATE_90) { - *xo = Dy - yi - 1; - *yo = xi; - } else if (rotating == ROTATE_90X) { - *xo = yi; - *yo = xi; - } else if (rotating == ROTATE_90Y) { - *xo = Dy - yi - 1; - *yo = Dx - xi - 1; - } else if (rotating == ROTATE_270) { - *xo = yi; - *yo = Dx - xi - 1; - } -} - -void rotate_coords_inverse(int x, int y, int *xo, int *yo, int dxi, int dyi) { - int xi = x, yi = y; - - int Dx, Dy; - - if (dxi >= 0) { - Dx = dxi; - Dy = dyi; - } else if (scaling) { - Dx = scaled_x; - Dy = scaled_y; - } else { - Dx = dpy_x; - Dy = dpy_y; - } - if (! rotating_same) { - int t = Dx; - Dx = Dy; - Dy = t; - } - - if (rotating == ROTATE_NONE) { - *xo = xi; - *yo = yi; - } else if (rotating == ROTATE_X) { - *xo = Dx - xi - 1; - *yo = yi; - } else if (rotating == ROTATE_Y) { - *xo = xi; - *yo = Dy - yi - 1; - } else if (rotating == ROTATE_XY) { - *xo = Dx - xi - 1; - *yo = Dy - yi - 1; - } else if (rotating == ROTATE_90) { - *xo = yi; - *yo = Dx - xi - 1; - } else if (rotating == ROTATE_90X) { - *xo = yi; - *yo = xi; - } else if (rotating == ROTATE_90Y) { - *xo = Dy - yi - 1; - *yo = Dx - xi - 1; - } else if (rotating == ROTATE_270) { - *xo = Dy - yi - 1; - *yo = xi; - } -} - - /* unroll the Bpp loop to be used in each case: */ -#define ROT_COPY \ - src = src_0 + fbl*y + Bpp*x; \ - dst = dst_0 + rbl*yn + Bpp*xn; \ - if (Bpp == 1) { \ - *(dst) = *(src); \ - } else if (Bpp == 2) { \ - *(dst+0) = *(src+0); \ - *(dst+1) = *(src+1); \ - } else if (Bpp == 3) { \ - *(dst+0) = *(src+0); \ - *(dst+1) = *(src+1); \ - *(dst+2) = *(src+2); \ - } else if (Bpp == 4) { \ - *(dst+0) = *(src+0); \ - *(dst+1) = *(src+1); \ - *(dst+2) = *(src+2); \ - *(dst+3) = *(src+3); \ - } - -void rotate_fb(int x1, int y1, int x2, int y2) { - int x, y, xn, yn, r_x1, r_y1, r_x2, r_y2, Bpp = bpp/8; - int fbl = rfb_bytes_per_line; - int rbl = rot_bytes_per_line; - int Dx, Dy; - char *src, *dst; - char *src_0 = rfb_fb; - char *dst_0 = rot_fb; - - if (! rotating || ! rot_fb) { - return; - } - - if (scaling) { - Dx = scaled_x; - Dy = scaled_y; - } else { - Dx = dpy_x; - Dy = dpy_y; - } - rotate_coords(x1, y1, &r_x1, &r_y1, -1, -1); - rotate_coords(x2, y2, &r_x2, &r_y2, -1, -1); - - dst = rot_fb; - - if (rotating == ROTATE_X) { - for (y = y1; y < y2; y++) { - for (x = x1; x < x2; x++) { - xn = Dx - x - 1; - yn = y; - ROT_COPY - } - } - } else if (rotating == ROTATE_Y) { - for (y = y1; y < y2; y++) { - for (x = x1; x < x2; x++) { - xn = x; - yn = Dy - y - 1; - ROT_COPY - } - } - } else if (rotating == ROTATE_XY) { - for (y = y1; y < y2; y++) { - for (x = x1; x < x2; x++) { - xn = Dx - x - 1; - yn = Dy - y - 1; - ROT_COPY - } - } - } else if (rotating == ROTATE_90) { - for (y = y1; y < y2; y++) { - for (x = x1; x < x2; x++) { - xn = Dy - y - 1; - yn = x; - ROT_COPY - } - } - } else if (rotating == ROTATE_90X) { - for (y = y1; y < y2; y++) { - for (x = x1; x < x2; x++) { - xn = y; - yn = x; - ROT_COPY - } - } - } else if (rotating == ROTATE_90Y) { - for (y = y1; y < y2; y++) { - for (x = x1; x < x2; x++) { - xn = Dy - y - 1; - yn = Dx - x - 1; - ROT_COPY - } - } - } else if (rotating == ROTATE_270) { - for (y = y1; y < y2; y++) { - for (x = x1; x < x2; x++) { - xn = y; - yn = Dx - x - 1; - ROT_COPY - } - } - } -} - -void rotate_curs(char *dst_0, char *src_0, int Dx, int Dy, int Bpp) { - int x, y, xn, yn; - char *src, *dst; - int fbl, rbl; - - if (! rotating) { - return; - } - - fbl = Dx * Bpp; - if (rotating_same) { - rbl = Dx * Bpp; - } else { - rbl = Dy * Bpp; - } - - if (rotating == ROTATE_X) { - for (y = 0; y < Dy; y++) { - for (x = 0; x < Dx; x++) { - xn = Dx - x - 1; - yn = y; - ROT_COPY -if (0) fprintf(stderr, "rcurs: %d %d %d %d\n", x, y, xn, yn); - } - } - } else if (rotating == ROTATE_Y) { - for (y = 0; y < Dy; y++) { - for (x = 0; x < Dx; x++) { - xn = x; - yn = Dy - y - 1; - ROT_COPY - } - } - } else if (rotating == ROTATE_XY) { - for (y = 0; y < Dy; y++) { - for (x = 0; x < Dx; x++) { - xn = Dx - x - 1; - yn = Dy - y - 1; - ROT_COPY - } - } - } else if (rotating == ROTATE_90) { - for (y = 0; y < Dy; y++) { - for (x = 0; x < Dx; x++) { - xn = Dy - y - 1; - yn = x; - ROT_COPY - } - } - } else if (rotating == ROTATE_90X) { - for (y = 0; y < Dy; y++) { - for (x = 0; x < Dx; x++) { - xn = y; - yn = x; - ROT_COPY - } - } - } else if (rotating == ROTATE_90Y) { - for (y = 0; y < Dy; y++) { - for (x = 0; x < Dx; x++) { - xn = Dy - y - 1; - yn = Dx - x - 1; - ROT_COPY - } - } - } else if (rotating == ROTATE_270) { - for (y = 0; y < Dy; y++) { - for (x = 0; x < Dx; x++) { - xn = y; - yn = Dx - x - 1; - ROT_COPY - } - } - } -} - -void mark_wrapper(int x1, int y1, int x2, int y2) { - int t, r_x1 = x1, r_y1 = y1, r_x2 = x2, r_y2 = y2; - - if (rotating) { - /* well we hope rot_fb will always be the last one... */ - rotate_coords(x1, y1, &r_x1, &r_y1, -1, -1); - rotate_coords(x2, y2, &r_x2, &r_y2, -1, -1); - rotate_fb(x1, y1, x2, y2); - if (r_x1 > r_x2) { - t = r_x1; - r_x1 = r_x2; - r_x2 = t; - } - if (r_y1 > r_y2) { - t = r_y1; - r_y1 = r_y2; - r_y2 = t; - } - /* painting errors */ - r_x1--; - r_x2++; - r_y1--; - r_y2++; - } - rfbMarkRectAsModified(screen, r_x1, r_y1, r_x2, r_y2); -} - -void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force) { - - if (damage_time != 0) { - /* - * This is not XDAMAGE, rather a hack for testing - * where we allow the framebuffer to be corrupted for - * damage_delay seconds. - */ - int debug = 0; - if (time(NULL) > damage_time + damage_delay) { - if (! quiet) { - rfbLog("damaging turned off.\n"); - } - damage_time = 0; - damage_delay = 0; - } else { - if (debug) { - rfbLog("damaging viewer fb by not marking " - "rect: %d,%d,%d,%d\n", x1, y1, x2, y2); - } - return; - } - } - - - if (rfb_fb == main_fb || force) { - mark_wrapper(x1, y1, x2, y2); - return; - } - - if (cmap8to24) { - bpp8to24(x1, y1, x2, y2); - } - - if (scaling) { - scale_and_mark_rect(x1, y1, x2, y2, 1); - } else { - mark_wrapper(x1, y1, x2, y2); - } -} - -/* - * Notifies libvncserver of a changed hint rectangle. - */ -static void mark_hint(hint_t hint) { - int x = hint.x; - int y = hint.y; - int w = hint.w; - int h = hint.h; - - mark_rect_as_modified(x, y, x + w, y + h, 0); -} - -/* - * copy_tiles() gives a slight improvement over copy_tile() since - * adjacent runs of tiles are done all at once there is some savings - * due to contiguous memory access. Not a great speedup, but in some - * cases it can be up to 2X. Even more on a SunRay or ShadowFB where - * no graphics hardware is involved in the read. Generally, graphics - * devices are optimized for write, not read, so we are limited by the - * read bandwidth, sometimes only 5 MB/sec on otherwise fast hardware. - */ -static int *first_line = NULL, *last_line = NULL; -static unsigned short *left_diff = NULL, *right_diff = NULL; - -static int copy_tiles(int tx, int ty, int nt) { - int x, y, line; - int size_x, size_y, width1, width2; - int off, len, n, dw, dx, t; - int w1, w2, dx1, dx2; /* tmps for normal and short tiles */ - int pixelsize = bpp/8; - int first_min, last_max; - int first_x = -1, last_x = -1; - static int prev_ntiles_x = -1; - - char *src, *dst, *s_src, *s_dst, *m_src, *m_dst; - char *h_src, *h_dst; - if (unixpw_in_progress) return 0; - - if (ntiles_x != prev_ntiles_x && first_line != NULL) { - free(first_line); first_line = NULL; - free(last_line); last_line = NULL; - free(left_diff); left_diff = NULL; - free(right_diff); right_diff = NULL; - } - - if (first_line == NULL) { - /* allocate arrays first time in. */ - int n = ntiles_x + 1; - rfbLog("copy_tiles: allocating first_line at size %d\n", n); - first_line = (int *) malloc((size_t) (n * sizeof(int))); - last_line = (int *) malloc((size_t) (n * sizeof(int))); - left_diff = (unsigned short *) - malloc((size_t) (n * sizeof(unsigned short))); - right_diff = (unsigned short *) - malloc((size_t) (n * sizeof(unsigned short))); - } - prev_ntiles_x = ntiles_x; - - x = tx * tile_x; - y = ty * tile_y; - - size_x = dpy_x - x; - if ( size_x > tile_x * nt ) { - size_x = tile_x * nt; - width1 = tile_x; - width2 = tile_x; - } else { - /* short tile */ - width1 = tile_x; /* internal tile */ - width2 = size_x - (nt - 1) * tile_x; /* right hand tile */ - } - - size_y = dpy_y - y; - if ( size_y > tile_y ) { - size_y = tile_y; - } - - n = tx + ty * ntiles_x; /* number of the first tile */ - - if (blackouts && tile_blackout[n].cover == 2) { - /* - * If there are blackouts and this tile is completely covered - * no need to poll screen or do anything else.. - * n.b. we are in single copy_tile mode: nt=1 - */ - tile_has_diff[n] = 0; - return(0); - } - - X_LOCK; - 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"); - - - X_UNLOCK; - - if (blackouts && tile_blackout[n].cover == 1) { - /* - * If there are blackouts and this tile is partially covered - * we should re-black-out the portion. - * n.b. we are in single copy_tile mode: nt=1 - */ - int x1, x2, y1, y2, b; - int w, s, fill = 0; - - for (b=0; b < tile_blackout[n].count; b++) { - char *b_dst = tile_row[nt]->data; - - x1 = tile_blackout[n].bo[b].x1 - x; - y1 = tile_blackout[n].bo[b].y1 - y; - x2 = tile_blackout[n].bo[b].x2 - x; - y2 = tile_blackout[n].bo[b].y2 - y; - - w = (x2 - x1) * pixelsize; - s = x1 * pixelsize; - - for (line = 0; line < size_y; line++) { - if (y1 <= line && line < y2) { - memset(b_dst + s, fill, (size_t) w); - } - b_dst += tile_row[nt]->bytes_per_line; - } - } - } - - src = tile_row[nt]->data; - dst = main_fb + y * main_bytes_per_line + x * pixelsize; - - s_src = src; - s_dst = dst; - - for (t=1; t <= nt; t++) { - first_line[t] = -1; - } - - /* find the first line with difference: */ - w1 = width1 * pixelsize; - w2 = width2 * pixelsize; - - /* foreach line: */ - for (line = 0; line < size_y; line++) { - /* foreach horizontal tile: */ - 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; - } - - if (memcmp(s_dst + off, s_src + off, len)) { - first_line[t] = line; - } - } - s_src += tile_row[nt]->bytes_per_line; - s_dst += main_bytes_per_line; - } - - /* see if there were any differences for any tile: */ - first_min = -1; - for (t=1; t <= nt; t++) { - tile_tried[n+(t-1)] = 1; - if (first_line[t] != -1) { - if (first_min == -1 || first_line[t] < first_min) { - first_min = first_line[t]; - } - } - } - if (first_min == -1) { - /* no tile has a difference, note this and get out: */ - for (t=1; t <= nt; t++) { - tile_has_diff[n+(t-1)] = 0; - } - return(0); - } else { - /* - * at least one tile has a difference. make sure info - * is recorded (e.g. sometimes we guess tiles and they - * came in with tile_has_diff 0) - */ - for (t=1; t <= nt; t++) { - if (first_line[t] == -1) { - tile_has_diff[n+(t-1)] = 0; - } else { - tile_has_diff[n+(t-1)] = 1; - } - } - } - - m_src = src + (tile_row[nt]->bytes_per_line * size_y); - m_dst = dst + (main_bytes_per_line * size_y); - - for (t=1; t <= nt; t++) { - last_line[t] = first_line[t]; - } - - /* find the last line with difference: */ - w1 = width1 * pixelsize; - w2 = width2 * pixelsize; - - /* foreach line: */ - for (line = size_y - 1; line > first_min; line--) { - - m_src -= tile_row[nt]->bytes_per_line; - m_dst -= main_bytes_per_line; - - /* foreach tile: */ - for (t=1; t <= nt; t++) { - if (first_line[t] == -1 - || last_line[t] != first_line[t]) { - /* tile has no changes or already done */ - continue; - } - - off = (t-1) * w1; - if (t == nt) { - len = w2; /* possible short tile */ - } else { - len = w1; - } - if (memcmp(m_dst + off, m_src + off, len)) { - last_line[t] = line; - } - } - } - - /* - * determine the farthest down last changed line - * will be used below to limit our memcpy() to the framebuffer. - */ - last_max = -1; - for (t=1; t <= nt; t++) { - if (first_line[t] == -1) { - continue; - } - if (last_max == -1 || last_line[t] > last_max) { - last_max = last_line[t]; - } - } - - /* look for differences on left and right hand edges: */ - for (t=1; t <= nt; t++) { - left_diff[t] = 0; - right_diff[t] = 0; - } - - h_src = src; - h_dst = dst; - - w1 = width1 * pixelsize; - w2 = width2 * pixelsize; - - dx1 = (width1 - tile_fuzz) * pixelsize; - dx2 = (width2 - tile_fuzz) * pixelsize; - dw = tile_fuzz * pixelsize; - - /* foreach line: */ - for (line = 0; line < size_y; line++) { - /* foreach tile: */ - for (t=1; t <= nt; t++) { - if (first_line[t] == -1) { - /* tile has no changes at all */ - continue; - } - - off = (t-1) * w1; - if (t == nt) { - dx = dx2; /* possible short tile */ - if (dx <= 0) { - break; - } - } else { - dx = dx1; - } - - if (! left_diff[t] && memcmp(h_dst + off, - h_src + off, dw)) { - left_diff[t] = 1; - } - if (! right_diff[t] && memcmp(h_dst + off + dx, - h_src + off + dx, dw) ) { - right_diff[t] = 1; - } - } - h_src += tile_row[nt]->bytes_per_line; - h_dst += main_bytes_per_line; - } - - /* now finally copy the difference to the rfb framebuffer: */ - s_src = src + tile_row[nt]->bytes_per_line * first_min; - s_dst = dst + main_bytes_per_line * first_min; - - 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); - if (nt == 1) { - /* - * optimization for tall skinny lines, e.g. wm - * frame. try to find first_x and last_x to limit - * the size of the hint. could help for a slow - * link. Unfortunately we spent a lot of time - * reading in the many tiles. - * - * BTW, we like to think the above memcpy leaves - * the data we use below in the cache... (but - * it could be two 128 byte segments at 32bpp) - * so this inner loop is not as bad as it seems. - */ - int k, kx; - kx = pixelsize; - for (k=0; k<size_x; k++) { - if (memcmp(s_dst + k*kx, s_src + k*kx, kx)) { - if (first_x == -1 || k < first_x) { - first_x = k; - } - if (last_x == -1 || k > last_x) { - last_x = k; - } - } - } - } - s_src += tile_row[nt]->bytes_per_line; - s_dst += main_bytes_per_line; - } - - /* record all the info in the region array for this tile: */ - for (t=1; t <= nt; t++) { - int s = t - 1; - - if (first_line[t] == -1) { - /* tile unchanged */ - continue; - } - tile_region[n+s].first_line = first_line[t]; - tile_region[n+s].last_line = last_line[t]; - - tile_region[n+s].first_x = first_x; - tile_region[n+s].last_x = last_x; - - tile_region[n+s].top_diff = 0; - tile_region[n+s].bot_diff = 0; - if ( first_line[t] < tile_fuzz ) { - tile_region[n+s].top_diff = 1; - } - if ( last_line[t] > (size_y - 1) - tile_fuzz ) { - tile_region[n+s].bot_diff = 1; - } - - tile_region[n+s].left_diff = left_diff[t]; - tile_region[n+s].right_diff = right_diff[t]; - - tile_copied[n+s] = 1; - } - - return(1); -} - -/* - * The copy_tile() call in the loop below copies the changed tile into - * the rfb framebuffer. Note that copy_tile() sets the tile_region - * struct to have info about the y-range of the changed region and also - * whether the tile edges contain diffs (within distance tile_fuzz). - * - * We use this tile_region info to try to guess if the downward and right - * tiles will have diffs. These tiles will be checked later in the loop - * (since y+1 > y and x+1 > x). - * - * See copy_tiles_backward_pass() for analogous checking upward and - * left tiles. - */ -static int copy_all_tiles(void) { - int x, y, n, m; - int diffs = 0, ct; - - if (unixpw_in_progress) return 0; - - for (y=0; y < ntiles_y; y++) { - for (x=0; x < ntiles_x; x++) { - n = x + y * ntiles_x; - - if (tile_has_diff[n]) { - ct = copy_tiles(x, y, 1); - if (ct < 0) return ct; /* fatal */ - } - if (! tile_has_diff[n]) { - /* - * n.b. copy_tiles() may have detected - * no change and reset tile_has_diff to 0. - */ - continue; - } - diffs++; - - /* neighboring tile downward: */ - if ( (y+1) < ntiles_y && tile_region[n].bot_diff) { - m = x + (y+1) * ntiles_x; - if (! tile_has_diff[m]) { - tile_has_diff[m] = 2; - } - } - /* neighboring tile to right: */ - if ( (x+1) < ntiles_x && tile_region[n].right_diff) { - m = (x+1) + y * ntiles_x; - if (! tile_has_diff[m]) { - tile_has_diff[m] = 2; - } - } - } - } - return diffs; -} - -/* - * Routine analogous to copy_all_tiles() above, but for horizontal runs - * of adjacent changed tiles. - */ -static int copy_all_tile_runs(void) { - int x, y, n, m, i; - int diffs = 0, ct; - int in_run = 0, run = 0; - int ntave = 0, ntcnt = 0; - - if (unixpw_in_progress) return 0; - - for (y=0; y < ntiles_y; y++) { - for (x=0; x < ntiles_x + 1; x++) { - n = x + y * ntiles_x; - - if (x != ntiles_x && tile_has_diff[n]) { - in_run = 1; - run++; - } else { - if (! in_run) { - in_run = 0; - run = 0; - continue; - } - ct = copy_tiles(x - run, y, run); - if (ct < 0) return ct; /* fatal */ - - ntcnt++; - ntave += run; - diffs += run; - - /* neighboring tile downward: */ - for (i=1; i <= run; i++) { - if ((y+1) < ntiles_y - && tile_region[n-i].bot_diff) { - m = (x-i) + (y+1) * ntiles_x; - if (! tile_has_diff[m]) { - tile_has_diff[m] = 2; - } - } - } - - /* neighboring tile to right: */ - if (((x-1)+1) < ntiles_x - && tile_region[n-1].right_diff) { - m = ((x-1)+1) + y * ntiles_x; - if (! tile_has_diff[m]) { - tile_has_diff[m] = 2; - } - - /* note that this starts a new run */ - in_run = 1; - run = 1; - } else { - in_run = 0; - run = 0; - } - } - } - /* - * Could some activity go here, to emulate threaded - * behavior by servicing some libvncserver tasks? - */ - } - return diffs; -} - -/* - * Here starts a bunch of heuristics to guess/detect changed tiles. - * They are: - * copy_tiles_backward_pass, fill_tile_gaps/gap_try, grow_islands/island_try - */ - -/* - * Try to predict whether the upward and/or leftward tile has been modified. - * copy_all_tiles() has already done downward and rightward tiles. - */ -static int copy_tiles_backward_pass(void) { - int x, y, n, m; - int diffs = 0, ct; - - if (unixpw_in_progress) return 0; - - for (y = ntiles_y - 1; y >= 0; y--) { - for (x = ntiles_x - 1; x >= 0; x--) { - n = x + y * ntiles_x; /* number of this tile */ - - if (! tile_has_diff[n]) { - continue; - } - - m = x + (y-1) * ntiles_x; /* neighboring tile upward */ - - if (y >= 1 && ! tile_has_diff[m] && tile_region[n].top_diff) { - if (! tile_tried[m]) { - tile_has_diff[m] = 2; - ct = copy_tiles(x, y-1, 1); - if (ct < 0) return ct; /* fatal */ - } - } - - m = (x-1) + y * ntiles_x; /* neighboring tile to left */ - - if (x >= 1 && ! tile_has_diff[m] && tile_region[n].left_diff) { - if (! tile_tried[m]) { - tile_has_diff[m] = 2; - ct = copy_tiles(x-1, y, 1); - if (ct < 0) return ct; /* fatal */ - } - } - } - } - for (n=0; n < ntiles; n++) { - if (tile_has_diff[n]) { - diffs++; - } - } - return diffs; -} - -static int copy_tiles_additional_pass(void) { - int x, y, n; - int diffs = 0, ct; - - if (unixpw_in_progress) return 0; - - for (y=0; y < ntiles_y; y++) { - for (x=0; x < ntiles_x; x++) { - n = x + y * ntiles_x; /* number of this tile */ - - if (! tile_has_diff[n]) { - continue; - } - if (tile_copied[n]) { - continue; - } - - ct = copy_tiles(x, y, 1); - if (ct < 0) return ct; /* fatal */ - } - } - for (n=0; n < ntiles; n++) { - if (tile_has_diff[n]) { - diffs++; - } - } - return diffs; -} - -static int gap_try(int x, int y, int *run, int *saw, int along_x) { - int n, m, i, xt, yt, ct; - - n = x + y * ntiles_x; - - if (! tile_has_diff[n]) { - if (*saw) { - (*run)++; /* extend the gap run. */ - } - return 0; - } - if (! *saw || *run == 0 || *run > gaps_fill) { - *run = 0; /* unacceptable run. */ - *saw = 1; - return 0; - } - - for (i=1; i <= *run; i++) { /* iterate thru the run. */ - if (along_x) { - xt = x - i; - yt = y; - } else { - xt = x; - yt = y - i; - } - - m = xt + yt * ntiles_x; - if (tile_tried[m]) { /* do not repeat tiles */ - continue; - } - - ct = copy_tiles(xt, yt, 1); - if (ct < 0) return ct; /* fatal */ - } - *run = 0; - *saw = 1; - return 1; -} - -/* - * Look for small gaps of unchanged tiles that may actually contain changes. - * E.g. when paging up and down in a web broswer or terminal there can - * be a distracting delayed filling in of such gaps. gaps_fill is the - * tweak parameter that sets the width of the gaps that are checked. - * - * BTW, grow_islands() is actually pretty successful at doing this too... - */ -static int fill_tile_gaps(void) { - int x, y, run, saw; - int n, diffs = 0, ct; - - /* horizontal: */ - for (y=0; y < ntiles_y; y++) { - run = 0; - saw = 0; - for (x=0; x < ntiles_x; x++) { - ct = gap_try(x, y, &run, &saw, 1); - if (ct < 0) return ct; /* fatal */ - } - } - - /* vertical: */ - for (x=0; x < ntiles_x; x++) { - run = 0; - saw = 0; - for (y=0; y < ntiles_y; y++) { - ct = gap_try(x, y, &run, &saw, 0); - if (ct < 0) return ct; /* fatal */ - } - } - - for (n=0; n < ntiles; n++) { - if (tile_has_diff[n]) { - diffs++; - } - } - return diffs; -} - -static int island_try(int x, int y, int u, int v, int *run) { - int n, m, ct; - - n = x + y * ntiles_x; - m = u + v * ntiles_x; - - if (tile_has_diff[n]) { - (*run)++; - } else { - *run = 0; - } - - if (tile_has_diff[n] && ! tile_has_diff[m]) { - /* found a discontinuity */ - - if (tile_tried[m]) { - return 0; - } else if (*run < grow_fill) { - return 0; - } - - ct = copy_tiles(u, v, 1); - if (ct < 0) return ct; /* fatal */ - } - return 1; -} - -/* - * Scan looking for discontinuities in tile_has_diff[]. Try to extend - * the boundary of the discontinuity (i.e. make the island larger). - * Vertical scans are skipped since they do not seem to yield much... - */ -static int grow_islands(void) { - int x, y, n, run; - int diffs = 0, ct; - - /* - * n.b. the way we scan here should keep an extension going, - * and so also fill in gaps effectively... - */ - - /* left to right: */ - for (y=0; y < ntiles_y; y++) { - run = 0; - for (x=0; x <= ntiles_x - 2; x++) { - ct = island_try(x, y, x+1, y, &run); - if (ct < 0) return ct; /* fatal */ - } - } - /* right to left: */ - for (y=0; y < ntiles_y; y++) { - run = 0; - for (x = ntiles_x - 1; x >= 1; x--) { - ct = island_try(x, y, x-1, y, &run); - if (ct < 0) return ct; /* fatal */ - } - } - for (n=0; n < ntiles; n++) { - if (tile_has_diff[n]) { - diffs++; - } - } - return diffs; -} - -/* - * Fill the framebuffer with zeros for each blackout region - */ -static void blackout_regions(void) { - int i; - for (i=0; i < blackouts; i++) { - zero_fb(blackr[i].x1, blackr[i].y1, blackr[i].x2, blackr[i].y2); - } -} - -/* - * copy the whole X screen to the rfb framebuffer. For a large enough - * number of changed tiles, this is faster than tiles scheme at retrieving - * the info from the X server. Bandwidth to client and compression time - * are other issues... use -fs 1.0 to disable. - */ -int copy_screen(void) { - char *fbp; - int i, y, block_size; - - if (! fs_factor) { - return 0; - } - if (debug_tiles) fprintf(stderr, "copy_screen\n"); - - if (unixpw_in_progress) return 0; - - - if (! main_fb) { - return 0; - } - - block_size = ((dpy_y/fs_factor) * main_bytes_per_line); - - fbp = main_fb; - y = 0; - - X_LOCK; - - /* screen may be too big for 1 shm area, so broken into fs_factor */ - for (i=0; i < fs_factor; i++) { - XRANDR_SET_TRAP_RET(-1, "copy_screen-set"); - copy_image(fullscreen, 0, y, 0, 0); - XRANDR_CHK_TRAP_RET(-1, "copy_screen-chk"); - - memcpy(fbp, fullscreen->data, (size_t) block_size); - - y += dpy_y / fs_factor; - fbp += block_size; - } - - X_UNLOCK; - - if (blackouts) { - blackout_regions(); - } - - mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); - return 0; -} - -#include <rfb/default8x16.h> - -/* - * Color values from the vcsadump program. - * void dumpcss(FILE *fp, char *attribs_used) - * char *colormap[] = { - * "#000000", "#0000AA", "#00AA00", "#00AAAA", "#AA0000", "#AA00AA", "#AA5500", "#AAAAAA", - * "#555555", "#5555AA", "#55FF55", "#55FFFF", "#FF5555", "#FF55FF", "#FFFF00", "#FFFFFF" }; - */ - -static unsigned char console_cmap[16*3]={ -/* 0 */ 0x00, 0x00, 0x00, -/* 1 */ 0x00, 0x00, 0xAA, -/* 2 */ 0x00, 0xAA, 0x00, -/* 3 */ 0x00, 0xAA, 0xAA, -/* 4 */ 0xAA, 0x00, 0x00, -/* 5 */ 0xAA, 0x00, 0xAA, -/* 6 */ 0xAA, 0x55, 0x00, -/* 7 */ 0xAA, 0xAA, 0xAA, -/* 8 */ 0x55, 0x55, 0x55, -/* 9 */ 0x55, 0x55, 0xAA, -/* 10 */ 0x55, 0xFF, 0x55, -/* 11 */ 0x55, 0xFF, 0xFF, -/* 12 */ 0xFF, 0x55, 0x55, -/* 13 */ 0xFF, 0x55, 0xFF, -/* 14 */ 0xFF, 0xFF, 0x00, -/* 15 */ 0xFF, 0xFF, 0xFF -}; - -static void snap_vcsa_rawfb(void) { - int n; - char *dst; - char buf[32]; - int i, len, del; - unsigned char rows, cols, xpos, ypos; - static int prev_rows = -1, prev_cols = -1; - static unsigned char prev_xpos = -1, prev_ypos = -1; - static char *vcsabuf = NULL; - static char *vcsabuf0 = NULL; - static unsigned int color_tab[16]; - static int Cw = 8, Ch = 16; - static int db = -1, first = 1; - int created = 0; - rfbScreenInfo s; - rfbScreenInfoPtr fake_screen = &s; - int Bpp = raw_fb_native_bpp / 8; - - if (db < 0) { - if (getenv("X11VNC_DEBUG_VCSA")) { - db = atoi(getenv("X11VNC_DEBUG_VCSA")); - } else { - db = 0; - } - } - - if (first) { - unsigned int rm = raw_fb_native_red_mask; - unsigned int gm = raw_fb_native_green_mask; - unsigned int bm = raw_fb_native_blue_mask; - unsigned int rs = raw_fb_native_red_shift; - unsigned int gs = raw_fb_native_green_shift; - unsigned int bs = raw_fb_native_blue_shift; - unsigned int rx = raw_fb_native_red_max; - unsigned int gx = raw_fb_native_green_max; - unsigned int bx = raw_fb_native_blue_max; - - for (i=0; i < 16; i++) { - int r = console_cmap[3*i+0]; - int g = console_cmap[3*i+1]; - int b = console_cmap[3*i+2]; - r = rx * r / 255; - g = gx * g / 255; - b = bx * b / 255; - color_tab[i] = (r << rs) | (g << gs) | (b << bs); - if (db) fprintf(stderr, "cmap[%02d] 0x%08x %04d %04d %04d\n", i, color_tab[i], r, g, b); - if (i != 0 && getenv("RAWFB_VCSA_BW")) { - color_tab[i] = rm | gm | bm; - } - } - } - first = 0; - - lseek(raw_fb_fd, 0, SEEK_SET); - len = 4; - del = 0; - memset(buf, 0, sizeof(buf)); - while (len > 0) { - n = read(raw_fb_fd, buf + del, len); - if (n > 0) { - del += n; - len -= n; - } else if (n == 0) { - break; - } else if (errno != EINTR && errno != EAGAIN) { - break; - } - } - - rows = (unsigned char) buf[0]; - cols = (unsigned char) buf[1]; - xpos = (unsigned char) buf[2]; - ypos = (unsigned char) buf[3]; - - if (db) fprintf(stderr, "rows=%d cols=%d xpos=%d ypos=%d Bpp=%d\n", rows, cols, xpos, ypos, Bpp); - if (rows == 0 || cols == 0) { - usleep(100 * 1000); - return; - } - - if (vcsabuf == NULL || prev_rows != rows || prev_cols != cols) { - if (vcsabuf) { - free(vcsabuf); - free(vcsabuf0); - } - vcsabuf = (char *) calloc(2 * rows * cols, 1); - vcsabuf0 = (char *) calloc(2 * rows * cols, 1); - created = 1; - - if (prev_rows != -1 && prev_cols != -1) { - do_new_fb(1); - } - - prev_rows = rows; - prev_cols = cols; - } - - if (!rfbEndianTest) { - unsigned char tc = rows; - rows = cols; - cols = tc; - - tc = xpos; - xpos = ypos; - ypos = tc; - } - - len = 2 * rows * cols; - del = 0; - memset(vcsabuf, 0, len); - while (len > 0) { - n = read(raw_fb_fd, vcsabuf + del, len); - if (n > 0) { - del += n; - len -= n; - } else if (n == 0) { - break; - } else if (errno != EINTR && errno != EAGAIN) { - break; - } - } - - fake_screen->frameBuffer = snap->data; - fake_screen->paddedWidthInBytes = snap->bytes_per_line; - fake_screen->serverFormat.bitsPerPixel = raw_fb_native_bpp; - fake_screen->width = snap->width; - fake_screen->height = snap->height; - - for (i=0; i < rows * cols; i++) { - int ix, iy, x, y, w, h; - unsigned char chr = 0; - unsigned char attr; - unsigned int fore, back; - unsigned short *usp; - unsigned int *uip; - chr = (unsigned char) vcsabuf[2*i]; - attr = vcsabuf[2*i+1]; - - iy = i / cols; - ix = i - iy * cols; - - if (ix == prev_xpos && iy == prev_ypos) { - ; - } else if (ix == xpos && iy == ypos) { - ; - } else if (!created && chr == vcsabuf0[2*i] && attr == vcsabuf0[2*i+1]) { - continue; - } - - if (!rfbEndianTest) { - unsigned char tc = chr; - chr = attr; - attr = tc; - } - - y = iy * Ch; - x = ix * Cw; - dst = snap->data + y * snap->bytes_per_line + x * Bpp; - - fore = color_tab[attr & 0xf]; - back = color_tab[(attr >> 4) & 0x7]; - - if (ix == xpos && iy == ypos) { - unsigned int ti = fore; - fore = back; - back = ti; - } - - for (h = 0; h < Ch; h++) { - if (Bpp == 1) { - memset(dst, back, Cw); - } else if (Bpp == 2) { - for (w = 0; w < Cw; w++) { - usp = (unsigned short *) (dst + w*Bpp); - *usp = (unsigned short) back; - } - } else if (Bpp == 4) { - for (w = 0; w < Cw; w++) { - uip = (unsigned int *) (dst + w*Bpp); - *uip = (unsigned int) back; - } - } - dst += snap->bytes_per_line; - } - rfbDrawChar(fake_screen, &default8x16Font, x, y + Ch, chr, fore); - } - memcpy(vcsabuf0, vcsabuf, 2 * rows * cols); - prev_xpos = xpos; - prev_ypos = ypos; -} - -static void snap_all_rawfb(void) { - int pixelsize = bpp/8; - int n, sz; - char *dst; - static char *unclipped_dst = NULL; - static int unclipped_len = 0; - - dst = snap->data; - - if (xform24to32 && bpp == 32) { - pixelsize = 3; - } - sz = dpy_y * snap->bytes_per_line; - - if (wdpy_x > dpy_x || wdpy_y > dpy_y) { - sz = wdpy_x * wdpy_y * pixelsize; - if (sz > unclipped_len || unclipped_dst == NULL) { - if (unclipped_dst) { - free(unclipped_dst); - } - unclipped_dst = (char *) malloc(sz+4); - unclipped_len = sz; - } - dst = unclipped_dst; - } - - if (! raw_fb_seek) { - memcpy(dst, raw_fb_addr + raw_fb_offset, sz); - - } else { - int len = sz, del = 0; - off_t off = (off_t) raw_fb_offset; - - lseek(raw_fb_fd, off, SEEK_SET); - while (len > 0) { - n = read(raw_fb_fd, dst + del, len); - if (n > 0) { - del += n; - len -= n; - } else if (n == 0) { - break; - } else if (errno != EINTR && errno != EAGAIN) { - break; - } - } - } - - if (dst == unclipped_dst) { - char *src; - int h; - int x = off_x + coff_x; - int y = off_y + coff_y; - - src = unclipped_dst + y * wdpy_x * pixelsize + - x * pixelsize; - dst = snap->data; - - for (h = 0; h < dpy_y; h++) { - memcpy(dst, src, dpy_x * pixelsize); - src += wdpy_x * pixelsize; - dst += snap->bytes_per_line; - } - } -} - -int copy_snap(void) { - int db = 1; - char *fbp; - int i, y, block_size; - double dt; - static int first = 1, snapcnt = 0; - - if (raw_fb_str) { - int read_all_at_once = 1; - double start = dnow(); - if (rawfb_reset < 0) { - if (getenv("SNAPFB_RAWFB_RESET")) { - rawfb_reset = 1; - } else { - rawfb_reset = 0; - } - } - if (snap_fb == NULL || snap == NULL) { - rfbLog("copy_snap: rawfb mode and null snap fb\n"); - clean_up_exit(1); - } - if (rawfb_reset) { - initialize_raw_fb(1); - } - if (raw_fb_bytes_per_line != snap->bytes_per_line) { - read_all_at_once = 0; - } - if (raw_fb_full_str && strstr(raw_fb_full_str, "/dev/vcsa")) { - snap_vcsa_rawfb(); - } else if (read_all_at_once) { - snap_all_rawfb(); - } else { - /* this goes line by line, XXX not working for video */ - copy_raw_fb(snap, 0, 0, dpy_x, dpy_y); - } -if (db && snapcnt++ < 5) rfbLog("rawfb copy_snap took: %.5f secs\n", dnow() - start); - - return 0; - } - - if (! fs_factor) { - return 0; - } - - - if (! snap_fb || ! snap || ! snaprect) { - return 0; - } - block_size = ((dpy_y/fs_factor) * snap->bytes_per_line); - - fbp = snap_fb; - y = 0; - - - dtime0(&dt); - X_LOCK; - - /* screen may be too big for 1 shm area, so broken into fs_factor */ - for (i=0; i < fs_factor; i++) { - XRANDR_SET_TRAP_RET(-1, "copy_snap-set"); - copy_image(snaprect, 0, y, 0, 0); - XRANDR_CHK_TRAP_RET(-1, "copy_snap-chk"); - - memcpy(fbp, snaprect->data, (size_t) block_size); - - y += dpy_y / fs_factor; - fbp += block_size; - } - - X_UNLOCK; - - dt = dtime(&dt); - if (first) { - rfbLog("copy_snap: time for -snapfb snapshot: %.3f sec\n", dt); - first = 0; - } - - return 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); - 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. - */ -static void nap_set(int tile_cnt) { - int nap_in = nap_ok; - time_t now = time(NULL); - - if (scan_count == 0) { - /* roll up check for all NSCAN scans */ - nap_ok = 0; - if (naptile && nap_diff_count < 2 * NSCAN * naptile) { - /* "2" is a fudge to permit a bit of bg drawing */ - nap_ok = 1; - } - nap_diff_count = 0; - } - if (nap_ok && ! nap_in && use_xdamage) { - if (XD_skip > 0.8 * XD_tot) { - /* X DAMAGE is keeping load low, so skip nap */ - nap_ok = 0; - } - } - if (! nap_ok && client_count) { - if(now > last_fb_bytes_sent + no_fbu_blank) { - if (debug_tiles > 1) { - fprintf(stderr, "nap_set: nap_ok=1: now: %d last: %d\n", - (int) now, (int) last_fb_bytes_sent); - } - nap_ok = 1; - } - } - - if (show_cursor) { - /* kludge for the up to 4 tiles the mouse patch could occupy */ - if ( tile_cnt > 4) { - last_event = now; - } - } else if (tile_cnt != 0) { - last_event = now; - } -} - -/* - * split up a long nap to improve the wakeup time - */ -void nap_sleep(int ms, int split) { - int i, input = got_user_input; - int gd = got_local_pointer_input; - - for (i=0; i<split; i++) { - usleep(ms * 1000 / split); - if (! use_threads && i != split - 1) { - rfbPE(-1); - } - if (input != got_user_input) { - break; - } - if (gd != got_local_pointer_input) { - break; - } - } -} - -static char *get_load(void) { - static char tmp[64]; - static int count = 0; - - if (count++ % 5 == 0) { - struct stat sb; - memset(tmp, 0, sizeof(tmp)); - if (stat("/proc/loadavg", &sb) == 0) { - int d = open("/proc/loadavg", O_RDONLY); - if (d >= 0) { - read(d, tmp, 60); - close(d); - } - } - if (tmp[0] == '\0') { - strcat(tmp, "unknown"); - } - } - return tmp; -} - -/* - * see if we should take a nap of some sort between polls - */ -static void nap_check(int tile_cnt) { - time_t now; - - nap_diff_count += tile_cnt; - - if (! take_naps) { - return; - } - - now = time(NULL); - - if (screen_blank > 0) { - int dt_ev, dt_fbu; - static int ms = 0; - if (ms == 0) { - ms = 2000; - if (getenv("X11VNC_SB_FACTOR")) { - ms = ms * atof(getenv("X11VNC_SB_FACTOR")); - } - if (ms <= 0) { - ms = 2000; - } - } - - /* if no activity, pause here for a second or so. */ - dt_ev = (int) (now - last_event); - dt_fbu = (int) (now - last_fb_bytes_sent); - if (dt_fbu > screen_blank) { - /* sleep longer for no fb requests */ - if (debug_tiles > 1) { - fprintf(stderr, "screen blank sleep1: %d ms / 16, load: %s\n", 2 * ms, get_load()); - } - nap_sleep(2 * ms, 16); - return; - } - if (dt_ev > screen_blank) { - if (debug_tiles > 1) { - fprintf(stderr, "screen blank sleep2: %d ms / 8, load: %s\n", ms, get_load()); - } - nap_sleep(ms, 8); - return; - } - } - if (naptile && nap_ok && tile_cnt < naptile) { - int ms = napfac * waitms; - ms = ms > napmax ? napmax : ms; - if (now - last_input <= 3) { - nap_ok = 0; - } else if (now - last_local_input <= 3) { - nap_ok = 0; - } else { - if (debug_tiles > 1) { - fprintf(stderr, "nap_check sleep: %d ms / 1, load: %s\n", ms, get_load()); - } - nap_sleep(ms, 1); - } - } -} - -/* - * This is called to avoid a ~20 second timeout in libvncserver. - * May no longer be needed. - */ -static void ping_clients(int tile_cnt) { - static time_t last_send = 0; - time_t now = time(NULL); - - if (rfbMaxClientWait < 20000) { - rfbMaxClientWait = 20000; - rfbLog("reset rfbMaxClientWait to %d msec.\n", - rfbMaxClientWait); - } - if (tile_cnt > 0) { - last_send = now; - } else if (tile_cnt < 0) { - /* negative tile_cnt is -ping case */ - if (now >= last_send - tile_cnt) { - mark_rect_as_modified(0, 0, 1, 1, 1); - last_send = now; - } - } else if (now - last_send > 5) { - /* Send small heartbeat to client */ - mark_rect_as_modified(0, 0, 1, 1, 1); - last_send = now; - } -} - -/* - * scan_display() wants to know if this tile can be skipped due to - * blackout regions: (no data compare is done, just a quick geometric test) - */ -static int blackout_line_skip(int n, int x, int y, int rescan, - int *tile_count) { - - if (tile_blackout[n].cover == 2) { - tile_has_diff[n] = 0; - return 1; /* skip it */ - - } else if (tile_blackout[n].cover == 1) { - int w, x1, y1, x2, y2, b, hit = 0; - if (x + NSCAN > dpy_x) { - w = dpy_x - x; - } else { - w = NSCAN; - } - - for (b=0; b < tile_blackout[n].count; b++) { - - /* n.b. these coords are in full display space: */ - x1 = tile_blackout[n].bo[b].x1; - x2 = tile_blackout[n].bo[b].x2; - y1 = tile_blackout[n].bo[b].y1; - y2 = tile_blackout[n].bo[b].y2; - - if (x2 - x1 < w) { - /* need to cover full width */ - continue; - } - if (y1 <= y && y < y2) { - hit = 1; - break; - } - } - if (hit) { - if (! rescan) { - tile_has_diff[n] = 0; - } else { - *tile_count += tile_has_diff[n]; - } - return 1; /* skip */ - } - } - return 0; /* do not skip */ -} - -static int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src, - int w, int pixelsize) { - - int i, x1, y1, x2, y2, b, hit = 0; - int beg = -1, end = -1; - - if (tile_blackout[n].cover == 0) { - return 0; /* 0 means do not skip it. */ - } else if (tile_blackout[n].cover == 2) { - return 1; /* 1 means skip it. */ - } - - /* tile has partial coverage: */ - - for (i=0; i < w * pixelsize; i++) { - if (*(dst+i) != *(src+i)) { - beg = i/pixelsize; /* beginning difference */ - break; - } - } - for (i = w * pixelsize - 1; i >= 0; i--) { - if (*(dst+i) != *(src+i)) { - end = i/pixelsize; /* ending difference */ - break; - } - } - if (beg < 0 || end < 0) { - /* problem finding range... */ - return 0; - } - - /* loop over blackout rectangles: */ - for (b=0; b < tile_blackout[n].count; b++) { - - /* y in full display space: */ - y1 = tile_blackout[n].bo[b].y1; - y2 = tile_blackout[n].bo[b].y2; - - /* x relative to tile origin: */ - x1 = tile_blackout[n].bo[b].x1 - x; - x2 = tile_blackout[n].bo[b].x2 - x; - - if (y1 > y || y >= y2) { - continue; - } - if (x1 <= beg && end <= x2) { - hit = 1; - break; - } - } - if (hit) { - return 1; - } else { - return 0; - } -} - -/* - * For the subwin case follows the window if it is moved. - */ -void set_offset(void) { - Window w; - if (! subwin) { - return; - } - X_LOCK; - xtranslate(window, rootwin, 0, 0, &off_x, &off_y, &w, 0); - X_UNLOCK; -} - -static int xd_samples = 0, xd_misses = 0, xd_do_check = 0; - -/* - * Loop over 1-pixel tall horizontal scanlines looking for changes. - * Record the changes in tile_has_diff[]. Scanlines in the loop are - * equally spaced along y by NSCAN pixels, but have a slightly random - * starting offset ystart ( < NSCAN ) from scanlines[]. - */ - -static int scan_display(int ystart, int rescan) { - char *src, *dst; - int pixelsize = bpp/8; - int x, y, w, n; - int tile_count = 0; - int nodiffs = 0, diff_hint; - int xd_check = 0, xd_freq = 1; - static int xd_tck = 0; - - y = ystart; - - g_now = dnow(); - - if (! main_fb) { - rfbLog("scan_display: no main_fb!\n"); - return 0; - } - - X_LOCK; - - while (y < dpy_y) { - - if (use_xdamage) { - XD_tot++; - xd_check = 0; - if (xdamage_hint_skip(y)) { - if (xd_do_check && dpy && use_xdamage == 1) { - xd_tck++; - xd_tck = xd_tck % xd_freq; - if (xd_tck == 0) { - xd_check = 1; - xd_samples++; - } - } - if (!xd_check) { - XD_skip++; - y += NSCAN; - continue; - } - } else { - if (xd_do_check && 0) { - fprintf(stderr, "ns y=%d\n", y); - } - } - } - - /* grab the horizontal scanline from the display: */ - -#ifndef NO_NCACHE -/* XXX Y test */ -if (ncache > 0) { - int gotone = 0; - if (macosx_console) { - if (macosx_checkevent(NULL)) { - gotone = 1; - } - } else { -#if !NO_X11 - XEvent ev; - if (raw_fb_str) { - ; - } else if (XEventsQueued(dpy, QueuedAlready) == 0) { - ; /* XXX Y resp */ - } else if (XCheckTypedEvent(dpy, MapNotify, &ev)) { - gotone = 1; - } else if (XCheckTypedEvent(dpy, UnmapNotify, &ev)) { - gotone = 2; - } else if (XCheckTypedEvent(dpy, CreateNotify, &ev)) { - gotone = 3; - } else if (XCheckTypedEvent(dpy, ConfigureNotify, &ev)) { - gotone = 4; - } else if (XCheckTypedEvent(dpy, VisibilityNotify, &ev)) { - gotone = 5; - } - if (gotone) { - XPutBackEvent(dpy, &ev); - } -#endif - } - if (gotone) { - static int nomsg = 1; - if (nomsg) { - if (dnowx() > 20) { - nomsg = 0; - } - } else { -if (ncdb) fprintf(stderr, "\n*** SCAN_DISPLAY CHECK_NCACHE/%d *** %d rescan=%d\n", gotone, y, rescan); - } - X_UNLOCK; - check_ncache(0, 1); - X_LOCK; - } -} -#endif - - XRANDR_SET_TRAP_RET(-1, "scan_display-set"); - copy_image(scanline, 0, y, 0, 0); - XRANDR_CHK_TRAP_RET(-1, "scan_display-chk"); - - /* for better memory i/o try the whole line at once */ - src = scanline->data; - dst = main_fb + y * main_bytes_per_line; - - if (! memcmp(dst, src, main_bytes_per_line)) { - /* no changes anywhere in scan line */ - nodiffs = 1; - if (! rescan) { - y += NSCAN; - continue; - } - } - if (xd_check) { - xd_misses++; - } - - x = 0; - while (x < dpy_x) { - n = (x/tile_x) + (y/tile_y) * ntiles_x; - diff_hint = 0; - - if (blackouts) { - if (blackout_line_skip(n, x, y, rescan, - &tile_count)) { - x += NSCAN; - continue; - } - } - - if (rescan) { - if (nodiffs || tile_has_diff[n]) { - tile_count += tile_has_diff[n]; - x += NSCAN; - continue; - } - } else if (xdamage_tile_count && - tile_has_xdamage_diff[n]) { - tile_has_xdamage_diff[n] = 2; - diff_hint = 1; - } - - /* set ptrs to correspond to the x offset: */ - src = scanline->data + x * pixelsize; - dst = main_fb + y * main_bytes_per_line + x * pixelsize; - - /* compute the width of data to be compared: */ - if (x + NSCAN > dpy_x) { - w = dpy_x - x; - } else { - w = NSCAN; - } - - if (diff_hint || memcmp(dst, src, w * pixelsize)) { - /* found a difference, record it: */ - if (! blackouts) { - tile_has_diff[n] = 1; - tile_count++; - } else { - if (blackout_line_cmpskip(n, x, y, - dst, src, w, pixelsize)) { - tile_has_diff[n] = 0; - } else { - tile_has_diff[n] = 1; - tile_count++; - } - } - } - x += NSCAN; - } - y += NSCAN; - } - - X_UNLOCK; - - return tile_count; -} - - -int scanlines[NSCAN] = { - 0, 16, 8, 24, 4, 20, 12, 28, - 10, 26, 18, 2, 22, 6, 30, 14, - 1, 17, 9, 25, 7, 23, 15, 31, - 19, 3, 27, 11, 29, 13, 5, 21 -}; - -/* - * toplevel for the scanning, rescanning, and applying the heuristics. - * returns number of changed tiles. - */ -int scan_for_updates(int count_only) { - int i, tile_count, tile_diffs; - int old_copy_tile; - 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() */ - static double last_poll = 0.0; - double dtmp = 0.0; - - if (unixpw_in_progress) return 0; - - if (slow_fb > 0.0) { - double now = dnow(); - if (now < last_poll + slow_fb) { - return 0; - } - last_poll = now; - } - - for (i=0; i < ntiles; i++) { - tile_has_diff[i] = 0; - tile_has_xdamage_diff[i] = 0; - tile_tried[i] = 0; - tile_copied[i] = 0; - } - for (i=0; i < ntiles_y; i++) { - /* could be useful, currently not used */ - tile_row_has_xdamage_diff[i] = 0; - } - xdamage_tile_count = 0; - - /* - * n.b. this program has only been tested so far with - * tile_x = tile_y = NSCAN = 32! - */ - - if (!count_only) { - scan_count++; - scan_count %= NSCAN; - - /* some periodic maintenance */ - if (subwin && scan_count % 4 == 0) { - set_offset(); /* follow the subwindow */ - } - if (indexed_color && scan_count % 4 == 0) { - /* check for changed colormap */ - set_colormap(0); - } - if (cmap8to24 && scan_count % 1 == 0) { - check_for_multivis(); - } -#ifdef MACOSX - if (macosx_console) { - macosx_event_loop(); - } -#endif - if (use_xdamage) { - /* first pass collecting DAMAGE events: */ -#ifdef MACOSX - if (macosx_console) { - collect_non_X_xdamage(-1, -1, -1, -1, 0); - } else -#endif - { - if (rawfb_vnc_reflect) { - collect_non_X_xdamage(-1, -1, -1, -1, 0); - } else { - collect_xdamage(scan_count, 0); - } - } - } - } - -#define SCAN_FATAL(x) \ - if (x < 0) { \ - scan_in_progress = 0; \ - fb_copy_in_progress = 0; \ - return 0; \ - } - - /* scan with the initial y to the jitter value from scanlines: */ - scan_in_progress = 1; - tile_count = scan_display(scanlines[scan_count], 0); - SCAN_FATAL(tile_count); - - /* - * we do the XDAMAGE here too since after scan_display() - * there is a better chance we have received the events from - * the X server (otherwise the DAMAGE events will be processed - * in the *next* call, usually too late and wasteful since - * the unchanged tiles are read in again). - */ - if (use_xdamage) { -#ifdef MACOSX - if (macosx_console) { - ; - } else -#endif - { - if (rawfb_vnc_reflect) { - ; - } else { - collect_xdamage(scan_count, 1); - } - } - } - if (count_only) { - scan_in_progress = 0; - fb_copy_in_progress = 0; - return tile_count; - } - - if (xdamage_tile_count) { - /* pick up "known" damaged tiles we missed in scan_display() */ - for (i=0; i < ntiles; i++) { - if (tile_has_diff[i]) { - continue; - } - if (tile_has_xdamage_diff[i]) { - tile_has_diff[i] = 1; - if (tile_has_xdamage_diff[i] == 1) { - tile_has_xdamage_diff[i] = 2; - tile_count++; - } - } - } - } - if (dpy && use_xdamage == 1) { - static time_t last_xd_check = 0; - if (time(NULL) > last_xd_check + 2) { - int cp = (scan_count + 3) % NSCAN; - xd_do_check = 1; - tile_count = scan_display(scanlines[cp], 0); - xd_do_check = 0; - SCAN_FATAL(tile_count); - last_xd_check = time(NULL); - if (xd_samples > 200) { - static int bad = 0; - if (xd_misses > (20 * xd_samples) / 100) { - rfbLog("XDAMAGE is not working well... misses: %d/%d\n", xd_misses, xd_samples); - rfbLog("Maybe an OpenGL app like Beryl or Compiz is the problem?\n"); - rfbLog("Use x11vnc -noxdamage or disable the Beryl/Compiz app.\n"); - rfbLog("To disable this check and warning specify -xdamage twice.\n"); - if (++bad >= 10) { - rfbLog("XDAMAGE appears broken (OpenGL app?), turning it off.\n"); - use_xdamage = 0; - initialize_xdamage(); - destroy_xdamage_if_needed(); - } - } - xd_samples = 0; - xd_misses = 0; - } - } - } - - nap_set(tile_count); - - if (fs_factor && frac1 >= fs_frac) { - /* make frac1 < fs_frac if fullscreen updates are enabled */ - frac1 = fs_frac/2.0; - } - - if (tile_count > frac1 * ntiles) { - /* - * many tiles have changed, so try a rescan (since it should - * be short compared to the many upcoming copy_tiles() calls) - */ - - /* this check is done to skip the extra scan_display() call */ - if (! fs_factor || tile_count <= fs_frac * ntiles) { - int cp, tile_count_old = tile_count; - - /* choose a different y shift for the 2nd scan: */ - cp = (NSCAN - scan_count) % NSCAN; - - tile_count = scan_display(scanlines[cp], 1); - SCAN_FATAL(tile_count); - - 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); - } - } - scan_in_progress = 0; - - /* - * At some number of changed tiles it is better to just - * copy the full screen at once. I.e. time = c1 + m * r1 - * where m is number of tiles, r1 is the copy_tiles() - * time, and c1 is the scan_display() time: for some m - * it crosses the full screen update time. - * - * We try to predict that crossover with the fs_frac - * fudge factor... seems to be about 1/2 the total number - * of tiles. n.b. this ignores network bandwidth, - * compression time etc... - * - * Use -fs 1.0 to disable on slow links. - */ - if (fs_factor && tile_count > fs_frac * ntiles) { - int cs; - fb_copy_in_progress = 1; - cs = copy_screen(); - fb_copy_in_progress = 0; - SCAN_FATAL(cs); - if (use_threads && pointer_mode != 1) { - pointer_event(-1, 0, 0, NULL); - } - nap_check(tile_count); - return tile_count; - } - } - scan_in_progress = 0; - - /* copy all tiles with differences from display to rfb framebuffer: */ - fb_copy_in_progress = 1; - - if (single_copytile || tile_shm_count < ntiles_x) { - /* - * Old way, copy I/O one tile at a time. - */ - old_copy_tile = 1; - } else { - /* - * New way, does runs of horizontal tiles at once. - * Note that below, for simplicity, the extra tile finding - * (e.g. copy_tiles_backward_pass) is done the old way. - */ - old_copy_tile = 0; - } - - if (unixpw_in_progress) return 0; - -/* XXX Y */ -if (0 && tile_count > 20) print_tiles(); -#if 0 -dtmp = dnow(); -#else -dtmp = 0.0; -#endif - - if (old_copy_tile) { - tile_diffs = copy_all_tiles(); - } else { - tile_diffs = copy_all_tile_runs(); - } - SCAN_FATAL(tile_diffs); - -#if 0 -if (tile_count) fprintf(stderr, "XX copytile: %.4f tile_count: %d\n", dnow() - dtmp, tile_count); -#endif - - /* - * This backward pass for upward and left tiles complements what - * was done in copy_all_tiles() for downward and right tiles. - */ - tile_diffs = copy_tiles_backward_pass(); - SCAN_FATAL(tile_diffs); - - if (tile_diffs > frac3 * ntiles) { - /* - * we spent a lot of time in those copy_tiles, run - * another scan, maybe more of the screen changed. - */ - int cp = (NSCAN - scan_count + 13) % NSCAN; - - scan_in_progress = 1; - tile_count = scan_display(scanlines[cp], 1); - SCAN_FATAL(tile_count); - scan_in_progress = 0; - - tile_diffs = copy_tiles_additional_pass(); - SCAN_FATAL(tile_diffs); - } - - /* Given enough tile diffs, try the islands: */ - if (grow_fill && tile_diffs > 4) { - tile_diffs = grow_islands(); - } - SCAN_FATAL(tile_diffs); - - /* Given enough tile diffs, try the gaps: */ - if (gaps_fill && tile_diffs > 4) { - tile_diffs = fill_tile_gaps(); - } - SCAN_FATAL(tile_diffs); - - fb_copy_in_progress = 0; - if (use_threads && pointer_mode != 1) { - /* - * tell the pointer handler it can process any queued - * pointer events: - */ - pointer_event(-1, 0, 0, NULL); - } - - if (blackouts) { - /* ignore any diffs in completely covered tiles */ - int x, y, n; - for (y=0; y < ntiles_y; y++) { - for (x=0; x < ntiles_x; x++) { - n = x + y * ntiles_x; - if (tile_blackout[n].cover == 2) { - tile_has_diff[n] = 0; - } - } - } - } - - hint_updates(); /* use x0rfbserver hints algorithm */ - - /* Work around threaded rfbProcessClientMessage() calls timeouts */ - if (use_threads) { - ping_clients(tile_diffs); - } else if (saw_ultra_chat || saw_ultra_file) { - ping_clients(-1); - } else if (use_openssl && !tile_diffs) { - ping_clients(0); - } - /* -ping option: */ - if (ping_interval) { - int td = ping_interval > 0 ? ping_interval : -ping_interval; - ping_clients(-td); - } - - - nap_check(tile_diffs); - return tile_diffs; -} - - |