1 /* 2 Copyright (C) 2002-2010 Karl J. Runge <runge (at) karlrunge.com> 3 All rights reserved. 4 5 This file is part of x11vnc. 6 7 x11vnc is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or (at 10 your option) any later version. 11 12 x11vnc is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with x11vnc; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA 20 or see <http://www.gnu.org/licenses/>. 21 22 In addition, as a special exception, Karl J. Runge 23 gives permission to link the code of its release of x11vnc with the 24 OpenSSL project's "OpenSSL" library (or with modified versions of it 25 that use the same license as the "OpenSSL" library), and distribute 26 the linked executables. You must obey the GNU General Public License 27 in all respects for all of the code used other than "OpenSSL". If you 28 modify this file, you may extend this exception to your version of the 29 file, but you are not obligated to do so. If you do not wish to do 30 so, delete this exception statement from your version. 31 */ 32 33 /* -- scan.c -- */ 34 35 #include "x11vnc.h" 36 #include "xinerama.h" 37 #include "xwrappers.h" 38 #include "xdamage.h" 39 #include "xrandr.h" 40 #include "win_utils.h" 41 #include "8to24.h" 42 #include "screen.h" 43 #include "pointer.h" 44 #include "cleanup.h" 45 #include "unixpw.h" 46 #include "screen.h" 47 #include "macosx.h" 48 #include "userinput.h" 49 50 /* 51 * routines for scanning and reading the X11 display for changes, and 52 * for doing all the tile work (shm, etc). 53 */ 54 void initialize_tiles(void); 55 void free_tiles(void); 56 void shm_delete(XShmSegmentInfo *shm); 57 void shm_clean(XShmSegmentInfo *shm, XImage *xim); 58 void initialize_polling_images(void); 59 void scale_rect(double factor_x, double factor_y, int blend, int interpolate, int Bpp, 60 char *src_fb, int src_bytes_per_line, char *dst_fb, int dst_bytes_per_line, 61 int Nx, int Ny, int nx, int ny, int X1, int Y1, int X2, int Y2, int mark); 62 void scale_and_mark_rect(int X1, int Y1, int X2, int Y2, int mark); 63 void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force); 64 int copy_screen(void); 65 int copy_snap(void); 66 void nap_sleep(int ms, int split); 67 void set_offset(void); 68 int scan_for_updates(int count_only); 69 void rotate_curs(char *dst_0, char *src_0, int Dx, int Dy, int Bpp); 70 void rotate_coords(int x, int y, int *xo, int *yo, int dxi, int dyi); 71 void rotate_coords_inverse(int x, int y, int *xo, int *yo, int dxi, int dyi); 72 73 static void set_fs_factor(int max); 74 static char *flip_ximage_byte_order(XImage *xim); 75 static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, 76 char *name); 77 static void create_tile_hint(int x, int y, int tw, int th, hint_t *hint); 78 static void extend_tile_hint(int x, int y, int tw, int th, hint_t *hint); 79 static void save_hint(hint_t hint, int loc); 80 static void hint_updates(void); 81 static void mark_hint(hint_t hint); 82 static int copy_tiles(int tx, int ty, int nt); 83 static int copy_all_tiles(void); 84 static int copy_all_tile_runs(void); 85 static int copy_tiles_backward_pass(void); 86 static int copy_tiles_additional_pass(void); 87 static int gap_try(int x, int y, int *run, int *saw, int along_x); 88 static int fill_tile_gaps(void); 89 static int island_try(int x, int y, int u, int v, int *run); 90 static int grow_islands(void); 91 static void blackout_regions(void); 92 static void nap_set(int tile_cnt); 93 static void nap_check(int tile_cnt); 94 static void ping_clients(int tile_cnt); 95 static int blackout_line_skip(int n, int x, int y, int rescan, 96 int *tile_count); 97 static int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src, 98 int w, int pixelsize); 99 static int scan_display(int ystart, int rescan); 100 101 102 /* array to hold the hints: */ 103 static hint_t *hint_list; 104 105 /* nap state */ 106 int nap_ok = 0; 107 static int nap_diff_count = 0; 108 109 static int scan_count = 0; /* indicates which scan pattern we are on */ 110 static int scan_in_progress = 0; 111 112 113 typedef struct tile_change_region { 114 /* start and end lines, along y, of the changed area inside a tile. */ 115 unsigned short first_line, last_line; 116 short first_x, last_x; 117 /* info about differences along edges. */ 118 unsigned short left_diff, right_diff; 119 unsigned short top_diff, bot_diff; 120 } region_t; 121 122 /* array to hold the tiles region_t-s. */ 123 static region_t *tile_region; 124 125 126 127 128 /* 129 * setup tile numbers and allocate the tile and hint arrays: 130 */ 131 void initialize_tiles(void) { 132 133 ntiles_x = (dpy_x - 1)/tile_x + 1; 134 ntiles_y = (dpy_y - 1)/tile_y + 1; 135 ntiles = ntiles_x * ntiles_y; 136 137 tile_has_diff = (unsigned char *) 138 calloc((size_t) (ntiles * sizeof(unsigned char)), 1); 139 tile_has_xdamage_diff = (unsigned char *) 140 calloc((size_t) (ntiles * sizeof(unsigned char)), 1); 141 tile_row_has_xdamage_diff = (unsigned char *) 142 calloc((size_t) (ntiles_y * sizeof(unsigned char)), 1); 143 tile_tried = (unsigned char *) 144 calloc((size_t) (ntiles * sizeof(unsigned char)), 1); 145 tile_copied = (unsigned char *) 146 calloc((size_t) (ntiles * sizeof(unsigned char)), 1); 147 tile_blackout = (tile_blackout_t *) 148 calloc((size_t) (ntiles * sizeof(tile_blackout_t)), 1); 149 tile_region = (region_t *) calloc((size_t) (ntiles * sizeof(region_t)), 1); 150 151 tile_row = (XImage **) 152 calloc((size_t) ((ntiles_x + 1) * sizeof(XImage *)), 1); 153 tile_row_shm = (XShmSegmentInfo *) 154 calloc((size_t) ((ntiles_x + 1) * sizeof(XShmSegmentInfo)), 1); 155 156 /* there will never be more hints than tiles: */ 157 hint_list = (hint_t *) calloc((size_t) (ntiles * sizeof(hint_t)), 1); 158 } 159 160 void free_tiles(void) { 161 if (tile_has_diff) { 162 free(tile_has_diff); 163 tile_has_diff = NULL; 164 } 165 if (tile_has_xdamage_diff) { 166 free(tile_has_xdamage_diff); 167 tile_has_xdamage_diff = NULL; 168 } 169 if (tile_row_has_xdamage_diff) { 170 free(tile_row_has_xdamage_diff); 171 tile_row_has_xdamage_diff = NULL; 172 } 173 if (tile_tried) { 174 free(tile_tried); 175 tile_tried = NULL; 176 } 177 if (tile_copied) { 178 free(tile_copied); 179 tile_copied = NULL; 180 } 181 if (tile_blackout) { 182 free(tile_blackout); 183 tile_blackout = NULL; 184 } 185 if (tile_region) { 186 free(tile_region); 187 tile_region = NULL; 188 } 189 if (tile_row) { 190 free(tile_row); 191 tile_row = NULL; 192 } 193 if (tile_row_shm) { 194 free(tile_row_shm); 195 tile_row_shm = NULL; 196 } 197 if (hint_list) { 198 free(hint_list); 199 hint_list = NULL; 200 } 201 } 202 203 /* 204 * silly function to factor dpy_y until fullscreen shm is not bigger than max. 205 * should always work unless dpy_y is a large prime or something... under 206 * failure fs_factor remains 0 and no fullscreen updates will be tried. 207 */ 208 static int fs_factor = 0; 209 210 static void set_fs_factor(int max) { 211 int f, fac = 1, n = dpy_y; 212 213 fs_factor = 0; 214 if ((bpp/8) * dpy_x * dpy_y <= max) { 215 fs_factor = 1; 216 return; 217 } 218 for (f=2; f <= 101; f++) { 219 while (n % f == 0) { 220 n = n / f; 221 fac = fac * f; 222 if ( (bpp/8) * dpy_x * (dpy_y/fac) <= max ) { 223 fs_factor = fac; 224 return; 225 } 226 } 227 } 228 } 229 230 static char *flip_ximage_byte_order(XImage *xim) { 231 char *order; 232 if (xim->byte_order == LSBFirst) { 233 order = "MSBFirst"; 234 xim->byte_order = MSBFirst; 235 xim->bitmap_bit_order = MSBFirst; 236 } else { 237 order = "LSBFirst"; 238 xim->byte_order = LSBFirst; 239 xim->bitmap_bit_order = LSBFirst; 240 } 241 return order; 242 } 243 244 /* 245 * set up an XShm image, or if not using shm just create the XImage. 246 */ 247 static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, 248 char *name) { 249 250 XImage *xim; 251 static int reported_flip = 0; 252 int db = 0; 253 254 shm->shmid = -1; 255 shm->shmaddr = (char *) -1; 256 *ximg_ptr = NULL; 257 258 if (nofb) { 259 return 1; 260 } 261 262 X_LOCK; 263 264 if (! using_shm || xform24to32 || raw_fb) { 265 /* we only need the XImage created */ 266 xim = XCreateImage_wr(dpy, default_visual, depth, ZPixmap, 267 0, NULL, w, h, raw_fb ? 32 : BitmapPad(dpy), 0); 268 269 X_UNLOCK; 270 271 if (xim == NULL) { 272 rfbErr("XCreateImage(%s) failed.\n", name); 273 if (quiet) { 274 fprintf(stderr, "XCreateImage(%s) failed.\n", 275 name); 276 } 277 return 0; 278 } 279 if (db) fprintf(stderr, "shm_create simple %d %d\t%p %s\n", w, h, (void *)xim, name); 280 xim->data = (char *) malloc(xim->bytes_per_line * xim->height); 281 if (xim->data == NULL) { 282 rfbErr("XCreateImage(%s) data malloc failed.\n", name); 283 if (quiet) { 284 fprintf(stderr, "XCreateImage(%s) data malloc" 285 " failed.\n", name); 286 } 287 return 0; 288 } 289 if (flip_byte_order) { 290 char *order = flip_ximage_byte_order(xim); 291 if (! reported_flip && ! quiet) { 292 rfbLog("Changing XImage byte order" 293 " to %s\n", order); 294 reported_flip = 1; 295 } 296 } 297 298 *ximg_ptr = xim; 299 return 1; 300 } 301 302 if (! dpy) { 303 X_UNLOCK; 304 return 0; 305 } 306 307 xim = XShmCreateImage_wr(dpy, default_visual, depth, ZPixmap, NULL, 308 shm, w, h); 309 310 if (xim == NULL) { 311 rfbErr("XShmCreateImage(%s) failed.\n", name); 312 if (quiet) { 313 fprintf(stderr, "XShmCreateImage(%s) failed.\n", name); 314 } 315 X_UNLOCK; 316 return 0; 317 } 318 319 *ximg_ptr = xim; 320 321 #if LIBVNCSERVER_HAVE_XSHM 322 shm->shmid = shmget(IPC_PRIVATE, 323 xim->bytes_per_line * xim->height, IPC_CREAT | 0777); 324 325 if (shm->shmid == -1) { 326 rfbErr("shmget(%s) failed.\n", name); 327 rfbLogPerror("shmget"); 328 329 XDestroyImage(xim); 330 *ximg_ptr = NULL; 331 332 X_UNLOCK; 333 return 0; 334 } 335 336 shm->shmaddr = xim->data = (char *) shmat(shm->shmid, 0, 0); 337 338 if (shm->shmaddr == (char *)-1) { 339 rfbErr("shmat(%s) failed.\n", name); 340 rfbLogPerror("shmat"); 341 342 XDestroyImage(xim); 343 *ximg_ptr = NULL; 344 345 shmctl(shm->shmid, IPC_RMID, 0); 346 shm->shmid = -1; 347 348 X_UNLOCK; 349 return 0; 350 } 351 352 shm->readOnly = False; 353 354 if (! XShmAttach_wr(dpy, shm)) { 355 rfbErr("XShmAttach(%s) failed.\n", name); 356 XDestroyImage(xim); 357 *ximg_ptr = NULL; 358 359 shmdt(shm->shmaddr); 360 shm->shmaddr = (char *) -1; 361 362 shmctl(shm->shmid, IPC_RMID, 0); 363 shm->shmid = -1; 364 365 X_UNLOCK; 366 return 0; 367 } 368 #endif 369 370 X_UNLOCK; 371 return 1; 372 } 373 374 void shm_delete(XShmSegmentInfo *shm) { 375 #if LIBVNCSERVER_HAVE_XSHM 376 if (getenv("X11VNC_SHM_DEBUG")) fprintf(stderr, "shm_delete: %p\n", (void *) shm); 377 if (shm != NULL && shm->shmaddr != (char *) -1) { 378 shmdt(shm->shmaddr); 379 } 380 if (shm != NULL && shm->shmid != -1) { 381 shmctl(shm->shmid, IPC_RMID, 0); 382 } 383 if (shm != NULL) { 384 shm->shmaddr = (char *) -1; 385 shm->shmid = -1; 386 } 387 #else 388 if (!shm) {} 389 #endif 390 } 391 392 void shm_clean(XShmSegmentInfo *shm, XImage *xim) { 393 int db = 0; 394 395 if (db) fprintf(stderr, "shm_clean: called: %p\n", (void *)xim); 396 X_LOCK; 397 #if LIBVNCSERVER_HAVE_XSHM 398 if (shm != NULL && shm->shmid != -1 && dpy) { 399 if (db) fprintf(stderr, "shm_clean: XShmDetach_wr\n"); 400 XShmDetach_wr(dpy, shm); 401 } 402 #endif 403 if (xim != NULL) { 404 if (! raw_fb_back_to_X) { /* raw_fb hack */ 405 if (xim->bitmap_unit != -1) { 406 if (db) fprintf(stderr, "shm_clean: XDestroyImage %p\n", (void *)xim); 407 XDestroyImage(xim); 408 } else { 409 if (xim->data) { 410 if (db) fprintf(stderr, "shm_clean: free xim->data %p %p\n", (void *)xim, (void *)(xim->data)); 411 free(xim->data); 412 xim->data = NULL; 413 } 414 } 415 } 416 xim = NULL; 417 } 418 X_UNLOCK; 419 420 shm_delete(shm); 421 } 422 423 void initialize_polling_images(void) { 424 int i, MB = 1024 * 1024; 425 426 /* set all shm areas to "none" before trying to create any */ 427 scanline_shm.shmid = -1; 428 scanline_shm.shmaddr = (char *) -1; 429 scanline = NULL; 430 fullscreen_shm.shmid = -1; 431 fullscreen_shm.shmaddr = (char *) -1; 432 fullscreen = NULL; 433 snaprect_shm.shmid = -1; 434 snaprect_shm.shmaddr = (char *) -1; 435 snaprect = NULL; 436 for (i=1; i<=ntiles_x; i++) { 437 tile_row_shm[i].shmid = -1; 438 tile_row_shm[i].shmaddr = (char *) -1; 439 tile_row[i] = NULL; 440 } 441 442 /* the scanline (e.g. 1280x1) shared memory area image: */ 443 444 if (! shm_create(&scanline_shm, &scanline, dpy_x, 1, "scanline")) { 445 clean_up_exit(1); 446 } 447 448 /* 449 * the fullscreen (e.g. 1280x1024/fs_factor) shared memory area image: 450 * (we cut down the size of the shm area to try avoid and shm segment 451 * limits, e.g. the default 1MB on Solaris) 452 */ 453 if (UT.sysname && strstr(UT.sysname, "Linux")) { 454 set_fs_factor(10 * MB); 455 } else { 456 set_fs_factor(1 * MB); 457 } 458 if (fs_frac >= 1.0) { 459 fs_frac = 1.1; 460 fs_factor = 0; 461 } 462 if (! fs_factor) { 463 rfbLog("warning: fullscreen updates are disabled.\n"); 464 } else { 465 if (! shm_create(&fullscreen_shm, &fullscreen, dpy_x, 466 dpy_y/fs_factor, "fullscreen")) { 467 clean_up_exit(1); 468 } 469 } 470 if (use_snapfb) { 471 if (! fs_factor) { 472 rfbLog("warning: disabling -snapfb mode.\n"); 473 use_snapfb = 0; 474 } else if (! shm_create(&snaprect_shm, &snaprect, dpy_x, 475 dpy_y/fs_factor, "snaprect")) { 476 clean_up_exit(1); 477 } 478 } 479 480 /* 481 * for copy_tiles we need a lot of shared memory areas, one for 482 * each possible run length of changed tiles. 32 for 1024x768 483 * and 40 for 1280x1024, etc. 484 */ 485 486 tile_shm_count = 0; 487 for (i=1; i<=ntiles_x; i++) { 488 if (! shm_create(&tile_row_shm[i], &tile_row[i], tile_x * i, 489 tile_y, "tile_row")) { 490 if (i == 1) { 491 clean_up_exit(1); 492 } 493 rfbLog("shm: Error creating shared memory tile-row for" 494 " len=%d,\n", i); 495 rfbLog("shm: reverting to -onetile mode. If this" 496 " problem persists\n"); 497 rfbLog("shm: try using the -onetile or -noshm options" 498 " to limit\n"); 499 rfbLog("shm: shared memory usage, or run ipcrm(1)" 500 " to manually\n"); 501 rfbLog("shm: delete unattached shm segments.\n"); 502 single_copytile_count = i; 503 single_copytile = 1; 504 } 505 tile_shm_count++; 506 if (single_copytile && i >= 1) { 507 /* only need 1x1 tiles */ 508 break; 509 } 510 } 511 if (verbose) { 512 if (using_shm && ! xform24to32) { 513 rfbLog("created %d tile_row shm polling images.\n", 514 tile_shm_count); 515 } else { 516 rfbLog("created %d tile_row polling images.\n", 517 tile_shm_count); 518 } 519 } 520 } 521 522 /* 523 * A hint is a rectangular region built from 1 or more adjacent tiles 524 * glued together. Ultimately, this information in a single hint is sent 525 * to libvncserver rather than sending each tile separately. 526 */ 527 static void create_tile_hint(int x, int y, int tw, int th, hint_t *hint) { 528 int w = dpy_x - x; 529 int h = dpy_y - y; 530 531 if (w > tw) { 532 w = tw; 533 } 534 if (h > th) { 535 h = th; 536 } 537 538 hint->x = x; 539 hint->y = y; 540 hint->w = w; 541 hint->h = h; 542 } 543 544 static void extend_tile_hint(int x, int y, int tw, int th, hint_t *hint) { 545 int w = dpy_x - x; 546 int h = dpy_y - y; 547 548 if (w > tw) { 549 w = tw; 550 } 551 if (h > th) { 552 h = th; 553 } 554 555 if (hint->x > x) { /* extend to the left */ 556 hint->w += hint->x - x; 557 hint->x = x; 558 } 559 if (hint->y > y) { /* extend upward */ 560 hint->h += hint->y - y; 561 hint->y = y; 562 } 563 564 if (hint->x + hint->w < x + w) { /* extend to the right */ 565 hint->w = x + w - hint->x; 566 } 567 if (hint->y + hint->h < y + h) { /* extend downward */ 568 hint->h = y + h - hint->y; 569 } 570 } 571 572 static void save_hint(hint_t hint, int loc) { 573 /* simply copy it to the global array for later use. */ 574 hint_list[loc].x = hint.x; 575 hint_list[loc].y = hint.y; 576 hint_list[loc].w = hint.w; 577 hint_list[loc].h = hint.h; 578 } 579 580 /* 581 * Glue together horizontal "runs" of adjacent changed tiles into one big 582 * rectangle change "hint" to be passed to the vnc machinery. 583 */ 584 static void hint_updates(void) { 585 hint_t hint; 586 int x, y, i, n, ty, th, tx, tw; 587 int hint_count = 0, in_run = 0; 588 589 hint.x = hint.y = hint.w = hint.h = 0; 590 591 for (y=0; y < ntiles_y; y++) { 592 for (x=0; x < ntiles_x; x++) { 593 n = x + y * ntiles_x; 594 595 if (tile_has_diff[n]) { 596 ty = tile_region[n].first_line; 597 th = tile_region[n].last_line - ty + 1; 598 599 tx = tile_region[n].first_x; 600 tw = tile_region[n].last_x - tx + 1; 601 if (tx < 0) { 602 tx = 0; 603 tw = tile_x; 604 } 605 606 if (! in_run) { 607 create_tile_hint( x * tile_x + tx, 608 y * tile_y + ty, tw, th, &hint); 609 in_run = 1; 610 } else { 611 extend_tile_hint( x * tile_x + tx, 612 y * tile_y + ty, tw, th, &hint); 613 } 614 } else { 615 if (in_run) { 616 /* end of a row run of altered tiles: */ 617 save_hint(hint, hint_count++); 618 in_run = 0; 619 } 620 } 621 } 622 if (in_run) { /* save the last row run */ 623 save_hint(hint, hint_count++); 624 in_run = 0; 625 } 626 } 627 628 for (i=0; i < hint_count; i++) { 629 /* pass update info to vnc: */ 630 mark_hint(hint_list[i]); 631 } 632 } 633 634 /* 635 * kludge, simple ceil+floor for non-negative doubles: 636 */ 637 #define CEIL(x) ( (double) ((int) (x)) == (x) ? \ 638 (double) ((int) (x)) : (double) ((int) (x) + 1) ) 639 #define FLOOR(x) ( (double) ((int) (x)) ) 640 641 /* 642 * Scaling: 643 * 644 * For shrinking, a destination (scaled) pixel will correspond to more 645 * than one source (i.e. main fb) pixel. Think of an x-y plane made with 646 * graph paper. Each unit square in the graph paper (i.e. collection of 647 * points (x,y) such that N < x < N+1 and M < y < M+1, N and M integers) 648 * corresponds to one pixel in the unscaled fb. There is a solid 649 * color filling the inside of such a square. A scaled pixel has width 650 * 1/scale_fac, e.g. for "-scale 3/4" the width of the scaled pixel 651 * is 1.333. The area of this scaled pixel is 1.333 * 1.333 (so it 652 * obviously overlaps more than one source pixel, each which have area 1). 653 * 654 * We take the weight an unscaled pixel (source) contributes to a 655 * scaled pixel (destination) as simply proportional to the overlap area 656 * between the two pixels. One can then think of the value of the scaled 657 * pixel as an integral over the portion of the graph paper it covers. 658 * The thing being integrated is the color value of the unscaled source. 659 * That color value is constant over a graph paper square (source pixel), 660 * and changes discontinuously from one unit square to the next. 661 * 662 663 Here is an example for -scale 3/4, the solid lines are the source pixels 664 (graph paper unit squares), while the dotted lines denote the scaled 665 pixels (destination pixels): 666 667 0 1 4/3 2 8/3 3 4=12/3 668 |---------|--.------|------.--|---------|. 669 | | . | . | |. 670 | A | . B | . | |. 671 | | . | . | |. 672 | | . | . | |. 673 1 |---------|--.------|------.--|---------|. 674 4/3|.........|.........|.........|.........|. 675 | | . | . | |. 676 | C | . D | . | |. 677 | | . | . | |. 678 2 |---------|--.------|------.--|---------|. 679 | | . | . | |. 680 | | . | . | |. 681 8/3|.........|.........|.........|.........|. 682 | | . | . | |. 683 3 |---------|--.------|------.--|---------|. 684 685 So we see the first scaled pixel (0 < x < 4/3 and 0 < y < 4/3) mostly 686 overlaps with unscaled source pixel "A". The integration (averaging) 687 weights for this scaled pixel are: 688 689 A 1 690 B 1/3 691 C 1/3 692 D 1/9 693 694 * 695 * The Red, Green, and Blue color values must be averaged over separately 696 * otherwise you can get a complete mess (except in solid regions), 697 * because high order bits are averaged differently from the low order bits. 698 * 699 * So the algorithm is roughly: 700 * 701 * - Given as input a rectangle in the unscaled source fb with changes, 702 * find the rectangle of pixels this affects in the scaled destination fb. 703 * 704 * - For each of the affected scaled (dest) pixels, determine all of the 705 * unscaled (source) pixels it overlaps with. 706 * 707 * - Average those unscaled source values together, weighted by the area 708 * overlap with the destination pixel. Average R, G, B separately. 709 * 710 * - Take this average value and convert to a valid pixel value if 711 * necessary (e.g. rounding, shifting), and then insert it into the 712 * destination framebuffer as the pixel value. 713 * 714 * - On to the next destination pixel... 715 * 716 * ======================================================================== 717 * 718 * For expanding, e.g. -scale 1.1 (which we don't think people will do 719 * very often... or at least so we hope, the framebuffer can become huge) 720 * the situation is reversed and the destination pixel is smaller than a 721 * "graph paper" unit square (source pixel). Some destination pixels 722 * will be completely within a single unscaled source pixel. 723 * 724 * What we do here is a simple 4 point interpolation scheme: 725 * 726 * Let P00 be the source pixel closest to the destination pixel but with 727 * x and y values less than or equal to those of the destination pixel. 728 * (for simplicity, think of the upper left corner of a pixel defining the 729 * x,y location of the pixel, the center would work just as well). So it 730 * is the source pixel immediately to the upper left of the destination 731 * pixel. Let P10 be the source pixel one to the right of P00. Let P01 732 * be one down from P00. And let P11 be one down and one to the right 733 * of P00. They form a 2x2 square we will interpolate inside of. 734 * 735 * Let V00, V10, V01, and V11 be the color values of those 4 source 736 * pixels. Let dx be the displacement along x the destination pixel is 737 * from P00. Note: 0 <= dx < 1 by definition of P00. Similarly let 738 * dy be the displacement along y. The weighted average for the 739 * interpolation is: 740 * 741 * V_ave = V00 * (1 - dx) * (1 - dy) 742 * + V10 * dx * (1 - dy) 743 * + V01 * (1 - dx) * dy 744 * + V11 * dx * dy 745 * 746 * Note that the weights (1-dx)*(1-dy) + dx*(1-dy) + (1-dx)*dy + dx*dy 747 * automatically add up to 1. It is also nice that all the weights are 748 * positive (unsigned char stays unsigned char). The above formula can 749 * be motivated by doing two 1D interpolations along x: 750 * 751 * VA = V00 * (1 - dx) + V10 * dx 752 * VB = V01 * (1 - dx) + V11 * dx 753 * 754 * and then interpolating VA and VB along y: 755 * 756 * V_ave = VA * (1 - dy) + VB * dy 757 * 758 * VA 759 * v |<-dx->| 760 * -- V00 ------ V10 761 * dy | | 762 * -- | o...|... "o" denotes the position of the desired 763 * ^ | . | . destination pixel relative to the P00 764 * | . | . source pixel. 765 * V10 ----.- V11 . 766 * ........ 767 * | 768 * VB 769 * 770 * 771 * Of course R, G, B averages are done separately as in the shrinking 772 * case. This gives reasonable results, and the implementation for 773 * shrinking can simply be used with different choices for weights for 774 * the loop over the 4 pixels. 775 */ 776 777 void scale_rect(double factor_x, double factor_y, int blend, int interpolate, int Bpp, 778 char *src_fb, int src_bytes_per_line, char *dst_fb, int dst_bytes_per_line, 779 int Nx, int Ny, int nx, int ny, int X1, int Y1, int X2, int Y2, int mark) { 780 /* 781 * Notation: 782 * "i" an x pixel index in the destination (scaled) framebuffer 783 * "j" a y pixel index in the destination (scaled) framebuffer 784 * "I" an x pixel index in the source (un-scaled, i.e. main) framebuffer 785 * "J" a y pixel index in the source (un-scaled, i.e. main) framebuffer 786 * 787 * Similarly for nx, ny, Nx, Ny, etc. Lowercase: dest, Uppercase: source. 788 */ 789 int i, j, i1, i2, j1, j2; /* indices for scaled fb (dest) */ 790 int I, J, I1, I2, J1, J2; /* indices for main fb (source) */ 791 792 double w, wx, wy, wtot; /* pixel weights */ 793 794 double x1, y1, x2, y2; /* x-y coords for destination pixels edges */ 795 double dx, dy; /* size of destination pixel */ 796 double ddx=0, ddy=0; /* for interpolation expansion */ 797 798 char *src, *dest; /* pointers to the two framebuffers */ 799 800 801 unsigned short us = 0; 802 unsigned char uc = 0; 803 unsigned int ui = 0; 804 805 int use_noblend_shortcut = 1; 806 int shrink; /* whether shrinking or expanding */ 807 static int constant_weights = -1, mag_int = -1; 808 static int last_Nx = -1, last_Ny = -1, cnt = 0; 809 static double last_factor = -1.0; 810 int b, k; 811 double pixave[4]; /* for averaging pixel values */ 812 813 if (factor_x <= 1.0 && factor_y <= 1.0) { 814 shrink = 1; 815 } else { 816 shrink = 0; 817 } 818 819 /* 820 * N.B. width and height (real numbers) of a scaled pixel. 821 * both are > 1 (e.g. 1.333 for -scale 3/4) 822 * they should also be equal but we don't assume it. 823 * 824 * This new way is probably the best we can do, take the inverse 825 * of the scaling factor to double precision. 826 */ 827 dx = 1.0/factor_x; 828 dy = 1.0/factor_y; 829 830 /* 831 * There is some speedup if the pixel weights are constant, so 832 * let's special case these. 833 * 834 * If scale = 1/n and n divides Nx and Ny, the pixel weights 835 * are constant (e.g. 1/2 => equal on 2x2 square). 836 */ 837 if (factor_x != last_factor || Nx != last_Nx || Ny != last_Ny) { 838 constant_weights = -1; 839 mag_int = -1; 840 last_Nx = Nx; 841 last_Ny = Ny; 842 last_factor = factor_x; 843 } 844 if (constant_weights < 0 && factor_x != factor_y) { 845 constant_weights = 0; 846 mag_int = 0; 847 848 } else if (constant_weights < 0) { 849 int n = 0; 850 851 constant_weights = 0; 852 mag_int = 0; 853 854 for (i = 2; i<=128; i++) { 855 double test = ((double) 1)/ i; 856 double diff, eps = 1.0e-7; 857 diff = factor_x - test; 858 if (-eps < diff && diff < eps) { 859 n = i; 860 break; 861 } 862 } 863 if (! blend || ! shrink || interpolate) { 864 ; 865 } else if (n != 0) { 866 if (Nx % n == 0 && Ny % n == 0) { 867 static int didmsg = 0; 868 if (mark && ! didmsg) { 869 didmsg = 1; 870 rfbLog("scale_and_mark_rect: using " 871 "constant pixel weight speedup " 872 "for 1/%d\n", n); 873 } 874 constant_weights = 1; 875 } 876 } 877 878 n = 0; 879 for (i = 2; i<=32; i++) { 880 double test = (double) i; 881 double diff, eps = 1.0e-7; 882 diff = factor_x - test; 883 if (-eps < diff && diff < eps) { 884 n = i; 885 break; 886 } 887 } 888 if (! blend && factor_x > 1.0 && n) { 889 mag_int = n; 890 } 891 } 892 893 if (mark && factor_x > 1.0 && blend) { 894 /* 895 * kludge: correct for interpolating blurring leaking 896 * up or left 1 destination pixel. 897 */ 898 if (X1 > 0) X1--; 899 if (Y1 > 0) Y1--; 900 } 901 902 /* 903 * find the extent of the change the input rectangle induces in 904 * the scaled framebuffer. 905 */ 906 907 /* Left edges: find largest i such that i * dx <= X1 */ 908 i1 = FLOOR(X1/dx); 909 910 /* Right edges: find smallest i such that (i+1) * dx >= X2+1 */ 911 i2 = CEIL( (X2+1)/dx ) - 1; 912 913 /* To be safe, correct any overflows: */ 914 i1 = nfix(i1, nx); 915 i2 = nfix(i2, nx) + 1; /* add 1 to make a rectangle upper boundary */ 916 917 /* Repeat above for y direction: */ 918 j1 = FLOOR(Y1/dy); 919 j2 = CEIL( (Y2+1)/dy ) - 1; 920 921 j1 = nfix(j1, ny); 922 j2 = nfix(j2, ny) + 1; 923 924 /* 925 * special case integer magnification with no blending. 926 * vision impaired magnification usage is interested in this case. 927 */ 928 if (mark && ! blend && mag_int && Bpp != 3) { 929 int jmin, jmax, imin, imax; 930 931 /* outer loop over *source* pixels */ 932 for (J=Y1; J < Y2; J++) { 933 jmin = J * mag_int; 934 jmax = jmin + mag_int; 935 for (I=X1; I < X2; I++) { 936 /* extract value */ 937 src = src_fb + J*src_bytes_per_line + I*Bpp; 938 if (Bpp == 4) { 939 ui = *((unsigned int *)src); 940 } else if (Bpp == 2) { 941 us = *((unsigned short *)src); 942 } else if (Bpp == 1) { 943 uc = *((unsigned char *)src); 944 } 945 imin = I * mag_int; 946 imax = imin + mag_int; 947 /* inner loop over *dest* pixels */ 948 for (j=jmin; j<jmax; j++) { 949 dest = dst_fb + j*dst_bytes_per_line + imin*Bpp; 950 for (i=imin; i<imax; i++) { 951 if (Bpp == 4) { 952 *((unsigned int *)dest) = ui; 953 } else if (Bpp == 2) { 954 *((unsigned short *)dest) = us; 955 } else if (Bpp == 1) { 956 *((unsigned char *)dest) = uc; 957 } 958 dest += Bpp; 959 } 960 } 961 } 962 } 963 goto markit; 964 } 965 966 /* set these all to 1.0 to begin with */ 967 wx = 1.0; 968 wy = 1.0; 969 w = 1.0; 970 971 /* 972 * Loop over destination pixels in scaled fb: 973 */ 974 for (j=j1; j<j2; j++) { 975 y1 = j * dy; /* top edge */ 976 if (y1 > Ny - 1) { 977 /* can go over with dy = 1/scale_fac */ 978 y1 = Ny - 1; 979 } 980 y2 = y1 + dy; /* bottom edge */ 981 982 /* Find main fb indices covered by this dest pixel: */ 983 J1 = (int) FLOOR(y1); 984 J1 = nfix(J1, Ny); 985 986 if (shrink && ! interpolate) { 987 J2 = (int) CEIL(y2) - 1; 988 J2 = nfix(J2, Ny); 989 } else { 990 J2 = J1 + 1; /* simple interpolation */ 991 ddy = y1 - J1; 992 } 993 994 /* destination char* pointer: */ 995 dest = dst_fb + j*dst_bytes_per_line + i1*Bpp; 996 997 for (i=i1; i<i2; i++) { 998 999 x1 = i * dx; /* left edge */ 1000 if (x1 > Nx - 1) { 1001 /* can go over with dx = 1/scale_fac */ 1002 x1 = Nx - 1; 1003 } 1004 x2 = x1 + dx; /* right edge */ 1005 1006 cnt++; 1007 1008 /* Find main fb indices covered by this dest pixel: */ 1009 I1 = (int) FLOOR(x1); 1010 if (I1 >= Nx) I1 = Nx - 1; 1011 1012 if (! blend && use_noblend_shortcut) { 1013 /* 1014 * The noblend case involves no weights, 1015 * and 1 pixel, so just copy the value 1016 * directly. 1017 */ 1018 src = src_fb + J1*src_bytes_per_line + I1*Bpp; 1019 if (Bpp == 4) { 1020 *((unsigned int *)dest) 1021 = *((unsigned int *)src); 1022 } else if (Bpp == 2) { 1023 *((unsigned short *)dest) 1024 = *((unsigned short *)src); 1025 } else if (Bpp == 1) { 1026 *(dest) = *(src); 1027 } else if (Bpp == 3) { 1028 /* rare case */ 1029 for (k=0; k<=2; k++) { 1030 *(dest+k) = *(src+k); 1031 } 1032 } 1033 dest += Bpp; 1034 continue; 1035 } 1036 1037 if (shrink && ! interpolate) { 1038 I2 = (int) CEIL(x2) - 1; 1039 if (I2 >= Nx) I2 = Nx - 1; 1040 } else { 1041 I2 = I1 + 1; /* simple interpolation */ 1042 ddx = x1 - I1; 1043 } 1044 1045 /* Zero out accumulators for next pixel average: */ 1046 for (b=0; b<4; b++) { 1047 pixave[b] = 0.0; /* for RGB weighted sums */ 1048 } 1049 1050 /* 1051 * wtot is for accumulating the total weight. 1052 * It should always sum to 1/(scale_fac * scale_fac). 1053 */ 1054 wtot = 0.0; 1055 1056 /* 1057 * Loop over source pixels covered by this dest pixel. 1058 * 1059 * These "extra" loops over "J" and "I" make 1060 * the cache/cacheline performance unclear. 1061 * For example, will the data brought in from 1062 * src for j, i, and J=0 still be in the cache 1063 * after the J > 0 data have been accessed and 1064 * we are at j, i+1, J=0? The stride in J is 1065 * main_bytes_per_line, and so ~4 KB. 1066 * 1067 * Typical case when shrinking are 2x2 loop, so 1068 * just two lines to worry about. 1069 */ 1070 for (J=J1; J<=J2; J++) { 1071 /* see comments for I, x1, x2, etc. below */ 1072 if (constant_weights) { 1073 ; 1074 } else if (! blend) { 1075 if (J != J1) { 1076 continue; 1077 } 1078 wy = 1.0; 1079 1080 /* interpolation scheme: */ 1081 } else if (! shrink || interpolate) { 1082 if (J >= Ny) { 1083 continue; 1084 } else if (J == J1) { 1085 wy = 1.0 - ddy; 1086 } else if (J != J1) { 1087 wy = ddy; 1088 } 1089 1090 /* integration scheme: */ 1091 } else if (J < y1) { 1092 wy = J+1 - y1; 1093 } else if (J+1 > y2) { 1094 wy = y2 - J; 1095 } else { 1096 wy = 1.0; 1097 } 1098 1099 src = src_fb + J*src_bytes_per_line + I1*Bpp; 1100 1101 for (I=I1; I<=I2; I++) { 1102 1103 /* Work out the weight: */ 1104 1105 if (constant_weights) { 1106 ; 1107 } else if (! blend) { 1108 /* 1109 * Ugh, PseudoColor colormap is 1110 * bad news, to avoid random 1111 * colors just take the first 1112 * pixel. Or user may have 1113 * specified :nb to fraction. 1114 * The :fb will force blending 1115 * for this case. 1116 */ 1117 if (I != I1) { 1118 continue; 1119 } 1120 wx = 1.0; 1121 1122 /* interpolation scheme: */ 1123 } else if (! shrink || interpolate) { 1124 if (I >= Nx) { 1125 continue; /* off edge */ 1126 } else if (I == I1) { 1127 wx = 1.0 - ddx; 1128 } else if (I != I1) { 1129 wx = ddx; 1130 } 1131 1132 /* integration scheme: */ 1133 } else if (I < x1) { 1134 /* 1135 * source left edge (I) to the 1136 * left of dest left edge (x1): 1137 * fractional weight 1138 */ 1139 wx = I+1 - x1; 1140 } else if (I+1 > x2) { 1141 /* 1142 * source right edge (I+1) to the 1143 * right of dest right edge (x2): 1144 * fractional weight 1145 */ 1146 wx = x2 - I; 1147 } else { 1148 /* 1149 * source edges (I and I+1) completely 1150 * inside dest edges (x1 and x2): 1151 * full weight 1152 */ 1153 wx = 1.0; 1154 } 1155 1156 w = wx * wy; 1157 wtot += w; 1158 1159 /* 1160 * We average the unsigned char value 1161 * instead of char value: otherwise 1162 * the minimum (char 0) is right next 1163 * to the maximum (char -1)! This way 1164 * they are spread between 0 and 255. 1165 */ 1166 if (Bpp == 4) { 1167 /* unroll the loops, can give 20% */ 1168 pixave[0] += w * ((unsigned char) *(src )); 1169 pixave[1] += w * ((unsigned char) *(src+1)); 1170 pixave[2] += w * ((unsigned char) *(src+2)); 1171 pixave[3] += w * ((unsigned char) *(src+3)); 1172 } else if (Bpp == 2) { 1173 /* 1174 * 16bpp: trickier with green 1175 * split over two bytes, so we 1176 * use the masks: 1177 */ 1178 us = *((unsigned short *) src); 1179 pixave[0] += w*(us & main_red_mask); 1180 pixave[1] += w*(us & main_green_mask); 1181 pixave[2] += w*(us & main_blue_mask); 1182 } else if (Bpp == 1) { 1183 pixave[0] += w * 1184 ((unsigned char) *(src)); 1185 } else { 1186 for (b=0; b<Bpp; b++) { 1187 pixave[b] += w * 1188 ((unsigned char) *(src+b)); 1189 } 1190 } 1191 src += Bpp; 1192 } 1193 } 1194 1195 if (wtot <= 0.0) { 1196 wtot = 1.0; 1197 } 1198 wtot = 1.0/wtot; /* normalization factor */ 1199 1200 /* place weighted average pixel in the scaled fb: */ 1201 if (Bpp == 4) { 1202 *(dest ) = (char) (wtot * pixave[0]); 1203 *(dest+1) = (char) (wtot * pixave[1]); 1204 *(dest+2) = (char) (wtot * pixave[2]); 1205 *(dest+3) = (char) (wtot * pixave[3]); 1206 } else if (Bpp == 2) { 1207 /* 16bpp / 565 case: */ 1208 pixave[0] *= wtot; 1209 pixave[1] *= wtot; 1210 pixave[2] *= wtot; 1211 us = (main_red_mask & (int) pixave[0]) 1212 | (main_green_mask & (int) pixave[1]) 1213 | (main_blue_mask & (int) pixave[2]); 1214 *( (unsigned short *) dest ) = us; 1215 } else if (Bpp == 1) { 1216 *(dest) = (char) (wtot * pixave[0]); 1217 } else { 1218 for (b=0; b<Bpp; b++) { 1219 *(dest+b) = (char) (wtot * pixave[b]); 1220 } 1221 } 1222 dest += Bpp; 1223 } 1224 } 1225 markit: 1226 if (mark) { 1227 mark_rect_as_modified(i1, j1, i2, j2, 1); 1228 } 1229 } 1230 1231 /* 1232 Framebuffers data flow: 1233 1234 General case: 1235 -------- -------- -------- -------- 1236 ----- |8to24_fb| |main_fb | |snap_fb | | X | 1237 |rfbfb| <== | | <== | | <== | | <== | Server | 1238 ----- -------- -------- -------- -------- 1239 (to vnc) (optional) (usu = rfbfb) (optional) (read only) 1240 1241 8to24_fb mode will create side fbs: poll24_fb and poll8_fb for 1242 bookkeepping the different regions (merged into 8to24_fb). 1243 1244 Normal case: 1245 -------- -------- 1246 |main_fb | | X | 1247 |= rfb_fb| <== | Server | 1248 -------- -------- 1249 1250 Scaling case: 1251 -------- -------- 1252 ----- |main_fb | | X | 1253 |rfbfb| <== | | <== | Server | 1254 ----- -------- -------- 1255 1256 Webcam/video case: 1257 -------- -------- -------- 1258 |main_fb | |snap_fb | | Video | 1259 | | <== | | <== | device | 1260 -------- -------- -------- 1261 1262 If we ever do a -rr rotation/reflection tran, it probably should 1263 be done after any scaling (need a rr_fb for intermediate results) 1264 1265 -rr option: transformation: 1266 1267 none x -> x; 1268 y -> y; 1269 1270 x x -> w - x - 1; 1271 y -> y; 1272 1273 y x -> x; 1274 x -> h - y - 1; 1275 1276 xy x -> w - x - 1; 1277 y -> h - y - 1; 1278 1279 +90 x -> h - y - 1; 1280 y -> x; 1281 1282 +90x x -> y; 1283 y -> x; 1284 1285 +90y x -> h - y - 1; 1286 y -> w - x - 1; 1287 1288 -90 x -> y; 1289 y -> w - x - 1; 1290 1291 some aliases: 1292 1293 xy: yx, +180, -180, 180 1294 +90: 90 1295 +90x: 90x 1296 +90y: 90y 1297 -90: +270, 270 1298 */ 1299 1300 void scale_and_mark_rect(int X1, int Y1, int X2, int Y2, int mark) { 1301 char *dst_fb, *src_fb = main_fb; 1302 int dst_bpl, Bpp = bpp/8, fac = 1; 1303 1304 if (!screen || !rfb_fb || !main_fb) { 1305 return; 1306 } 1307 if (! screen->serverFormat.trueColour) { 1308 /* 1309 * PseudoColor colormap... blending leads to random colors. 1310 * User can override with ":fb" 1311 */ 1312 if (scaling_blend == 1) { 1313 /* :fb option sets it to 2 */ 1314 if (default_visual->class == StaticGray) { 1315 /* 1316 * StaticGray can be blended OK, otherwise 1317 * user can disable with :nb 1318 */ 1319 ; 1320 } else { 1321 scaling_blend = 0; 1322 } 1323 } 1324 } 1325 1326 if (cmap8to24 && cmap8to24_fb) { 1327 src_fb = cmap8to24_fb; 1328 if (scaling) { 1329 if (depth <= 8) { 1330 fac = 4; 1331 } else if (depth <= 16) { 1332 fac = 2; 1333 } 1334 } 1335 } 1336 dst_fb = rfb_fb; 1337 dst_bpl = rfb_bytes_per_line; 1338 1339 scale_rect(scale_fac_x, scale_fac_y, scaling_blend, scaling_interpolate, fac * Bpp, 1340 src_fb, fac * main_bytes_per_line, dst_fb, dst_bpl, dpy_x, dpy_y, 1341 scaled_x, scaled_y, X1, Y1, X2, Y2, mark); 1342 } 1343 1344 void rotate_coords(int x, int y, int *xo, int *yo, int dxi, int dyi) { 1345 int xi = x, yi = y; 1346 int Dx, Dy; 1347 1348 if (dxi >= 0) { 1349 Dx = dxi; 1350 Dy = dyi; 1351 } else if (scaling) { 1352 Dx = scaled_x; 1353 Dy = scaled_y; 1354 } else { 1355 Dx = dpy_x; 1356 Dy = dpy_y; 1357 } 1358 1359 /* ncache?? */ 1360 1361 if (rotating == ROTATE_NONE) { 1362 *xo = xi; 1363 *yo = yi; 1364 } else if (rotating == ROTATE_X) { 1365 *xo = Dx - xi - 1; 1366 *yo = yi; 1367 } else if (rotating == ROTATE_Y) { 1368 *xo = xi; 1369 *yo = Dy - yi - 1; 1370 } else if (rotating == ROTATE_XY) { 1371 *xo = Dx - xi - 1; 1372 *yo = Dy - yi - 1; 1373 } else if (rotating == ROTATE_90) { 1374 *xo = Dy - yi - 1; 1375 *yo = xi; 1376 } else if (rotating == ROTATE_90X) { 1377 *xo = yi; 1378 *yo = xi; 1379 } else if (rotating == ROTATE_90Y) { 1380 *xo = Dy - yi - 1; 1381 *yo = Dx - xi - 1; 1382 } else if (rotating == ROTATE_270) { 1383 *xo = yi; 1384 *yo = Dx - xi - 1; 1385 } 1386 } 1387 1388 void rotate_coords_inverse(int x, int y, int *xo, int *yo, int dxi, int dyi) { 1389 int xi = x, yi = y; 1390 1391 int Dx, Dy; 1392 1393 if (dxi >= 0) { 1394 Dx = dxi; 1395 Dy = dyi; 1396 } else if (scaling) { 1397 Dx = scaled_x; 1398 Dy = scaled_y; 1399 } else { 1400 Dx = dpy_x; 1401 Dy = dpy_y; 1402 } 1403 if (! rotating_same) { 1404 int t = Dx; 1405 Dx = Dy; 1406 Dy = t; 1407 } 1408 1409 if (rotating == ROTATE_NONE) { 1410 *xo = xi; 1411 *yo = yi; 1412 } else if (rotating == ROTATE_X) { 1413 *xo = Dx - xi - 1; 1414 *yo = yi; 1415 } else if (rotating == ROTATE_Y) { 1416 *xo = xi; 1417 *yo = Dy - yi - 1; 1418 } else if (rotating == ROTATE_XY) { 1419 *xo = Dx - xi - 1; 1420 *yo = Dy - yi - 1; 1421 } else if (rotating == ROTATE_90) { 1422 *xo = yi; 1423 *yo = Dx - xi - 1; 1424 } else if (rotating == ROTATE_90X) { 1425 *xo = yi; 1426 *yo = xi; 1427 } else if (rotating == ROTATE_90Y) { 1428 *xo = Dy - yi - 1; 1429 *yo = Dx - xi - 1; 1430 } else if (rotating == ROTATE_270) { 1431 *xo = Dy - yi - 1; 1432 *yo = xi; 1433 } 1434 } 1435 1436 /* unroll the Bpp loop to be used in each case: */ 1437 #define ROT_COPY \ 1438 src = src_0 + fbl*y + Bpp*x; \ 1439 dst = dst_0 + rbl*yn + Bpp*xn; \ 1440 if (Bpp == 1) { \ 1441 *(dst) = *(src); \ 1442 } else if (Bpp == 2) { \ 1443 *(dst+0) = *(src+0); \ 1444 *(dst+1) = *(src+1); \ 1445 } else if (Bpp == 3) { \ 1446 *(dst+0) = *(src+0); \ 1447 *(dst+1) = *(src+1); \ 1448 *(dst+2) = *(src+2); \ 1449 } else if (Bpp == 4) { \ 1450 *(dst+0) = *(src+0); \ 1451 *(dst+1) = *(src+1); \ 1452 *(dst+2) = *(src+2); \ 1453 *(dst+3) = *(src+3); \ 1454 } 1455 1456 void rotate_fb(int x1, int y1, int x2, int y2) { 1457 int x, y, xn, yn, r_x1, r_y1, r_x2, r_y2, Bpp = bpp/8; 1458 int fbl = rfb_bytes_per_line; 1459 int rbl = rot_bytes_per_line; 1460 int Dx, Dy; 1461 char *src, *dst; 1462 char *src_0 = rfb_fb; 1463 char *dst_0 = rot_fb; 1464 1465 if (! rotating || ! rot_fb) { 1466 return; 1467 } 1468 1469 if (scaling) { 1470 Dx = scaled_x; 1471 Dy = scaled_y; 1472 } else { 1473 Dx = dpy_x; 1474 Dy = dpy_y; 1475 } 1476 rotate_coords(x1, y1, &r_x1, &r_y1, -1, -1); 1477 rotate_coords(x2, y2, &r_x2, &r_y2, -1, -1); 1478 1479 dst = rot_fb; 1480 1481 if (rotating == ROTATE_X) { 1482 for (y = y1; y < y2; y++) { 1483 for (x = x1; x < x2; x++) { 1484 xn = Dx - x - 1; 1485 yn = y; 1486 ROT_COPY 1487 } 1488 } 1489 } else if (rotating == ROTATE_Y) { 1490 for (y = y1; y < y2; y++) { 1491 for (x = x1; x < x2; x++) { 1492 xn = x; 1493 yn = Dy - y - 1; 1494 ROT_COPY 1495 } 1496 } 1497 } else if (rotating == ROTATE_XY) { 1498 for (y = y1; y < y2; y++) { 1499 for (x = x1; x < x2; x++) { 1500 xn = Dx - x - 1; 1501 yn = Dy - y - 1; 1502 ROT_COPY 1503 } 1504 } 1505 } else if (rotating == ROTATE_90) { 1506 for (y = y1; y < y2; y++) { 1507 for (x = x1; x < x2; x++) { 1508 xn = Dy - y - 1; 1509 yn = x; 1510 ROT_COPY 1511 } 1512 } 1513 } else if (rotating == ROTATE_90X) { 1514 for (y = y1; y < y2; y++) { 1515 for (x = x1; x < x2; x++) { 1516 xn = y; 1517 yn = x; 1518 ROT_COPY 1519 } 1520 } 1521 } else if (rotating == ROTATE_90Y) { 1522 for (y = y1; y < y2; y++) { 1523 for (x = x1; x < x2; x++) { 1524 xn = Dy - y - 1; 1525 yn = Dx - x - 1; 1526 ROT_COPY 1527 } 1528 } 1529 } else if (rotating == ROTATE_270) { 1530 for (y = y1; y < y2; y++) { 1531 for (x = x1; x < x2; x++) { 1532 xn = y; 1533 yn = Dx - x - 1; 1534 ROT_COPY 1535 } 1536 } 1537 } 1538 } 1539 1540 void rotate_curs(char *dst_0, char *src_0, int Dx, int Dy, int Bpp) { 1541 int x, y, xn, yn; 1542 char *src, *dst; 1543 int fbl, rbl; 1544 1545 if (! rotating) { 1546 return; 1547 } 1548 1549 fbl = Dx * Bpp; 1550 if (rotating_same) { 1551 rbl = Dx * Bpp; 1552 } else { 1553 rbl = Dy * Bpp; 1554 } 1555 1556 if (rotating == ROTATE_X) { 1557 for (y = 0; y < Dy; y++) { 1558 for (x = 0; x < Dx; x++) { 1559 xn = Dx - x - 1; 1560 yn = y; 1561 ROT_COPY 1562 if (0) fprintf(stderr, "rcurs: %d %d %d %d\n", x, y, xn, yn); 1563 } 1564 } 1565 } else if (rotating == ROTATE_Y) { 1566 for (y = 0; y < Dy; y++) { 1567 for (x = 0; x < Dx; x++) { 1568 xn = x; 1569 yn = Dy - y - 1; 1570 ROT_COPY 1571 } 1572 } 1573 } else if (rotating == ROTATE_XY) { 1574 for (y = 0; y < Dy; y++) { 1575 for (x = 0; x < Dx; x++) { 1576 xn = Dx - x - 1; 1577 yn = Dy - y - 1; 1578 ROT_COPY 1579 } 1580 } 1581 } else if (rotating == ROTATE_90) { 1582 for (y = 0; y < Dy; y++) { 1583 for (x = 0; x < Dx; x++) { 1584 xn = Dy - y - 1; 1585 yn = x; 1586 ROT_COPY 1587 } 1588 } 1589 } else if (rotating == ROTATE_90X) { 1590 for (y = 0; y < Dy; y++) { 1591 for (x = 0; x < Dx; x++) { 1592 xn = y; 1593 yn = x; 1594 ROT_COPY 1595 } 1596 } 1597 } else if (rotating == ROTATE_90Y) { 1598 for (y = 0; y < Dy; y++) { 1599 for (x = 0; x < Dx; x++) { 1600 xn = Dy - y - 1; 1601 yn = Dx - x - 1; 1602 ROT_COPY 1603 } 1604 } 1605 } else if (rotating == ROTATE_270) { 1606 for (y = 0; y < Dy; y++) { 1607 for (x = 0; x < Dx; x++) { 1608 xn = y; 1609 yn = Dx - x - 1; 1610 ROT_COPY 1611 } 1612 } 1613 } 1614 } 1615 1616 void mark_wrapper(int x1, int y1, int x2, int y2) { 1617 int t, r_x1 = x1, r_y1 = y1, r_x2 = x2, r_y2 = y2; 1618 1619 if (rotating) { 1620 /* well we hope rot_fb will always be the last one... */ 1621 rotate_coords(x1, y1, &r_x1, &r_y1, -1, -1); 1622 rotate_coords(x2, y2, &r_x2, &r_y2, -1, -1); 1623 rotate_fb(x1, y1, x2, y2); 1624 if (r_x1 > r_x2) { 1625 t = r_x1; 1626 r_x1 = r_x2; 1627 r_x2 = t; 1628 } 1629 if (r_y1 > r_y2) { 1630 t = r_y1; 1631 r_y1 = r_y2; 1632 r_y2 = t; 1633 } 1634 /* painting errors */ 1635 r_x1--; 1636 r_x2++; 1637 r_y1--; 1638 r_y2++; 1639 } 1640 rfbMarkRectAsModified(screen, r_x1, r_y1, r_x2, r_y2); 1641 } 1642 1643 void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force) { 1644 1645 if (damage_time != 0) { 1646 /* 1647 * This is not XDAMAGE, rather a hack for testing 1648 * where we allow the framebuffer to be corrupted for 1649 * damage_delay seconds. 1650 */ 1651 int debug = 0; 1652 if (time(NULL) > damage_time + damage_delay) { 1653 if (! quiet) { 1654 rfbLog("damaging turned off.\n"); 1655 } 1656 damage_time = 0; 1657 damage_delay = 0; 1658 } else { 1659 if (debug) { 1660 rfbLog("damaging viewer fb by not marking " 1661 "rect: %d,%d,%d,%d\n", x1, y1, x2, y2); 1662 } 1663 return; 1664 } 1665 } 1666 1667 1668 if (rfb_fb == main_fb || force) { 1669 mark_wrapper(x1, y1, x2, y2); 1670 return; 1671 } 1672 1673 if (cmap8to24) { 1674 bpp8to24(x1, y1, x2, y2); 1675 } 1676 1677 if (scaling) { 1678 scale_and_mark_rect(x1, y1, x2, y2, 1); 1679 } else { 1680 mark_wrapper(x1, y1, x2, y2); 1681 } 1682 } 1683 1684 /* 1685 * Notifies libvncserver of a changed hint rectangle. 1686 */ 1687 static void mark_hint(hint_t hint) { 1688 int x = hint.x; 1689 int y = hint.y; 1690 int w = hint.w; 1691 int h = hint.h; 1692 1693 mark_rect_as_modified(x, y, x + w, y + h, 0); 1694 } 1695 1696 /* 1697 * copy_tiles() gives a slight improvement over copy_tile() since 1698 * adjacent runs of tiles are done all at once there is some savings 1699 * due to contiguous memory access. Not a great speedup, but in some 1700 * cases it can be up to 2X. Even more on a SunRay or ShadowFB where 1701 * no graphics hardware is involved in the read. Generally, graphics 1702 * devices are optimized for write, not read, so we are limited by the 1703 * read bandwidth, sometimes only 5 MB/sec on otherwise fast hardware. 1704 */ 1705 static int *first_line = NULL, *last_line = NULL; 1706 static unsigned short *left_diff = NULL, *right_diff = NULL; 1707 1708 static int copy_tiles(int tx, int ty, int nt) { 1709 int x, y, line; 1710 int size_x, size_y, width1, width2; 1711 int off, len, n, dw, dx, t; 1712 int w1, w2, dx1, dx2; /* tmps for normal and short tiles */ 1713 int pixelsize = bpp/8; 1714 int first_min, last_max; 1715 int first_x = -1, last_x = -1; 1716 static int prev_ntiles_x = -1; 1717 1718 char *src, *dst, *s_src, *s_dst, *m_src, *m_dst; 1719 char *h_src, *h_dst; 1720 if (unixpw_in_progress) return 0; 1721 1722 if (ntiles_x != prev_ntiles_x && first_line != NULL) { 1723 free(first_line); first_line = NULL; 1724 free(last_line); last_line = NULL; 1725 free(left_diff); left_diff = NULL; 1726 free(right_diff); right_diff = NULL; 1727 } 1728 1729 if (first_line == NULL) { 1730 /* allocate arrays first time in. */ 1731 int n = ntiles_x + 1; 1732 rfbLog("copy_tiles: allocating first_line at size %d\n", n); 1733 first_line = (int *) malloc((size_t) (n * sizeof(int))); 1734 last_line = (int *) malloc((size_t) (n * sizeof(int))); 1735 left_diff = (unsigned short *) 1736 malloc((size_t) (n * sizeof(unsigned short))); 1737 right_diff = (unsigned short *) 1738 malloc((size_t) (n * sizeof(unsigned short))); 1739 } 1740 prev_ntiles_x = ntiles_x; 1741 1742 x = tx * tile_x; 1743 y = ty * tile_y; 1744 1745 size_x = dpy_x - x; 1746 if ( size_x > tile_x * nt ) { 1747 size_x = tile_x * nt; 1748 width1 = tile_x; 1749 width2 = tile_x; 1750 } else { 1751 /* short tile */ 1752 width1 = tile_x; /* internal tile */ 1753 width2 = size_x - (nt - 1) * tile_x; /* right hand tile */ 1754 } 1755 1756 size_y = dpy_y - y; 1757 if ( size_y > tile_y ) { 1758 size_y = tile_y; 1759 } 1760 1761 n = tx + ty * ntiles_x; /* number of the first tile */ 1762 1763 if (blackouts && tile_blackout[n].cover == 2) { 1764 /* 1765 * If there are blackouts and this tile is completely covered 1766 * no need to poll screen or do anything else.. 1767 * n.b. we are in single copy_tile mode: nt=1 1768 */ 1769 tile_has_diff[n] = 0; 1770 return(0); 1771 } 1772 1773 X_LOCK; 1774 XRANDR_SET_TRAP_RET(-1, "copy_tile-set"); 1775 /* read in the whole tile run at once: */ 1776 copy_image(tile_row[nt], x, y, size_x, size_y); 1777 XRANDR_CHK_TRAP_RET(-1, "copy_tile-chk"); 1778 1779 1780 X_UNLOCK; 1781 1782 if (blackouts && tile_blackout[n].cover == 1) { 1783 /* 1784 * If there are blackouts and this tile is partially covered 1785 * we should re-black-out the portion. 1786 * n.b. we are in single copy_tile mode: nt=1 1787 */ 1788 int x1, x2, y1, y2, b; 1789 int w, s, fill = 0; 1790 1791 for (b=0; b < tile_blackout[n].count; b++) { 1792 char *b_dst = tile_row[nt]->data; 1793 1794 x1 = tile_blackout[n].bo[b].x1 - x; 1795 y1 = tile_blackout[n].bo[b].y1 - y; 1796 x2 = tile_blackout[n].bo[b].x2 - x; 1797 y2 = tile_blackout[n].bo[b].y2 - y; 1798 1799 w = (x2 - x1) * pixelsize; 1800 s = x1 * pixelsize; 1801 1802 for (line = 0; line < size_y; line++) { 1803 if (y1 <= line && line < y2) { 1804 memset(b_dst + s, fill, (size_t) w); 1805 } 1806 b_dst += tile_row[nt]->bytes_per_line; 1807 } 1808 } 1809 } 1810 1811 src = tile_row[nt]->data; 1812 dst = main_fb + y * main_bytes_per_line + x * pixelsize; 1813 1814 s_src = src; 1815 s_dst = dst; 1816 1817 for (t=1; t <= nt; t++) { 1818 first_line[t] = -1; 1819 } 1820 1821 /* find the first line with difference: */ 1822 w1 = width1 * pixelsize; 1823 w2 = width2 * pixelsize; 1824 1825 /* foreach line: */ 1826 for (line = 0; line < size_y; line++) { 1827 /* foreach horizontal tile: */ 1828 for (t=1; t <= nt; t++) { 1829 if (first_line[t] != -1) { 1830 continue; 1831 } 1832 1833 off = (t-1) * w1; 1834 if (t == nt) { 1835 len = w2; /* possible short tile */ 1836 } else { 1837 len = w1; 1838 } 1839 1840 if (memcmp(s_dst + off, s_src + off, len)) { 1841 first_line[t] = line; 1842 } 1843 } 1844 s_src += tile_row[nt]->bytes_per_line; 1845 s_dst += main_bytes_per_line; 1846 } 1847 1848 /* see if there were any differences for any tile: */ 1849 first_min = -1; 1850 for (t=1; t <= nt; t++) { 1851 tile_tried[n+(t-1)] = 1; 1852 if (first_line[t] != -1) { 1853 if (first_min == -1 || first_line[t] < first_min) { 1854 first_min = first_line[t]; 1855 } 1856 } 1857 } 1858 if (first_min == -1) { 1859 /* no tile has a difference, note this and get out: */ 1860 for (t=1; t <= nt; t++) { 1861 tile_has_diff[n+(t-1)] = 0; 1862 } 1863 return(0); 1864 } else { 1865 /* 1866 * at least one tile has a difference. make sure info 1867 * is recorded (e.g. sometimes we guess tiles and they 1868 * came in with tile_has_diff 0) 1869 */ 1870 for (t=1; t <= nt; t++) { 1871 if (first_line[t] == -1) { 1872 tile_has_diff[n+(t-1)] = 0; 1873 } else { 1874 tile_has_diff[n+(t-1)] = 1; 1875 } 1876 } 1877 } 1878 1879 m_src = src + (tile_row[nt]->bytes_per_line * size_y); 1880 m_dst = dst + (main_bytes_per_line * size_y); 1881 1882 for (t=1; t <= nt; t++) { 1883 last_line[t] = first_line[t]; 1884 } 1885 1886 /* find the last line with difference: */ 1887 w1 = width1 * pixelsize; 1888 w2 = width2 * pixelsize; 1889 1890 /* foreach line: */ 1891 for (line = size_y - 1; line > first_min; line--) { 1892 1893 m_src -= tile_row[nt]->bytes_per_line; 1894 m_dst -= main_bytes_per_line; 1895 1896 /* foreach tile: */ 1897 for (t=1; t <= nt; t++) { 1898 if (first_line[t] == -1 1899 || last_line[t] != first_line[t]) { 1900 /* tile has no changes or already done */ 1901 continue; 1902 } 1903 1904 off = (t-1) * w1; 1905 if (t == nt) { 1906 len = w2; /* possible short tile */ 1907 } else { 1908 len = w1; 1909 } 1910 if (memcmp(m_dst + off, m_src + off, len)) { 1911 last_line[t] = line; 1912 } 1913 } 1914 } 1915 1916 /* 1917 * determine the farthest down last changed line 1918 * will be used below to limit our memcpy() to the framebuffer. 1919 */ 1920 last_max = -1; 1921 for (t=1; t <= nt; t++) { 1922 if (first_line[t] == -1) { 1923 continue; 1924 } 1925 if (last_max == -1 || last_line[t] > last_max) { 1926 last_max = last_line[t]; 1927 } 1928 } 1929 1930 /* look for differences on left and right hand edges: */ 1931 for (t=1; t <= nt; t++) { 1932 left_diff[t] = 0; 1933 right_diff[t] = 0; 1934 } 1935 1936 h_src = src; 1937 h_dst = dst; 1938 1939 w1 = width1 * pixelsize; 1940 w2 = width2 * pixelsize; 1941 1942 dx1 = (width1 - tile_fuzz) * pixelsize; 1943 dx2 = (width2 - tile_fuzz) * pixelsize; 1944 dw = tile_fuzz * pixelsize; 1945 1946 /* foreach line: */ 1947 for (line = 0; line < size_y; line++) { 1948 /* foreach tile: */ 1949 for (t=1; t <= nt; t++) { 1950 if (first_line[t] == -1) { 1951 /* tile has no changes at all */ 1952 continue; 1953 } 1954 1955 off = (t-1) * w1; 1956 if (t == nt) { 1957 dx = dx2; /* possible short tile */ 1958 if (dx <= 0) { 1959 break; 1960 } 1961 } else { 1962 dx = dx1; 1963 } 1964 1965 if (! left_diff[t] && memcmp(h_dst + off, 1966 h_src + off, dw)) { 1967 left_diff[t] = 1; 1968 } 1969 if (! right_diff[t] && memcmp(h_dst + off + dx, 1970 h_src + off + dx, dw) ) { 1971 right_diff[t] = 1; 1972 } 1973 } 1974 h_src += tile_row[nt]->bytes_per_line; 1975 h_dst += main_bytes_per_line; 1976 } 1977 1978 /* now finally copy the difference to the rfb framebuffer: */ 1979 s_src = src + tile_row[nt]->bytes_per_line * first_min; 1980 s_dst = dst + main_bytes_per_line * first_min; 1981 1982 for (line = first_min; line <= last_max; line++) { 1983 /* for I/O speed we do not do this tile by tile */ 1984 memcpy(s_dst, s_src, size_x * pixelsize); 1985 if (nt == 1) { 1986 /* 1987 * optimization for tall skinny lines, e.g. wm 1988 * frame. try to find first_x and last_x to limit 1989 * the size of the hint. could help for a slow 1990 * link. Unfortunately we spent a lot of time 1991 * reading in the many tiles. 1992 * 1993 * BTW, we like to think the above memcpy leaves 1994 * the data we use below in the cache... (but 1995 * it could be two 128 byte segments at 32bpp) 1996 * so this inner loop is not as bad as it seems. 1997 */ 1998 int k, kx; 1999 kx = pixelsize; 2000 for (k=0; k<size_x; k++) { 2001 if (memcmp(s_dst + k*kx, s_src + k*kx, kx)) { 2002 if (first_x == -1 || k < first_x) { 2003 first_x = k; 2004 } 2005 if (last_x == -1 || k > last_x) { 2006 last_x = k; 2007 } 2008 } 2009 } 2010 } 2011 s_src += tile_row[nt]->bytes_per_line; 2012 s_dst += main_bytes_per_line; 2013 } 2014 2015 /* record all the info in the region array for this tile: */ 2016 for (t=1; t <= nt; t++) { 2017 int s = t - 1; 2018 2019 if (first_line[t] == -1) { 2020 /* tile unchanged */ 2021 continue; 2022 } 2023 tile_region[n+s].first_line = first_line[t]; 2024 tile_region[n+s].last_line = last_line[t]; 2025 2026 tile_region[n+s].first_x = first_x; 2027 tile_region[n+s].last_x = last_x; 2028 2029 tile_region[n+s].top_diff = 0; 2030 tile_region[n+s].bot_diff = 0; 2031 if ( first_line[t] < tile_fuzz ) { 2032 tile_region[n+s].top_diff = 1; 2033 } 2034 if ( last_line[t] > (size_y - 1) - tile_fuzz ) { 2035 tile_region[n+s].bot_diff = 1; 2036 } 2037 2038 tile_region[n+s].left_diff = left_diff[t]; 2039 tile_region[n+s].right_diff = right_diff[t]; 2040 2041 tile_copied[n+s] = 1; 2042 } 2043 2044 return(1); 2045 } 2046 2047 /* 2048 * The copy_tile() call in the loop below copies the changed tile into 2049 * the rfb framebuffer. Note that copy_tile() sets the tile_region 2050 * struct to have info about the y-range of the changed region and also 2051 * whether the tile edges contain diffs (within distance tile_fuzz). 2052 * 2053 * We use this tile_region info to try to guess if the downward and right 2054 * tiles will have diffs. These tiles will be checked later in the loop 2055 * (since y+1 > y and x+1 > x). 2056 * 2057 * See copy_tiles_backward_pass() for analogous checking upward and 2058 * left tiles. 2059 */ 2060 static int copy_all_tiles(void) { 2061 int x, y, n, m; 2062 int diffs = 0, ct; 2063 2064 if (unixpw_in_progress) return 0; 2065 2066 for (y=0; y < ntiles_y; y++) { 2067 for (x=0; x < ntiles_x; x++) { 2068 n = x + y * ntiles_x; 2069 2070 if (tile_has_diff[n]) { 2071 ct = copy_tiles(x, y, 1); 2072 if (ct < 0) return ct; /* fatal */ 2073 } 2074 if (! tile_has_diff[n]) { 2075 /* 2076 * n.b. copy_tiles() may have detected 2077 * no change and reset tile_has_diff to 0. 2078 */ 2079 continue; 2080 } 2081 diffs++; 2082 2083 /* neighboring tile downward: */ 2084 if ( (y+1) < ntiles_y && tile_region[n].bot_diff) { 2085 m = x + (y+1) * ntiles_x; 2086 if (! tile_has_diff[m]) { 2087 tile_has_diff[m] = 2; 2088 } 2089 } 2090 /* neighboring tile to right: */ 2091 if ( (x+1) < ntiles_x && tile_region[n].right_diff) { 2092 m = (x+1) + y * ntiles_x; 2093 if (! tile_has_diff[m]) { 2094 tile_has_diff[m] = 2; 2095 } 2096 } 2097 } 2098 } 2099 return diffs; 2100 } 2101 2102 /* 2103 * Routine analogous to copy_all_tiles() above, but for horizontal runs 2104 * of adjacent changed tiles. 2105 */ 2106 static int copy_all_tile_runs(void) { 2107 int x, y, n, m, i; 2108 int diffs = 0, ct; 2109 int in_run = 0, run = 0; 2110 int ntave = 0, ntcnt = 0; 2111 2112 if (unixpw_in_progress) return 0; 2113 2114 for (y=0; y < ntiles_y; y++) { 2115 for (x=0; x < ntiles_x + 1; x++) { 2116 n = x + y * ntiles_x; 2117 2118 if (x != ntiles_x && tile_has_diff[n]) { 2119 in_run = 1; 2120 run++; 2121 } else { 2122 if (! in_run) { 2123 in_run = 0; 2124 run = 0; 2125 continue; 2126 } 2127 ct = copy_tiles(x - run, y, run); 2128 if (ct < 0) return ct; /* fatal */ 2129 2130 ntcnt++; 2131 ntave += run; 2132 diffs += run; 2133 2134 /* neighboring tile downward: */ 2135 for (i=1; i <= run; i++) { 2136 if ((y+1) < ntiles_y 2137 && tile_region[n-i].bot_diff) { 2138 m = (x-i) + (y+1) * ntiles_x; 2139 if (! tile_has_diff[m]) { 2140 tile_has_diff[m] = 2; 2141 } 2142 } 2143 } 2144 2145 /* neighboring tile to right: */ 2146 if (((x-1)+1) < ntiles_x 2147 && tile_region[n-1].right_diff) { 2148 m = ((x-1)+1) + y * ntiles_x; 2149 if (! tile_has_diff[m]) { 2150 tile_has_diff[m] = 2; 2151 } 2152 2153 /* note that this starts a new run */ 2154 in_run = 1; 2155 run = 1; 2156 } else { 2157 in_run = 0; 2158 run = 0; 2159 } 2160 } 2161 } 2162 /* 2163 * Could some activity go here, to emulate threaded 2164 * behavior by servicing some libvncserver tasks? 2165 */ 2166 } 2167 return diffs; 2168 } 2169 2170 /* 2171 * Here starts a bunch of heuristics to guess/detect changed tiles. 2172 * They are: 2173 * copy_tiles_backward_pass, fill_tile_gaps/gap_try, grow_islands/island_try 2174 */ 2175 2176 /* 2177 * Try to predict whether the upward and/or leftward tile has been modified. 2178 * copy_all_tiles() has already done downward and rightward tiles. 2179 */ 2180 static int copy_tiles_backward_pass(void) { 2181 int x, y, n, m; 2182 int diffs = 0, ct; 2183 2184 if (unixpw_in_progress) return 0; 2185 2186 for (y = ntiles_y - 1; y >= 0; y--) { 2187 for (x = ntiles_x - 1; x >= 0; x--) { 2188 n = x + y * ntiles_x; /* number of this tile */ 2189 2190 if (! tile_has_diff[n]) { 2191 continue; 2192 } 2193 2194 m = x + (y-1) * ntiles_x; /* neighboring tile upward */ 2195 2196 if (y >= 1 && ! tile_has_diff[m] && tile_region[n].top_diff) { 2197 if (! tile_tried[m]) { 2198 tile_has_diff[m] = 2; 2199 ct = copy_tiles(x, y-1, 1); 2200 if (ct < 0) return ct; /* fatal */ 2201 } 2202 } 2203 2204 m = (x-1) + y * ntiles_x; /* neighboring tile to left */ 2205 2206 if (x >= 1 && ! tile_has_diff[m] && tile_region[n].left_diff) { 2207 if (! tile_tried[m]) { 2208 tile_has_diff[m] = 2; 2209 ct = copy_tiles(x-1, y, 1); 2210 if (ct < 0) return ct; /* fatal */ 2211 } 2212 } 2213 } 2214 } 2215 for (n=0; n < ntiles; n++) { 2216 if (tile_has_diff[n]) { 2217 diffs++; 2218 } 2219 } 2220 return diffs; 2221 } 2222 2223 static int copy_tiles_additional_pass(void) { 2224 int x, y, n; 2225 int diffs = 0, ct; 2226 2227 if (unixpw_in_progress) return 0; 2228 2229 for (y=0; y < ntiles_y; y++) { 2230 for (x=0; x < ntiles_x; x++) { 2231 n = x + y * ntiles_x; /* number of this tile */ 2232 2233 if (! tile_has_diff[n]) { 2234 continue; 2235 } 2236 if (tile_copied[n]) { 2237 continue; 2238 } 2239 2240 ct = copy_tiles(x, y, 1); 2241 if (ct < 0) return ct; /* fatal */ 2242 } 2243 } 2244 for (n=0; n < ntiles; n++) { 2245 if (tile_has_diff[n]) { 2246 diffs++; 2247 } 2248 } 2249 return diffs; 2250 } 2251 2252 static int gap_try(int x, int y, int *run, int *saw, int along_x) { 2253 int n, m, i, xt, yt, ct; 2254 2255 n = x + y * ntiles_x; 2256 2257 if (! tile_has_diff[n]) { 2258 if (*saw) { 2259 (*run)++; /* extend the gap run. */ 2260 } 2261 return 0; 2262 } 2263 if (! *saw || *run == 0 || *run > gaps_fill) { 2264 *run = 0; /* unacceptable run. */ 2265 *saw = 1; 2266 return 0; 2267 } 2268 2269 for (i=1; i <= *run; i++) { /* iterate thru the run. */ 2270 if (along_x) { 2271 xt = x - i; 2272 yt = y; 2273 } else { 2274 xt = x; 2275 yt = y - i; 2276 } 2277 2278 m = xt + yt * ntiles_x; 2279 if (tile_tried[m]) { /* do not repeat tiles */ 2280 continue; 2281 } 2282 2283 ct = copy_tiles(xt, yt, 1); 2284 if (ct < 0) return ct; /* fatal */ 2285 } 2286 *run = 0; 2287 *saw = 1; 2288 return 1; 2289 } 2290 2291 /* 2292 * Look for small gaps of unchanged tiles that may actually contain changes. 2293 * E.g. when paging up and down in a web broswer or terminal there can 2294 * be a distracting delayed filling in of such gaps. gaps_fill is the 2295 * tweak parameter that sets the width of the gaps that are checked. 2296 * 2297 * BTW, grow_islands() is actually pretty successful at doing this too... 2298 */ 2299 static int fill_tile_gaps(void) { 2300 int x, y, run, saw; 2301 int n, diffs = 0, ct; 2302 2303 /* horizontal: */ 2304 for (y=0; y < ntiles_y; y++) { 2305 run = 0; 2306 saw = 0; 2307 for (x=0; x < ntiles_x; x++) { 2308 ct = gap_try(x, y, &run, &saw, 1); 2309 if (ct < 0) return ct; /* fatal */ 2310 } 2311 } 2312 2313 /* vertical: */ 2314 for (x=0; x < ntiles_x; x++) { 2315 run = 0; 2316 saw = 0; 2317 for (y=0; y < ntiles_y; y++) { 2318 ct = gap_try(x, y, &run, &saw, 0); 2319 if (ct < 0) return ct; /* fatal */ 2320 } 2321 } 2322 2323 for (n=0; n < ntiles; n++) { 2324 if (tile_has_diff[n]) { 2325 diffs++; 2326 } 2327 } 2328 return diffs; 2329 } 2330 2331 static int island_try(int x, int y, int u, int v, int *run) { 2332 int n, m, ct; 2333 2334 n = x + y * ntiles_x; 2335 m = u + v * ntiles_x; 2336 2337 if (tile_has_diff[n]) { 2338 (*run)++; 2339 } else { 2340 *run = 0; 2341 } 2342 2343 if (tile_has_diff[n] && ! tile_has_diff[m]) { 2344 /* found a discontinuity */ 2345 2346 if (tile_tried[m]) { 2347 return 0; 2348 } else if (*run < grow_fill) { 2349 return 0; 2350 } 2351 2352 ct = copy_tiles(u, v, 1); 2353 if (ct < 0) return ct; /* fatal */ 2354 } 2355 return 1; 2356 } 2357 2358 /* 2359 * Scan looking for discontinuities in tile_has_diff[]. Try to extend 2360 * the boundary of the discontinuity (i.e. make the island larger). 2361 * Vertical scans are skipped since they do not seem to yield much... 2362 */ 2363 static int grow_islands(void) { 2364 int x, y, n, run; 2365 int diffs = 0, ct; 2366 2367 /* 2368 * n.b. the way we scan here should keep an extension going, 2369 * and so also fill in gaps effectively... 2370 */ 2371 2372 /* left to right: */ 2373 for (y=0; y < ntiles_y; y++) { 2374 run = 0; 2375 for (x=0; x <= ntiles_x - 2; x++) { 2376 ct = island_try(x, y, x+1, y, &run); 2377 if (ct < 0) return ct; /* fatal */ 2378 } 2379 } 2380 /* right to left: */ 2381 for (y=0; y < ntiles_y; y++) { 2382 run = 0; 2383 for (x = ntiles_x - 1; x >= 1; x--) { 2384 ct = island_try(x, y, x-1, y, &run); 2385 if (ct < 0) return ct; /* fatal */ 2386 } 2387 } 2388 for (n=0; n < ntiles; n++) { 2389 if (tile_has_diff[n]) { 2390 diffs++; 2391 } 2392 } 2393 return diffs; 2394 } 2395 2396 /* 2397 * Fill the framebuffer with zeros for each blackout region 2398 */ 2399 static void blackout_regions(void) { 2400 int i; 2401 for (i=0; i < blackouts; i++) { 2402 zero_fb(blackr[i].x1, blackr[i].y1, blackr[i].x2, blackr[i].y2); 2403 } 2404 } 2405 2406 /* 2407 * copy the whole X screen to the rfb framebuffer. For a large enough 2408 * number of changed tiles, this is faster than tiles scheme at retrieving 2409 * the info from the X server. Bandwidth to client and compression time 2410 * are other issues... use -fs 1.0 to disable. 2411 */ 2412 int copy_screen(void) { 2413 char *fbp; 2414 int i, y, block_size; 2415 2416 if (! fs_factor) { 2417 return 0; 2418 } 2419 if (debug_tiles) fprintf(stderr, "copy_screen\n"); 2420 2421 if (unixpw_in_progress) return 0; 2422 2423 2424 if (! main_fb) { 2425 return 0; 2426 } 2427 2428 block_size = ((dpy_y/fs_factor) * main_bytes_per_line); 2429 2430 fbp = main_fb; 2431 y = 0; 2432 2433 X_LOCK; 2434 2435 /* screen may be too big for 1 shm area, so broken into fs_factor */ 2436 for (i=0; i < fs_factor; i++) { 2437 XRANDR_SET_TRAP_RET(-1, "copy_screen-set"); 2438 copy_image(fullscreen, 0, y, 0, 0); 2439 XRANDR_CHK_TRAP_RET(-1, "copy_screen-chk"); 2440 2441 memcpy(fbp, fullscreen->data, (size_t) block_size); 2442 2443 y += dpy_y / fs_factor; 2444 fbp += block_size; 2445 } 2446 2447 X_UNLOCK; 2448 2449 if (blackouts) { 2450 blackout_regions(); 2451 } 2452 2453 mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0); 2454 return 0; 2455 } 2456 2457 #include <rfb/default8x16.h> 2458 2459 /* 2460 * Color values from the vcsadump program. 2461 * void dumpcss(FILE *fp, char *attribs_used) 2462 * char *colormap[] = { 2463 * "#000000", "#0000AA", "#00AA00", "#00AAAA", "#AA0000", "#AA00AA", "#AA5500", "#AAAAAA", 2464 * "#555555", "#5555AA", "#55FF55", "#55FFFF", "#FF5555", "#FF55FF", "#FFFF00", "#FFFFFF" }; 2465 */ 2466 2467 static unsigned char console_cmap[16*3]={ 2468 /* 0 */ 0x00, 0x00, 0x00, 2469 /* 1 */ 0x00, 0x00, 0xAA, 2470 /* 2 */ 0x00, 0xAA, 0x00, 2471 /* 3 */ 0x00, 0xAA, 0xAA, 2472 /* 4 */ 0xAA, 0x00, 0x00, 2473 /* 5 */ 0xAA, 0x00, 0xAA, 2474 /* 6 */ 0xAA, 0x55, 0x00, 2475 /* 7 */ 0xAA, 0xAA, 0xAA, 2476 /* 8 */ 0x55, 0x55, 0x55, 2477 /* 9 */ 0x55, 0x55, 0xAA, 2478 /* 10 */ 0x55, 0xFF, 0x55, 2479 /* 11 */ 0x55, 0xFF, 0xFF, 2480 /* 12 */ 0xFF, 0x55, 0x55, 2481 /* 13 */ 0xFF, 0x55, 0xFF, 2482 /* 14 */ 0xFF, 0xFF, 0x00, 2483 /* 15 */ 0xFF, 0xFF, 0xFF 2484 }; 2485 2486 static void snap_vcsa_rawfb(void) { 2487 int n; 2488 char *dst; 2489 char buf[32]; 2490 int i, len, del; 2491 unsigned char rows, cols, xpos, ypos; 2492 static int prev_rows = -1, prev_cols = -1; 2493 static unsigned char prev_xpos = -1, prev_ypos = -1; 2494 static char *vcsabuf = NULL; 2495 static char *vcsabuf0 = NULL; 2496 static unsigned int color_tab[16]; 2497 static int Cw = 8, Ch = 16; 2498 static int db = -1, first = 1; 2499 int created = 0; 2500 rfbScreenInfo s; 2501 rfbScreenInfoPtr fake_screen = &s; 2502 int Bpp = raw_fb_native_bpp / 8; 2503 2504 if (db < 0) { 2505 if (getenv("X11VNC_DEBUG_VCSA")) { 2506 db = atoi(getenv("X11VNC_DEBUG_VCSA")); 2507 } else { 2508 db = 0; 2509 } 2510 } 2511 2512 if (first) { 2513 unsigned int rm = raw_fb_native_red_mask; 2514 unsigned int gm = raw_fb_native_green_mask; 2515 unsigned int bm = raw_fb_native_blue_mask; 2516 unsigned int rs = raw_fb_native_red_shift; 2517 unsigned int gs = raw_fb_native_green_shift; 2518 unsigned int bs = raw_fb_native_blue_shift; 2519 unsigned int rx = raw_fb_native_red_max; 2520 unsigned int gx = raw_fb_native_green_max; 2521 unsigned int bx = raw_fb_native_blue_max; 2522 2523 for (i=0; i < 16; i++) { 2524 int r = console_cmap[3*i+0]; 2525 int g = console_cmap[3*i+1]; 2526 int b = console_cmap[3*i+2]; 2527 r = rx * r / 255; 2528 g = gx * g / 255; 2529 b = bx * b / 255; 2530 color_tab[i] = (r << rs) | (g << gs) | (b << bs); 2531 if (db) fprintf(stderr, "cmap[%02d] 0x%08x %04d %04d %04d\n", i, color_tab[i], r, g, b); 2532 if (i != 0 && getenv("RAWFB_VCSA_BW")) { 2533 color_tab[i] = rm | gm | bm; 2534 } 2535 } 2536 } 2537 first = 0; 2538 2539 lseek(raw_fb_fd, 0, SEEK_SET); 2540 len = 4; 2541 del = 0; 2542 memset(buf, 0, sizeof(buf)); 2543 while (len > 0) { 2544 n = read(raw_fb_fd, buf + del, len); 2545 if (n > 0) { 2546 del += n; 2547 len -= n; 2548 } else if (n == 0) { 2549 break; 2550 } else if (errno != EINTR && errno != EAGAIN) { 2551 break; 2552 } 2553 } 2554 2555 rows = (unsigned char) buf[0]; 2556 cols = (unsigned char) buf[1]; 2557 xpos = (unsigned char) buf[2]; 2558 ypos = (unsigned char) buf[3]; 2559 2560 if (db) fprintf(stderr, "rows=%d cols=%d xpos=%d ypos=%d Bpp=%d\n", rows, cols, xpos, ypos, Bpp); 2561 if (rows == 0 || cols == 0) { 2562 usleep(100 * 1000); 2563 return; 2564 } 2565 2566 if (vcsabuf == NULL || prev_rows != rows || prev_cols != cols) { 2567 if (vcsabuf) { 2568 free(vcsabuf); 2569 free(vcsabuf0); 2570 } 2571 vcsabuf = (char *) calloc(2 * rows * cols, 1); 2572 vcsabuf0 = (char *) calloc(2 * rows * cols, 1); 2573 created = 1; 2574 2575 if (prev_rows != -1 && prev_cols != -1) { 2576 do_new_fb(1); 2577 } 2578 2579 prev_rows = rows; 2580 prev_cols = cols; 2581 } 2582 2583 if (!rfbEndianTest) { 2584 unsigned char tc = rows; 2585 rows = cols; 2586 cols = tc; 2587 2588 tc = xpos; 2589 xpos = ypos; 2590 ypos = tc; 2591 } 2592 2593 len = 2 * rows * cols; 2594 del = 0; 2595 memset(vcsabuf, 0, len); 2596 while (len > 0) { 2597 n = read(raw_fb_fd, vcsabuf + del, len); 2598 if (n > 0) { 2599 del += n; 2600 len -= n; 2601 } else if (n == 0) { 2602 break; 2603 } else if (errno != EINTR && errno != EAGAIN) { 2604 break; 2605 } 2606 } 2607 2608 fake_screen->frameBuffer = snap->data; 2609 fake_screen->paddedWidthInBytes = snap->bytes_per_line; 2610 fake_screen->serverFormat.bitsPerPixel = raw_fb_native_bpp; 2611 fake_screen->width = snap->width; 2612 fake_screen->height = snap->height; 2613 2614 for (i=0; i < rows * cols; i++) { 2615 int ix, iy, x, y, w, h; 2616 unsigned char chr = 0; 2617 unsigned char attr; 2618 unsigned int fore, back; 2619 unsigned short *usp; 2620 unsigned int *uip; 2621 chr = (unsigned char) vcsabuf[2*i]; 2622 attr = vcsabuf[2*i+1]; 2623 2624 iy = i / cols; 2625 ix = i - iy * cols; 2626 2627 if (ix == prev_xpos && iy == prev_ypos) { 2628 ; 2629 } else if (ix == xpos && iy == ypos) { 2630 ; 2631 } else if (!created && chr == vcsabuf0[2*i] && attr == vcsabuf0[2*i+1]) { 2632 continue; 2633 } 2634 2635 if (!rfbEndianTest) { 2636 unsigned char tc = chr; 2637 chr = attr; 2638 attr = tc; 2639 } 2640 2641 y = iy * Ch; 2642 x = ix * Cw; 2643 dst = snap->data + y * snap->bytes_per_line + x * Bpp; 2644 2645 fore = color_tab[attr & 0xf]; 2646 back = color_tab[(attr >> 4) & 0x7]; 2647 2648 if (ix == xpos && iy == ypos) { 2649 unsigned int ti = fore; 2650 fore = back; 2651 back = ti; 2652 } 2653 2654 for (h = 0; h < Ch; h++) { 2655 if (Bpp == 1) { 2656 memset(dst, back, Cw); 2657 } else if (Bpp == 2) { 2658 for (w = 0; w < Cw; w++) { 2659 usp = (unsigned short *) (dst + w*Bpp); 2660 *usp = (unsigned short) back; 2661 } 2662 } else if (Bpp == 4) { 2663 for (w = 0; w < Cw; w++) { 2664 uip = (unsigned int *) (dst + w*Bpp); 2665 *uip = (unsigned int) back; 2666 } 2667 } 2668 dst += snap->bytes_per_line; 2669 } 2670 rfbDrawChar(fake_screen, &default8x16Font, x, y + Ch, chr, fore); 2671 } 2672 memcpy(vcsabuf0, vcsabuf, 2 * rows * cols); 2673 prev_xpos = xpos; 2674 prev_ypos = ypos; 2675 } 2676 2677 static void snap_all_rawfb(void) { 2678 int pixelsize = bpp/8; 2679 int n, sz; 2680 char *dst; 2681 static char *unclipped_dst = NULL; 2682 static int unclipped_len = 0; 2683 2684 dst = snap->data; 2685 2686 if (xform24to32 && bpp == 32) { 2687 pixelsize = 3; 2688 } 2689 sz = dpy_y * snap->bytes_per_line; 2690 2691 if (wdpy_x > dpy_x || wdpy_y > dpy_y) { 2692 sz = wdpy_x * wdpy_y * pixelsize; 2693 if (sz > unclipped_len || unclipped_dst == NULL) { 2694 if (unclipped_dst) { 2695 free(unclipped_dst); 2696 } 2697 unclipped_dst = (char *) malloc(sz+4); 2698 unclipped_len = sz; 2699 } 2700 dst = unclipped_dst; 2701 } 2702 2703 if (! raw_fb_seek) { 2704 memcpy(dst, raw_fb_addr + raw_fb_offset, sz); 2705 2706 } else { 2707 int len = sz, del = 0; 2708 off_t off = (off_t) raw_fb_offset; 2709 2710 lseek(raw_fb_fd, off, SEEK_SET); 2711 while (len > 0) { 2712 n = read(raw_fb_fd, dst + del, len); 2713 if (n > 0) { 2714 del += n; 2715 len -= n; 2716 } else if (n == 0) { 2717 break; 2718 } else if (errno != EINTR && errno != EAGAIN) { 2719 break; 2720 } 2721 } 2722 } 2723 2724 if (dst == unclipped_dst) { 2725 char *src; 2726 int h; 2727 int x = off_x + coff_x; 2728 int y = off_y + coff_y; 2729 2730 src = unclipped_dst + y * wdpy_x * pixelsize + 2731 x * pixelsize; 2732 dst = snap->data; 2733 2734 for (h = 0; h < dpy_y; h++) { 2735 memcpy(dst, src, dpy_x * pixelsize); 2736 src += wdpy_x * pixelsize; 2737 dst += snap->bytes_per_line; 2738 } 2739 } 2740 } 2741 2742 int copy_snap(void) { 2743 int db = 1; 2744 char *fbp; 2745 int i, y, block_size; 2746 double dt; 2747 static int first = 1, snapcnt = 0; 2748 2749 if (raw_fb_str) { 2750 int read_all_at_once = 1; 2751 double start = dnow(); 2752 if (rawfb_reset < 0) { 2753 if (getenv("SNAPFB_RAWFB_RESET")) { 2754 rawfb_reset = 1; 2755 } else { 2756 rawfb_reset = 0; 2757 } 2758 } 2759 if (snap_fb == NULL || snap == NULL) { 2760 rfbLog("copy_snap: rawfb mode and null snap fb\n"); 2761 clean_up_exit(1); 2762 } 2763 if (rawfb_reset) { 2764 initialize_raw_fb(1); 2765 } 2766 if (raw_fb_bytes_per_line != snap->bytes_per_line) { 2767 read_all_at_once = 0; 2768 } 2769 if (raw_fb_full_str && strstr(raw_fb_full_str, "/dev/vcsa")) { 2770 snap_vcsa_rawfb(); 2771 } else if (read_all_at_once) { 2772 snap_all_rawfb(); 2773 } else { 2774 /* this goes line by line, XXX not working for video */ 2775 copy_raw_fb(snap, 0, 0, dpy_x, dpy_y); 2776 } 2777 if (db && snapcnt++ < 5) rfbLog("rawfb copy_snap took: %.5f secs\n", dnow() - start); 2778 2779 return 0; 2780 } 2781 2782 if (! fs_factor) { 2783 return 0; 2784 } 2785 2786 2787 if (! snap_fb || ! snap || ! snaprect) { 2788 return 0; 2789 } 2790 block_size = ((dpy_y/fs_factor) * snap->bytes_per_line); 2791 2792 fbp = snap_fb; 2793 y = 0; 2794 2795 2796 dtime0(&dt); 2797 X_LOCK; 2798 2799 /* screen may be too big for 1 shm area, so broken into fs_factor */ 2800 for (i=0; i < fs_factor; i++) { 2801 XRANDR_SET_TRAP_RET(-1, "copy_snap-set"); 2802 copy_image(snaprect, 0, y, 0, 0); 2803 XRANDR_CHK_TRAP_RET(-1, "copy_snap-chk"); 2804 2805 memcpy(fbp, snaprect->data, (size_t) block_size); 2806 2807 y += dpy_y / fs_factor; 2808 fbp += block_size; 2809 } 2810 2811 X_UNLOCK; 2812 2813 dt = dtime(&dt); 2814 if (first) { 2815 rfbLog("copy_snap: time for -snapfb snapshot: %.3f sec\n", dt); 2816 first = 0; 2817 } 2818 2819 return 0; 2820 } 2821 2822 2823 /* 2824 * debugging: print out a picture of the tiles. 2825 */ 2826 static void print_tiles(void) { 2827 /* hack for viewing tile diffs on the screen. */ 2828 static char *prev = NULL; 2829 int n, x, y, ms = 1500; 2830 2831 ms = 1; 2832 2833 if (! prev) { 2834 prev = (char *) malloc((size_t) ntiles); 2835 for (n=0; n < ntiles; n++) { 2836 prev[n] = 0; 2837 } 2838 } 2839 fprintf(stderr, " "); 2840 for (x=0; x < ntiles_x; x++) { 2841 fprintf(stderr, "%1d", x % 10); 2842 } 2843 fprintf(stderr, "\n"); 2844 n = 0; 2845 for (y=0; y < ntiles_y; y++) { 2846 fprintf(stderr, "%2d ", y); 2847 for (x=0; x < ntiles_x; x++) { 2848 if (tile_has_diff[n]) { 2849 fprintf(stderr, "X"); 2850 } else if (prev[n]) { 2851 fprintf(stderr, "o"); 2852 } else { 2853 fprintf(stderr, "."); 2854 } 2855 n++; 2856 } 2857 fprintf(stderr, "\n"); 2858 } 2859 for (n=0; n < ntiles; n++) { 2860 prev[n] = tile_has_diff[n]; 2861 } 2862 usleep(ms * 1000); 2863 } 2864 2865 /* 2866 * Utilities for managing the "naps" to cut down on amount of polling. 2867 */ 2868 static void nap_set(int tile_cnt) { 2869 int nap_in = nap_ok; 2870 time_t now = time(NULL); 2871 2872 if (scan_count == 0) { 2873 /* roll up check for all NSCAN scans */ 2874 nap_ok = 0; 2875 if (naptile && nap_diff_count < 2 * NSCAN * naptile) { 2876 /* "2" is a fudge to permit a bit of bg drawing */ 2877 nap_ok = 1; 2878 } 2879 nap_diff_count = 0; 2880 } 2881 if (nap_ok && ! nap_in && use_xdamage) { 2882 if (XD_skip > 0.8 * XD_tot) { 2883 /* X DAMAGE is keeping load low, so skip nap */ 2884 nap_ok = 0; 2885 } 2886 } 2887 if (! nap_ok && client_count) { 2888 if(now > last_fb_bytes_sent + no_fbu_blank) { 2889 if (debug_tiles > 1) { 2890 fprintf(stderr, "nap_set: nap_ok=1: now: %d last: %d\n", 2891 (int) now, (int) last_fb_bytes_sent); 2892 } 2893 nap_ok = 1; 2894 } 2895 } 2896 2897 if (show_cursor) { 2898 /* kludge for the up to 4 tiles the mouse patch could occupy */ 2899 if ( tile_cnt > 4) { 2900 last_event = now; 2901 } 2902 } else if (tile_cnt != 0) { 2903 last_event = now; 2904 } 2905 } 2906 2907 /* 2908 * split up a long nap to improve the wakeup time 2909 */ 2910 void nap_sleep(int ms, int split) { 2911 int i, input = got_user_input; 2912 int gd = got_local_pointer_input; 2913 2914 for (i=0; i<split; i++) { 2915 usleep(ms * 1000 / split); 2916 if (! use_threads && i != split - 1) { 2917 rfbPE(-1); 2918 } 2919 if (input != got_user_input) { 2920 break; 2921 } 2922 if (gd != got_local_pointer_input) { 2923 break; 2924 } 2925 } 2926 } 2927 2928 static char *get_load(void) { 2929 static char tmp[64]; 2930 static int count = 0; 2931 2932 if (count++ % 5 == 0) { 2933 struct stat sb; 2934 memset(tmp, 0, sizeof(tmp)); 2935 if (stat("/proc/loadavg", &sb) == 0) { 2936 int d = open("/proc/loadavg", O_RDONLY); 2937 if (d >= 0) { 2938 read(d, tmp, 60); 2939 close(d); 2940 } 2941 } 2942 if (tmp[0] == '\0') { 2943 strcat(tmp, "unknown"); 2944 } 2945 } 2946 return tmp; 2947 } 2948 2949 /* 2950 * see if we should take a nap of some sort between polls 2951 */ 2952 static void nap_check(int tile_cnt) { 2953 time_t now; 2954 2955 nap_diff_count += tile_cnt; 2956 2957 if (! take_naps) { 2958 return; 2959 } 2960 2961 now = time(NULL); 2962 2963 if (screen_blank > 0) { 2964 int dt_ev, dt_fbu; 2965 static int ms = 0; 2966 if (ms == 0) { 2967 ms = 2000; 2968 if (getenv("X11VNC_SB_FACTOR")) { 2969 ms = ms * atof(getenv("X11VNC_SB_FACTOR")); 2970 } 2971 if (ms <= 0) { 2972 ms = 2000; 2973 } 2974 } 2975 2976 /* if no activity, pause here for a second or so. */ 2977 dt_ev = (int) (now - last_event); 2978 dt_fbu = (int) (now - last_fb_bytes_sent); 2979 if (dt_fbu > screen_blank) { 2980 /* sleep longer for no fb requests */ 2981 if (debug_tiles > 1) { 2982 fprintf(stderr, "screen blank sleep1: %d ms / 16, load: %s\n", 2 * ms, get_load()); 2983 } 2984 nap_sleep(2 * ms, 16); 2985 return; 2986 } 2987 if (dt_ev > screen_blank) { 2988 if (debug_tiles > 1) { 2989 fprintf(stderr, "screen blank sleep2: %d ms / 8, load: %s\n", ms, get_load()); 2990 } 2991 nap_sleep(ms, 8); 2992 return; 2993 } 2994 } 2995 if (naptile && nap_ok && tile_cnt < naptile) { 2996 int ms = napfac * waitms; 2997 ms = ms > napmax ? napmax : ms; 2998 if (now - last_input <= 3) { 2999 nap_ok = 0; 3000 } else if (now - last_local_input <= 3) { 3001 nap_ok = 0; 3002 } else { 3003 if (debug_tiles > 1) { 3004 fprintf(stderr, "nap_check sleep: %d ms / 1, load: %s\n", ms, get_load()); 3005 } 3006 nap_sleep(ms, 1); 3007 } 3008 } 3009 } 3010 3011 /* 3012 * This is called to avoid a ~20 second timeout in libvncserver. 3013 * May no longer be needed. 3014 */ 3015 static void ping_clients(int tile_cnt) { 3016 static time_t last_send = 0; 3017 time_t now = time(NULL); 3018 3019 if (rfbMaxClientWait < 20000) { 3020 rfbMaxClientWait = 20000; 3021 rfbLog("reset rfbMaxClientWait to %d msec.\n", 3022 rfbMaxClientWait); 3023 } 3024 if (tile_cnt > 0) { 3025 last_send = now; 3026 } else if (tile_cnt < 0) { 3027 /* negative tile_cnt is -ping case */ 3028 if (now >= last_send - tile_cnt) { 3029 mark_rect_as_modified(0, 0, 1, 1, 1); 3030 last_send = now; 3031 } 3032 } else if (now - last_send > 5) { 3033 /* Send small heartbeat to client */ 3034 mark_rect_as_modified(0, 0, 1, 1, 1); 3035 last_send = now; 3036 } 3037 } 3038 3039 /* 3040 * scan_display() wants to know if this tile can be skipped due to 3041 * blackout regions: (no data compare is done, just a quick geometric test) 3042 */ 3043 static int blackout_line_skip(int n, int x, int y, int rescan, 3044 int *tile_count) { 3045 3046 if (tile_blackout[n].cover == 2) { 3047 tile_has_diff[n] = 0; 3048 return 1; /* skip it */ 3049 3050 } else if (tile_blackout[n].cover == 1) { 3051 int w, x1, y1, x2, y2, b, hit = 0; 3052 if (x + NSCAN > dpy_x) { 3053 w = dpy_x - x; 3054 } else { 3055 w = NSCAN; 3056 } 3057 3058 for (b=0; b < tile_blackout[n].count; b++) { 3059 3060 /* n.b. these coords are in full display space: */ 3061 x1 = tile_blackout[n].bo[b].x1; 3062 x2 = tile_blackout[n].bo[b].x2; 3063 y1 = tile_blackout[n].bo[b].y1; 3064 y2 = tile_blackout[n].bo[b].y2; 3065 3066 if (x2 - x1 < w) { 3067 /* need to cover full width */ 3068 continue; 3069 } 3070 if (y1 <= y && y < y2) { 3071 hit = 1; 3072 break; 3073 } 3074 } 3075 if (hit) { 3076 if (! rescan) { 3077 tile_has_diff[n] = 0; 3078 } else { 3079 *tile_count += tile_has_diff[n]; 3080 } 3081 return 1; /* skip */ 3082 } 3083 } 3084 return 0; /* do not skip */ 3085 } 3086 3087 static int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src, 3088 int w, int pixelsize) { 3089 3090 int i, x1, y1, x2, y2, b, hit = 0; 3091 int beg = -1, end = -1; 3092 3093 if (tile_blackout[n].cover == 0) { 3094 return 0; /* 0 means do not skip it. */ 3095 } else if (tile_blackout[n].cover == 2) { 3096 return 1; /* 1 means skip it. */ 3097 } 3098 3099 /* tile has partial coverage: */ 3100 3101 for (i=0; i < w * pixelsize; i++) { 3102 if (*(dst+i) != *(src+i)) { 3103 beg = i/pixelsize; /* beginning difference */ 3104 break; 3105 } 3106 } 3107 for (i = w * pixelsize - 1; i >= 0; i--) { 3108 if (*(dst+i) != *(src+i)) { 3109 end = i/pixelsize; /* ending difference */ 3110 break; 3111 } 3112 } 3113 if (beg < 0 || end < 0) { 3114 /* problem finding range... */ 3115 return 0; 3116 } 3117 3118 /* loop over blackout rectangles: */ 3119 for (b=0; b < tile_blackout[n].count; b++) { 3120 3121 /* y in full display space: */ 3122 y1 = tile_blackout[n].bo[b].y1; 3123 y2 = tile_blackout[n].bo[b].y2; 3124 3125 /* x relative to tile origin: */ 3126 x1 = tile_blackout[n].bo[b].x1 - x; 3127 x2 = tile_blackout[n].bo[b].x2 - x; 3128 3129 if (y1 > y || y >= y2) { 3130 continue; 3131 } 3132 if (x1 <= beg && end <= x2) { 3133 hit = 1; 3134 break; 3135 } 3136 } 3137 if (hit) { 3138 return 1; 3139 } else { 3140 return 0; 3141 } 3142 } 3143 3144 /* 3145 * For the subwin case follows the window if it is moved. 3146 */ 3147 void set_offset(void) { 3148 Window w; 3149 if (! subwin) { 3150 return; 3151 } 3152 X_LOCK; 3153 xtranslate(window, rootwin, 0, 0, &off_x, &off_y, &w, 0); 3154 X_UNLOCK; 3155 } 3156 3157 static int xd_samples = 0, xd_misses = 0, xd_do_check = 0; 3158 3159 /* 3160 * Loop over 1-pixel tall horizontal scanlines looking for changes. 3161 * Record the changes in tile_has_diff[]. Scanlines in the loop are 3162 * equally spaced along y by NSCAN pixels, but have a slightly random 3163 * starting offset ystart ( < NSCAN ) from scanlines[]. 3164 */ 3165 3166 static int scan_display(int ystart, int rescan) { 3167 char *src, *dst; 3168 int pixelsize = bpp/8; 3169 int x, y, w, n; 3170 int tile_count = 0; 3171 int nodiffs = 0, diff_hint; 3172 int xd_check = 0, xd_freq = 1; 3173 static int xd_tck = 0; 3174 3175 y = ystart; 3176 3177 g_now = dnow(); 3178 3179 if (! main_fb) { 3180 rfbLog("scan_display: no main_fb!\n"); 3181 return 0; 3182 } 3183 3184 X_LOCK; 3185 3186 while (y < dpy_y) { 3187 3188 if (use_xdamage) { 3189 XD_tot++; 3190 xd_check = 0; 3191 if (xdamage_hint_skip(y)) { 3192 if (xd_do_check && dpy && use_xdamage == 1) { 3193 xd_tck++; 3194 xd_tck = xd_tck % xd_freq; 3195 if (xd_tck == 0) { 3196 xd_check = 1; 3197 xd_samples++; 3198 } 3199 } 3200 if (!xd_check) { 3201 XD_skip++; 3202 y += NSCAN; 3203 continue; 3204 } 3205 } else { 3206 if (xd_do_check && 0) { 3207 fprintf(stderr, "ns y=%d\n", y); 3208 } 3209 } 3210 } 3211 3212 /* grab the horizontal scanline from the display: */ 3213 3214 #ifndef NO_NCACHE 3215 /* XXX Y test */ 3216 if (ncache > 0) { 3217 int gotone = 0; 3218 if (macosx_console) { 3219 if (macosx_checkevent(NULL)) { 3220 gotone = 1; 3221 } 3222 } else { 3223 #if !NO_X11 3224 XEvent ev; 3225 if (raw_fb_str) { 3226 ; 3227 } else if (XEventsQueued(dpy, QueuedAlready) == 0) { 3228 ; /* XXX Y resp */ 3229 } else if (XCheckTypedEvent(dpy, MapNotify, &ev)) { 3230 gotone = 1; 3231 } else if (XCheckTypedEvent(dpy, UnmapNotify, &ev)) { 3232 gotone = 2; 3233 } else if (XCheckTypedEvent(dpy, CreateNotify, &ev)) { 3234 gotone = 3; 3235 } else if (XCheckTypedEvent(dpy, ConfigureNotify, &ev)) { 3236 gotone = 4; 3237 } else if (XCheckTypedEvent(dpy, VisibilityNotify, &ev)) { 3238 gotone = 5; 3239 } 3240 if (gotone) { 3241 XPutBackEvent(dpy, &ev); 3242 } 3243 #endif 3244 } 3245 if (gotone) { 3246 static int nomsg = 1; 3247 if (nomsg) { 3248 if (dnowx() > 20) { 3249 nomsg = 0; 3250 } 3251 } else { 3252 if (ncdb) fprintf(stderr, "\n*** SCAN_DISPLAY CHECK_NCACHE/%d *** %d rescan=%d\n", gotone, y, rescan); 3253 } 3254 X_UNLOCK; 3255 check_ncache(0, 1); 3256 X_LOCK; 3257 } 3258 } 3259 #endif 3260 3261 XRANDR_SET_TRAP_RET(-1, "scan_display-set"); 3262 copy_image(scanline, 0, y, 0, 0); 3263 XRANDR_CHK_TRAP_RET(-1, "scan_display-chk"); 3264 3265 /* for better memory i/o try the whole line at once */ 3266 src = scanline->data; 3267 dst = main_fb + y * main_bytes_per_line; 3268 3269 if (! memcmp(dst, src, main_bytes_per_line)) { 3270 /* no changes anywhere in scan line */ 3271 nodiffs = 1; 3272 if (! rescan) { 3273 y += NSCAN; 3274 continue; 3275 } 3276 } 3277 if (xd_check) { 3278 xd_misses++; 3279 } 3280 3281 x = 0; 3282 while (x < dpy_x) { 3283 n = (x/tile_x) + (y/tile_y) * ntiles_x; 3284 diff_hint = 0; 3285 3286 if (blackouts) { 3287 if (blackout_line_skip(n, x, y, rescan, 3288 &tile_count)) { 3289 x += NSCAN; 3290 continue; 3291 } 3292 } 3293 3294 if (rescan) { 3295 if (nodiffs || tile_has_diff[n]) { 3296 tile_count += tile_has_diff[n]; 3297 x += NSCAN; 3298 continue; 3299 } 3300 } else if (xdamage_tile_count && 3301 tile_has_xdamage_diff[n]) { 3302 tile_has_xdamage_diff[n] = 2; 3303 diff_hint = 1; 3304 } 3305 3306 /* set ptrs to correspond to the x offset: */ 3307 src = scanline->data + x * pixelsize; 3308 dst = main_fb + y * main_bytes_per_line + x * pixelsize; 3309 3310 /* compute the width of data to be compared: */ 3311 if (x + NSCAN > dpy_x) { 3312 w = dpy_x - x; 3313 } else { 3314 w = NSCAN; 3315 } 3316 3317 if (diff_hint || memcmp(dst, src, w * pixelsize)) { 3318 /* found a difference, record it: */ 3319 if (! blackouts) { 3320 tile_has_diff[n] = 1; 3321 tile_count++; 3322 } else { 3323 if (blackout_line_cmpskip(n, x, y, 3324 dst, src, w, pixelsize)) { 3325 tile_has_diff[n] = 0; 3326 } else { 3327 tile_has_diff[n] = 1; 3328 tile_count++; 3329 } 3330 } 3331 } 3332 x += NSCAN; 3333 } 3334 y += NSCAN; 3335 } 3336 3337 X_UNLOCK; 3338 3339 return tile_count; 3340 } 3341 3342 3343 int scanlines[NSCAN] = { 3344 0, 16, 8, 24, 4, 20, 12, 28, 3345 10, 26, 18, 2, 22, 6, 30, 14, 3346 1, 17, 9, 25, 7, 23, 15, 31, 3347 19, 3, 27, 11, 29, 13, 5, 21 3348 }; 3349 3350 /* 3351 * toplevel for the scanning, rescanning, and applying the heuristics. 3352 * returns number of changed tiles. 3353 */ 3354 int scan_for_updates(int count_only) { 3355 int i, tile_count, tile_diffs; 3356 int old_copy_tile; 3357 double frac1 = 0.1; /* tweak parameter to try a 2nd scan_display() */ 3358 double frac2 = 0.35; /* or 3rd */ 3359 double frac3 = 0.02; /* do scan_display() again after copy_tiles() */ 3360 static double last_poll = 0.0; 3361 double dtmp = 0.0; 3362 3363 if (unixpw_in_progress) return 0; 3364 3365 if (slow_fb > 0.0) { 3366 double now = dnow(); 3367 if (now < last_poll + slow_fb) { 3368 return 0; 3369 } 3370 last_poll = now; 3371 } 3372 3373 for (i=0; i < ntiles; i++) { 3374 tile_has_diff[i] = 0; 3375 tile_has_xdamage_diff[i] = 0; 3376 tile_tried[i] = 0; 3377 tile_copied[i] = 0; 3378 } 3379 for (i=0; i < ntiles_y; i++) { 3380 /* could be useful, currently not used */ 3381 tile_row_has_xdamage_diff[i] = 0; 3382 } 3383 xdamage_tile_count = 0; 3384 3385 /* 3386 * n.b. this program has only been tested so far with 3387 * tile_x = tile_y = NSCAN = 32! 3388 */ 3389 3390 if (!count_only) { 3391 scan_count++; 3392 scan_count %= NSCAN; 3393 3394 /* some periodic maintenance */ 3395 if (subwin && scan_count % 4 == 0) { 3396 set_offset(); /* follow the subwindow */ 3397 } 3398 if (indexed_color && scan_count % 4 == 0) { 3399 /* check for changed colormap */ 3400 set_colormap(0); 3401 } 3402 if (cmap8to24 && scan_count % 1 == 0) { 3403 check_for_multivis(); 3404 } 3405 #ifdef MACOSX 3406 if (macosx_console) { 3407 macosx_event_loop(); 3408 } 3409 #endif 3410 if (use_xdamage) { 3411 /* first pass collecting DAMAGE events: */ 3412 #ifdef MACOSX 3413 if (macosx_console) { 3414 collect_non_X_xdamage(-1, -1, -1, -1, 0); 3415 } else 3416 #endif 3417 { 3418 if (rawfb_vnc_reflect) { 3419 collect_non_X_xdamage(-1, -1, -1, -1, 0); 3420 } else { 3421 collect_xdamage(scan_count, 0); 3422 } 3423 } 3424 } 3425 } 3426 3427 #define SCAN_FATAL(x) \ 3428 if (x < 0) { \ 3429 scan_in_progress = 0; \ 3430 fb_copy_in_progress = 0; \ 3431 return 0; \ 3432 } 3433 3434 /* scan with the initial y to the jitter value from scanlines: */ 3435 scan_in_progress = 1; 3436 tile_count = scan_display(scanlines[scan_count], 0); 3437 SCAN_FATAL(tile_count); 3438 3439 /* 3440 * we do the XDAMAGE here too since after scan_display() 3441 * there is a better chance we have received the events from 3442 * the X server (otherwise the DAMAGE events will be processed 3443 * in the *next* call, usually too late and wasteful since 3444 * the unchanged tiles are read in again). 3445 */ 3446 if (use_xdamage) { 3447 #ifdef MACOSX 3448 if (macosx_console) { 3449 ; 3450 } else 3451 #endif 3452 { 3453 if (rawfb_vnc_reflect) { 3454 ; 3455 } else { 3456 collect_xdamage(scan_count, 1); 3457 } 3458 } 3459 } 3460 if (count_only) { 3461 scan_in_progress = 0; 3462 fb_copy_in_progress = 0; 3463 return tile_count; 3464 } 3465 3466 if (xdamage_tile_count) { 3467 /* pick up "known" damaged tiles we missed in scan_display() */ 3468 for (i=0; i < ntiles; i++) { 3469 if (tile_has_diff[i]) { 3470 continue; 3471 } 3472 if (tile_has_xdamage_diff[i]) { 3473 tile_has_diff[i] = 1; 3474 if (tile_has_xdamage_diff[i] == 1) { 3475 tile_has_xdamage_diff[i] = 2; 3476 tile_count++; 3477 } 3478 } 3479 } 3480 } 3481 if (dpy && use_xdamage == 1) { 3482 static time_t last_xd_check = 0; 3483 if (time(NULL) > last_xd_check + 2) { 3484 int cp = (scan_count + 3) % NSCAN; 3485 xd_do_check = 1; 3486 tile_count = scan_display(scanlines[cp], 0); 3487 xd_do_check = 0; 3488 SCAN_FATAL(tile_count); 3489 last_xd_check = time(NULL); 3490 if (xd_samples > 200) { 3491 static int bad = 0; 3492 if (xd_misses > (20 * xd_samples) / 100) { 3493 rfbLog("XDAMAGE is not working well... misses: %d/%d\n", xd_misses, xd_samples); 3494 rfbLog("Maybe an OpenGL app like Beryl or Compiz is the problem?\n"); 3495 rfbLog("Use x11vnc -noxdamage or disable the Beryl/Compiz app.\n"); 3496 rfbLog("To disable this check and warning specify -xdamage twice.\n"); 3497 if (++bad >= 10) { 3498 rfbLog("XDAMAGE appears broken (OpenGL app?), turning it off.\n"); 3499 use_xdamage = 0; 3500 initialize_xdamage(); 3501 destroy_xdamage_if_needed(); 3502 } 3503 } 3504 xd_samples = 0; 3505 xd_misses = 0; 3506 } 3507 } 3508 } 3509 3510 nap_set(tile_count); 3511 3512 if (fs_factor && frac1 >= fs_frac) { 3513 /* make frac1 < fs_frac if fullscreen updates are enabled */ 3514 frac1 = fs_frac/2.0; 3515 } 3516 3517 if (tile_count > frac1 * ntiles) { 3518 /* 3519 * many tiles have changed, so try a rescan (since it should 3520 * be short compared to the many upcoming copy_tiles() calls) 3521 */ 3522 3523 /* this check is done to skip the extra scan_display() call */ 3524 if (! fs_factor || tile_count <= fs_frac * ntiles) { 3525 int cp, tile_count_old = tile_count; 3526 3527 /* choose a different y shift for the 2nd scan: */ 3528 cp = (NSCAN - scan_count) % NSCAN; 3529 3530 tile_count = scan_display(scanlines[cp], 1); 3531 SCAN_FATAL(tile_count); 3532 3533 if (tile_count >= (1 + frac2) * tile_count_old) { 3534 /* on a roll... do a 3rd scan */ 3535 cp = (NSCAN - scan_count + 7) % NSCAN; 3536 tile_count = scan_display(scanlines[cp], 1); 3537 SCAN_FATAL(tile_count); 3538 } 3539 } 3540 scan_in_progress = 0; 3541 3542 /* 3543 * At some number of changed tiles it is better to just 3544 * copy the full screen at once. I.e. time = c1 + m * r1 3545 * where m is number of tiles, r1 is the copy_tiles() 3546 * time, and c1 is the scan_display() time: for some m 3547 * it crosses the full screen update time. 3548 * 3549 * We try to predict that crossover with the fs_frac 3550 * fudge factor... seems to be about 1/2 the total number 3551 * of tiles. n.b. this ignores network bandwidth, 3552 * compression time etc... 3553 * 3554 * Use -fs 1.0 to disable on slow links. 3555 */ 3556 if (fs_factor && tile_count > fs_frac * ntiles) { 3557 int cs; 3558 fb_copy_in_progress = 1; 3559 cs = copy_screen(); 3560 fb_copy_in_progress = 0; 3561 SCAN_FATAL(cs); 3562 if (use_threads && pointer_mode != 1) { 3563 pointer_event(-1, 0, 0, NULL); 3564 } 3565 nap_check(tile_count); 3566 return tile_count; 3567 } 3568 } 3569 scan_in_progress = 0; 3570 3571 /* copy all tiles with differences from display to rfb framebuffer: */ 3572 fb_copy_in_progress = 1; 3573 3574 if (single_copytile || tile_shm_count < ntiles_x) { 3575 /* 3576 * Old way, copy I/O one tile at a time. 3577 */ 3578 old_copy_tile = 1; 3579 } else { 3580 /* 3581 * New way, does runs of horizontal tiles at once. 3582 * Note that below, for simplicity, the extra tile finding 3583 * (e.g. copy_tiles_backward_pass) is done the old way. 3584 */ 3585 old_copy_tile = 0; 3586 } 3587 3588 if (unixpw_in_progress) return 0; 3589 3590 /* XXX Y */ 3591 if (0 && tile_count > 20) print_tiles(); 3592 #if 0 3593 dtmp = dnow(); 3594 #else 3595 dtmp = 0.0; 3596 #endif 3597 3598 if (old_copy_tile) { 3599 tile_diffs = copy_all_tiles(); 3600 } else { 3601 tile_diffs = copy_all_tile_runs(); 3602 } 3603 SCAN_FATAL(tile_diffs); 3604 3605 #if 0 3606 if (tile_count) fprintf(stderr, "XX copytile: %.4f tile_count: %d\n", dnow() - dtmp, tile_count); 3607 #endif 3608 3609 /* 3610 * This backward pass for upward and left tiles complements what 3611 * was done in copy_all_tiles() for downward and right tiles. 3612 */ 3613 tile_diffs = copy_tiles_backward_pass(); 3614 SCAN_FATAL(tile_diffs); 3615 3616 if (tile_diffs > frac3 * ntiles) { 3617 /* 3618 * we spent a lot of time in those copy_tiles, run 3619 * another scan, maybe more of the screen changed. 3620 */ 3621 int cp = (NSCAN - scan_count + 13) % NSCAN; 3622 3623 scan_in_progress = 1; 3624 tile_count = scan_display(scanlines[cp], 1); 3625 SCAN_FATAL(tile_count); 3626 scan_in_progress = 0; 3627 3628 tile_diffs = copy_tiles_additional_pass(); 3629 SCAN_FATAL(tile_diffs); 3630 } 3631 3632 /* Given enough tile diffs, try the islands: */ 3633 if (grow_fill && tile_diffs > 4) { 3634 tile_diffs = grow_islands(); 3635 } 3636 SCAN_FATAL(tile_diffs); 3637 3638 /* Given enough tile diffs, try the gaps: */ 3639 if (gaps_fill && tile_diffs > 4) { 3640 tile_diffs = fill_tile_gaps(); 3641 } 3642 SCAN_FATAL(tile_diffs); 3643 3644 fb_copy_in_progress = 0; 3645 if (use_threads && pointer_mode != 1) { 3646 /* 3647 * tell the pointer handler it can process any queued 3648 * pointer events: 3649 */ 3650 pointer_event(-1, 0, 0, NULL); 3651 } 3652 3653 if (blackouts) { 3654 /* ignore any diffs in completely covered tiles */ 3655 int x, y, n; 3656 for (y=0; y < ntiles_y; y++) { 3657 for (x=0; x < ntiles_x; x++) { 3658 n = x + y * ntiles_x; 3659 if (tile_blackout[n].cover == 2) { 3660 tile_has_diff[n] = 0; 3661 } 3662 } 3663 } 3664 } 3665 3666 hint_updates(); /* use x0rfbserver hints algorithm */ 3667 3668 /* Work around threaded rfbProcessClientMessage() calls timeouts */ 3669 if (use_threads) { 3670 ping_clients(tile_diffs); 3671 } else if (saw_ultra_chat || saw_ultra_file) { 3672 ping_clients(-1); 3673 } else if (use_openssl && !tile_diffs) { 3674 ping_clients(0); 3675 } 3676 /* -ping option: */ 3677 if (ping_interval) { 3678 int td = ping_interval > 0 ? ping_interval : -ping_interval; 3679 ping_clients(-td); 3680 } 3681 3682 3683 nap_check(tile_diffs); 3684 return tile_diffs; 3685 } 3686 3687 3688