16
#include "userinput.h"
19
* routines for scanning and reading the X11 display for changes, and
20
* for doing all the tile work (shm, etc).
22
void initialize_tiles(void);
23
void free_tiles(void);
24
void shm_delete(XShmSegmentInfo *shm);
25
void shm_clean(XShmSegmentInfo *shm, XImage *xim);
26
void initialize_polling_images(void);
27
void scale_rect(double factor, int blend, int interpolate, int Bpp,
28
char *src_fb, int src_bytes_per_line, char *dst_fb, int dst_bytes_per_line,
29
int Nx, int Ny, int nx, int ny, int X1, int Y1, int X2, int Y2, int mark);
30
void scale_and_mark_rect(int X1, int Y1, int X2, int Y2, int mark);
31
void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force);
32
int copy_screen(void);
34
void nap_sleep(int ms, int split);
35
void set_offset(void);
36
int scan_for_updates(int count_only);
37
void rotate_curs(char *dst_0, char *src_0, int Dx, int Dy, int Bpp);
38
void rotate_coords(int x, int y, int *xo, int *yo, int dxi, int dyi);
39
void rotate_coords_inverse(int x, int y, int *xo, int *yo, int dxi, int dyi);
41
static void set_fs_factor(int max);
42
static char *flip_ximage_byte_order(XImage *xim);
43
static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
45
static void create_tile_hint(int x, int y, int tw, int th, hint_t *hint);
46
static void extend_tile_hint(int x, int y, int tw, int th, hint_t *hint);
47
static void save_hint(hint_t hint, int loc);
48
static void hint_updates(void);
49
static void mark_hint(hint_t hint);
50
static int copy_tiles(int tx, int ty, int nt);
51
static int copy_all_tiles(void);
52
static int copy_all_tile_runs(void);
53
static int copy_tiles_backward_pass(void);
54
static int copy_tiles_additional_pass(void);
55
static int gap_try(int x, int y, int *run, int *saw, int along_x);
56
static int fill_tile_gaps(void);
57
static int island_try(int x, int y, int u, int v, int *run);
58
static int grow_islands(void);
59
static void blackout_regions(void);
60
static void nap_set(int tile_cnt);
61
static void nap_check(int tile_cnt);
62
static void ping_clients(int tile_cnt);
63
static int blackout_line_skip(int n, int x, int y, int rescan,
65
static int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src,
66
int w, int pixelsize);
67
static int scan_display(int ystart, int rescan);
70
/* array to hold the hints: */
71
static hint_t *hint_list;
75
static int nap_diff_count = 0;
77
static int scan_count = 0; /* indicates which scan pattern we are on */
78
static int scan_in_progress = 0;
81
typedef struct tile_change_region {
82
/* start and end lines, along y, of the changed area inside a tile. */
83
unsigned short first_line, last_line;
84
short first_x, last_x;
85
/* info about differences along edges. */
86
unsigned short left_diff, right_diff;
87
unsigned short top_diff, bot_diff;
90
/* array to hold the tiles region_t-s. */
91
static region_t *tile_region;
97
* setup tile numbers and allocate the tile and hint arrays:
99
void initialize_tiles(void) {
101
ntiles_x = (dpy_x - 1)/tile_x + 1;
102
ntiles_y = (dpy_y - 1)/tile_y + 1;
103
ntiles = ntiles_x * ntiles_y;
105
tile_has_diff = (unsigned char *)
106
calloc((size_t) (ntiles * sizeof(unsigned char)), 1);
107
tile_has_xdamage_diff = (unsigned char *)
108
calloc((size_t) (ntiles * sizeof(unsigned char)), 1);
109
tile_row_has_xdamage_diff = (unsigned char *)
110
calloc((size_t) (ntiles_y * sizeof(unsigned char)), 1);
111
tile_tried = (unsigned char *)
112
calloc((size_t) (ntiles * sizeof(unsigned char)), 1);
113
tile_copied = (unsigned char *)
114
calloc((size_t) (ntiles * sizeof(unsigned char)), 1);
115
tile_blackout = (tile_blackout_t *)
116
calloc((size_t) (ntiles * sizeof(tile_blackout_t)), 1);
117
tile_region = (region_t *) calloc((size_t) (ntiles * sizeof(region_t)), 1);
119
tile_row = (XImage **)
120
calloc((size_t) ((ntiles_x + 1) * sizeof(XImage *)), 1);
121
tile_row_shm = (XShmSegmentInfo *)
122
calloc((size_t) ((ntiles_x + 1) * sizeof(XShmSegmentInfo)), 1);
124
/* there will never be more hints than tiles: */
125
hint_list = (hint_t *) calloc((size_t) (ntiles * sizeof(hint_t)), 1);
128
void free_tiles(void) {
131
tile_has_diff = NULL;
133
if (tile_has_xdamage_diff) {
134
free(tile_has_xdamage_diff);
135
tile_has_xdamage_diff = NULL;
137
if (tile_row_has_xdamage_diff) {
138
free(tile_row_has_xdamage_diff);
139
tile_row_has_xdamage_diff = NULL;
151
tile_blackout = NULL;
172
* silly function to factor dpy_y until fullscreen shm is not bigger than max.
173
* should always work unless dpy_y is a large prime or something... under
174
* failure fs_factor remains 0 and no fullscreen updates will be tried.
176
static int fs_factor = 0;
178
static void set_fs_factor(int max) {
179
int f, fac = 1, n = dpy_y;
182
if ((bpp/8) * dpy_x * dpy_y <= max) {
186
for (f=2; f <= 101; f++) {
190
if ( (bpp/8) * dpy_x * (dpy_y/fac) <= max ) {
198
static char *flip_ximage_byte_order(XImage *xim) {
200
if (xim->byte_order == LSBFirst) {
202
xim->byte_order = MSBFirst;
203
xim->bitmap_bit_order = MSBFirst;
206
xim->byte_order = LSBFirst;
207
xim->bitmap_bit_order = LSBFirst;
213
* set up an XShm image, or if not using shm just create the XImage.
215
static int shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h,
219
static int reported_flip = 0;
223
shm->shmaddr = (char *) -1;
232
if (! using_shm || xform24to32 || raw_fb) {
233
/* we only need the XImage created */
234
xim = XCreateImage_wr(dpy, default_visual, depth, ZPixmap,
235
0, NULL, w, h, raw_fb ? 32 : BitmapPad(dpy), 0);
240
rfbErr("XCreateImage(%s) failed.\n", name);
242
fprintf(stderr, "XCreateImage(%s) failed.\n",
247
if (db) fprintf(stderr, "shm_create simple %d %d\t%p %s\n", w, h, (void *)xim, name);
248
xim->data = (char *) malloc(xim->bytes_per_line * xim->height);
249
if (xim->data == NULL) {
250
rfbErr("XCreateImage(%s) data malloc failed.\n", name);
252
fprintf(stderr, "XCreateImage(%s) data malloc"
257
if (flip_byte_order) {
258
char *order = flip_ximage_byte_order(xim);
259
if (! reported_flip && ! quiet) {
260
rfbLog("Changing XImage byte order"
275
xim = XShmCreateImage_wr(dpy, default_visual, depth, ZPixmap, NULL,
279
rfbErr("XShmCreateImage(%s) failed.\n", name);
281
fprintf(stderr, "XShmCreateImage(%s) failed.\n", name);
289
#if LIBVNCSERVER_HAVE_XSHM
290
shm->shmid = shmget(IPC_PRIVATE,
291
xim->bytes_per_line * xim->height, IPC_CREAT | 0777);
293
if (shm->shmid == -1) {
294
rfbErr("shmget(%s) failed.\n", name);
295
rfbLogPerror("shmget");
304
shm->shmaddr = xim->data = (char *) shmat(shm->shmid, 0, 0);
306
if (shm->shmaddr == (char *)-1) {
307
rfbErr("shmat(%s) failed.\n", name);
308
rfbLogPerror("shmat");
313
shmctl(shm->shmid, IPC_RMID, 0);
320
shm->readOnly = False;
322
if (! XShmAttach_wr(dpy, shm)) {
323
rfbErr("XShmAttach(%s) failed.\n", name);
328
shm->shmaddr = (char *) -1;
330
shmctl(shm->shmid, IPC_RMID, 0);
342
void shm_delete(XShmSegmentInfo *shm) {
343
#if LIBVNCSERVER_HAVE_XSHM
344
if (shm != NULL && shm->shmaddr != (char *) -1) {
347
if (shm != NULL && shm->shmid != -1) {
348
shmctl(shm->shmid, IPC_RMID, 0);
355
void shm_clean(XShmSegmentInfo *shm, XImage *xim) {
358
if (db) fprintf(stderr, "shm_clean: called: %p\n", (void *)xim);
360
#if LIBVNCSERVER_HAVE_XSHM
361
if (shm != NULL && shm->shmid != -1 && dpy) {
362
if (db) fprintf(stderr, "shm_clean: XShmDetach_wr\n");
363
XShmDetach_wr(dpy, shm);
367
if (! raw_fb_back_to_X) { /* raw_fb hack */
368
if (xim->bitmap_unit != -1) {
369
if (db) fprintf(stderr, "shm_clean: XDestroyImage %p\n", (void *)xim);
373
if (db) fprintf(stderr, "shm_clean: free xim->data %p %p\n", (void *)xim, (void *)(xim->data));
386
void initialize_polling_images(void) {
387
int i, MB = 1024 * 1024;
389
/* set all shm areas to "none" before trying to create any */
390
scanline_shm.shmid = -1;
391
scanline_shm.shmaddr = (char *) -1;
393
fullscreen_shm.shmid = -1;
394
fullscreen_shm.shmaddr = (char *) -1;
396
snaprect_shm.shmid = -1;
397
snaprect_shm.shmaddr = (char *) -1;
399
for (i=1; i<=ntiles_x; i++) {
400
tile_row_shm[i].shmid = -1;
401
tile_row_shm[i].shmaddr = (char *) -1;
405
/* the scanline (e.g. 1280x1) shared memory area image: */
407
if (! shm_create(&scanline_shm, &scanline, dpy_x, 1, "scanline")) {
412
* the fullscreen (e.g. 1280x1024/fs_factor) shared memory area image:
413
* (we cut down the size of the shm area to try avoid and shm segment
414
* limits, e.g. the default 1MB on Solaris)
416
if (UT.sysname && strstr(UT.sysname, "Linux")) {
417
set_fs_factor(10 * MB);
419
set_fs_factor(1 * MB);
421
if (fs_frac >= 1.0) {
426
rfbLog("warning: fullscreen updates are disabled.\n");
428
if (! shm_create(&fullscreen_shm, &fullscreen, dpy_x,
429
dpy_y/fs_factor, "fullscreen")) {
435
rfbLog("warning: disabling -snapfb mode.\n");
437
} else if (! shm_create(&snaprect_shm, &snaprect, dpy_x,
438
dpy_y/fs_factor, "snaprect")) {
444
* for copy_tiles we need a lot of shared memory areas, one for
445
* each possible run length of changed tiles. 32 for 1024x768
446
* and 40 for 1280x1024, etc.
450
for (i=1; i<=ntiles_x; i++) {
451
if (! shm_create(&tile_row_shm[i], &tile_row[i], tile_x * i,
452
tile_y, "tile_row")) {
456
rfbLog("shm: Error creating shared memory tile-row for"
458
rfbLog("shm: reverting to -onetile mode. If this"
459
" problem persists\n");
460
rfbLog("shm: try using the -onetile or -noshm options"
462
rfbLog("shm: shared memory usage, or run ipcrm(1)"
464
rfbLog("shm: delete unattached shm segments.\n");
465
single_copytile_count = i;
469
if (single_copytile && i >= 1) {
470
/* only need 1x1 tiles */
475
if (using_shm && ! xform24to32) {
476
rfbLog("created %d tile_row shm polling images.\n",
479
rfbLog("created %d tile_row polling images.\n",
486
* A hint is a rectangular region built from 1 or more adjacent tiles
487
* glued together. Ultimately, this information in a single hint is sent
488
* to libvncserver rather than sending each tile separately.
490
static void create_tile_hint(int x, int y, int tw, int th, hint_t *hint) {
507
static void extend_tile_hint(int x, int y, int tw, int th, hint_t *hint) {
518
if (hint->x > x) { /* extend to the left */
519
hint->w += hint->x - x;
522
if (hint->y > y) { /* extend upward */
523
hint->h += hint->y - y;
527
if (hint->x + hint->w < x + w) { /* extend to the right */
528
hint->w = x + w - hint->x;
530
if (hint->y + hint->h < y + h) { /* extend downward */
531
hint->h = y + h - hint->y;
535
static void save_hint(hint_t hint, int loc) {
536
/* simply copy it to the global array for later use. */
537
hint_list[loc].x = hint.x;
538
hint_list[loc].y = hint.y;
539
hint_list[loc].w = hint.w;
540
hint_list[loc].h = hint.h;
544
* Glue together horizontal "runs" of adjacent changed tiles into one big
545
* rectangle change "hint" to be passed to the vnc machinery.
547
static void hint_updates(void) {
549
int x, y, i, n, ty, th, tx, tw;
550
int hint_count = 0, in_run = 0;
552
hint.x = hint.y = hint.w = hint.h = 0;
554
for (y=0; y < ntiles_y; y++) {
555
for (x=0; x < ntiles_x; x++) {
556
n = x + y * ntiles_x;
558
if (tile_has_diff[n]) {
559
ty = tile_region[n].first_line;
560
th = tile_region[n].last_line - ty + 1;
562
tx = tile_region[n].first_x;
563
tw = tile_region[n].last_x - tx + 1;
570
create_tile_hint( x * tile_x + tx,
571
y * tile_y + ty, tw, th, &hint);
574
extend_tile_hint( x * tile_x + tx,
575
y * tile_y + ty, tw, th, &hint);
579
/* end of a row run of altered tiles: */
580
save_hint(hint, hint_count++);
585
if (in_run) { /* save the last row run */
586
save_hint(hint, hint_count++);
591
for (i=0; i < hint_count; i++) {
592
/* pass update info to vnc: */
593
mark_hint(hint_list[i]);
598
* kludge, simple ceil+floor for non-negative doubles:
600
#define CEIL(x) ( (double) ((int) (x)) == (x) ? \
601
(double) ((int) (x)) : (double) ((int) (x) + 1) )
602
#define FLOOR(x) ( (double) ((int) (x)) )
607
* For shrinking, a destination (scaled) pixel will correspond to more
608
* than one source (i.e. main fb) pixel. Think of an x-y plane made with
609
* graph paper. Each unit square in the graph paper (i.e. collection of
610
* points (x,y) such that N < x < N+1 and M < y < M+1, N and M integers)
611
* corresponds to one pixel in the unscaled fb. There is a solid
612
* color filling the inside of such a square. A scaled pixel has width
613
* 1/scale_fac, e.g. for "-scale 3/4" the width of the scaled pixel
614
* is 1.333. The area of this scaled pixel is 1.333 * 1.333 (so it
615
* obviously overlaps more than one source pixel, each which have area 1).
617
* We take the weight an unscaled pixel (source) contributes to a
618
* scaled pixel (destination) as simply proportional to the overlap area
619
* between the two pixels. One can then think of the value of the scaled
620
* pixel as an integral over the portion of the graph paper it covers.
621
* The thing being integrated is the color value of the unscaled source.
622
* That color value is constant over a graph paper square (source pixel),
623
* and changes discontinuously from one unit square to the next.
626
Here is an example for -scale 3/4, the solid lines are the source pixels
627
(graph paper unit squares), while the dotted lines denote the scaled
628
pixels (destination pixels):
630
0 1 4/3 2 8/3 3 4=12/3
631
|---------|--.------|------.--|---------|.
636
1 |---------|--.------|------.--|---------|.
637
4/3|.........|.........|.........|.........|.
641
2 |---------|--.------|------.--|---------|.
644
8/3|.........|.........|.........|.........|.
646
3 |---------|--.------|------.--|---------|.
648
So we see the first scaled pixel (0 < x < 4/3 and 0 < y < 4/3) mostly
649
overlaps with unscaled source pixel "A". The integration (averaging)
650
weights for this scaled pixel are:
658
* The Red, Green, and Blue color values must be averaged over separately
659
* otherwise you can get a complete mess (except in solid regions),
660
* because high order bits are averaged differently from the low order bits.
662
* So the algorithm is roughly:
664
* - Given as input a rectangle in the unscaled source fb with changes,
665
* find the rectangle of pixels this affects in the scaled destination fb.
667
* - For each of the affected scaled (dest) pixels, determine all of the
668
* unscaled (source) pixels it overlaps with.
670
* - Average those unscaled source values together, weighted by the area
671
* overlap with the destination pixel. Average R, G, B separately.
673
* - Take this average value and convert to a valid pixel value if
674
* necessary (e.g. rounding, shifting), and then insert it into the
675
* destination framebuffer as the pixel value.
677
* - On to the next destination pixel...
679
* ========================================================================
681
* For expanding, e.g. -scale 1.1 (which we don't think people will do
682
* very often... or at least so we hope, the framebuffer can become huge)
683
* the situation is reversed and the destination pixel is smaller than a
684
* "graph paper" unit square (source pixel). Some destination pixels
685
* will be completely within a single unscaled source pixel.
687
* What we do here is a simple 4 point interpolation scheme:
689
* Let P00 be the source pixel closest to the destination pixel but with
690
* x and y values less than or equal to those of the destination pixel.
691
* (for simplicity, think of the upper left corner of a pixel defining the
692
* x,y location of the pixel, the center would work just as well). So it
693
* is the source pixel immediately to the upper left of the destination
694
* pixel. Let P10 be the source pixel one to the right of P00. Let P01
695
* be one down from P00. And let P11 be one down and one to the right
696
* of P00. They form a 2x2 square we will interpolate inside of.
698
* Let V00, V10, V01, and V11 be the color values of those 4 source
699
* pixels. Let dx be the displacement along x the destination pixel is
700
* from P00. Note: 0 <= dx < 1 by definition of P00. Similarly let
701
* dy be the displacement along y. The weighted average for the
704
* V_ave = V00 * (1 - dx) * (1 - dy)
705
* + V10 * dx * (1 - dy)
706
* + V01 * (1 - dx) * dy
709
* Note that the weights (1-dx)*(1-dy) + dx*(1-dy) + (1-dx)*dy + dx*dy
710
* automatically add up to 1. It is also nice that all the weights are
711
* positive (unsigned char stays unsigned char). The above formula can
712
* be motivated by doing two 1D interpolations along x:
714
* VA = V00 * (1 - dx) + V10 * dx
715
* VB = V01 * (1 - dx) + V11 * dx
717
* and then interpolating VA and VB along y:
719
* V_ave = VA * (1 - dy) + VB * dy
725
* -- | o...|... "o" denotes the position of the desired
726
* ^ | . | . destination pixel relative to the P00
727
* | . | . source pixel.
734
* Of course R, G, B averages are done separately as in the shrinking
735
* case. This gives reasonable results, and the implementation for
736
* shrinking can simply be used with different choices for weights for
737
* the loop over the 4 pixels.
740
void scale_rect(double factor, int blend, int interpolate, int Bpp,
741
char *src_fb, int src_bytes_per_line, char *dst_fb, int dst_bytes_per_line,
742
int Nx, int Ny, int nx, int ny, int X1, int Y1, int X2, int Y2, int mark) {
745
* "i" an x pixel index in the destination (scaled) framebuffer
746
* "j" a y pixel index in the destination (scaled) framebuffer
747
* "I" an x pixel index in the source (un-scaled, i.e. main) framebuffer
748
* "J" a y pixel index in the source (un-scaled, i.e. main) framebuffer
750
* Similarly for nx, ny, Nx, Ny, etc. Lowercase: dest, Uppercase: source.
752
int i, j, i1, i2, j1, j2; /* indices for scaled fb (dest) */
753
int I, J, I1, I2, J1, J2; /* indices for main fb (source) */
755
double w, wx, wy, wtot; /* pixel weights */
757
double x1, y1, x2, y2; /* x-y coords for destination pixels edges */
758
double dx, dy; /* size of destination pixel */
759
double ddx=0, ddy=0; /* for interpolation expansion */
761
char *src, *dest; /* pointers to the two framebuffers */
764
unsigned short us = 0;
765
unsigned char uc = 0;
768
int use_noblend_shortcut = 1;
769
int shrink; /* whether shrinking or expanding */
770
static int constant_weights = -1, mag_int = -1;
771
static int last_Nx = -1, last_Ny = -1, cnt = 0;
772
static double last_factor = -1.0;
774
double pixave[4]; /* for averaging pixel values */
783
* N.B. width and height (real numbers) of a scaled pixel.
784
* both are > 1 (e.g. 1.333 for -scale 3/4)
785
* they should also be equal but we don't assume it.
787
* This new way is probably the best we can do, take the inverse
788
* of the scaling factor to double precision.
794
* There is some speedup if the pixel weights are constant, so
795
* let's special case these.
797
* If scale = 1/n and n divides Nx and Ny, the pixel weights
798
* are constant (e.g. 1/2 => equal on 2x2 square).
800
if (factor != last_factor || Nx != last_Nx || Ny != last_Ny) {
801
constant_weights = -1;
805
last_factor = factor;
808
if (constant_weights < 0) {
811
constant_weights = 0;
814
for (i = 2; i<=128; i++) {
815
double test = ((double) 1)/ i;
816
double diff, eps = 1.0e-7;
817
diff = factor - test;
818
if (-eps < diff && diff < eps) {
823
if (! blend || ! shrink || interpolate) {
826
if (Nx % n == 0 && Ny % n == 0) {
827
static int didmsg = 0;
828
if (mark && ! didmsg) {
830
rfbLog("scale_and_mark_rect: using "
831
"constant pixel weight speedup "
834
constant_weights = 1;
839
for (i = 2; i<=32; i++) {
840
double test = (double) i;
841
double diff, eps = 1.0e-7;
842
diff = factor - test;
843
if (-eps < diff && diff < eps) {
848
if (! blend && factor > 1.0 && n) {
853
if (mark && factor > 1.0 && blend) {
855
* kludge: correct for interpolating blurring leaking
856
* up or left 1 destination pixel.
863
* find the extent of the change the input rectangle induces in
864
* the scaled framebuffer.
867
/* Left edges: find largest i such that i * dx <= X1 */
870
/* Right edges: find smallest i such that (i+1) * dx >= X2+1 */
871
i2 = CEIL( (X2+1)/dx ) - 1;
873
/* To be safe, correct any overflows: */
875
i2 = nfix(i2, nx) + 1; /* add 1 to make a rectangle upper boundary */
877
/* Repeat above for y direction: */
879
j2 = CEIL( (Y2+1)/dy ) - 1;
882
j2 = nfix(j2, ny) + 1;
884
/* special case integer magnification with no blending */
885
if (mark && ! blend && mag_int && Bpp != 3) {
886
int jmin, jmax, imin, imax;
888
/* outer loop over *source* pixels */
889
for (J=Y1; J < Y2; J++) {
891
jmax = jmin + mag_int;
892
for (I=X1; I < X2; I++) {
894
src = src_fb + J*src_bytes_per_line + I*Bpp;
896
ui = *((unsigned int *)src);
897
} else if (Bpp == 2) {
898
us = *((unsigned short *)src);
899
} else if (Bpp == 1) {
900
uc = *((unsigned char *)src);
903
imax = imin + mag_int;
904
/* inner loop over *dest* pixels */
905
for (j=jmin; j<jmax; j++) {
906
dest = dst_fb + j*dst_bytes_per_line + imin*Bpp;
907
for (i=imin; i<imax; i++) {
909
*((unsigned int *)dest) = ui;
910
} else if (Bpp == 2) {
911
*((unsigned short *)dest) = us;
912
} else if (Bpp == 1) {
913
*((unsigned char *)dest) = uc;
923
/* set these all to 1.0 to begin with */
929
* Loop over destination pixels in scaled fb:
931
for (j=j1; j<j2; j++) {
932
y1 = j * dy; /* top edge */
934
/* can go over with dy = 1/scale_fac */
937
y2 = y1 + dy; /* bottom edge */
939
/* Find main fb indices covered by this dest pixel: */
940
J1 = (int) FLOOR(y1);
943
if (shrink && ! interpolate) {
944
J2 = (int) CEIL(y2) - 1;
947
J2 = J1 + 1; /* simple interpolation */
951
/* destination char* pointer: */
952
dest = dst_fb + j*dst_bytes_per_line + i1*Bpp;
954
for (i=i1; i<i2; i++) {
956
x1 = i * dx; /* left edge */
958
/* can go over with dx = 1/scale_fac */
961
x2 = x1 + dx; /* right edge */
965
/* Find main fb indices covered by this dest pixel: */
966
I1 = (int) FLOOR(x1);
967
if (I1 >= Nx) I1 = Nx - 1;
969
if (! blend && use_noblend_shortcut) {
971
* The noblend case involves no weights,
972
* and 1 pixel, so just copy the value
975
src = src_fb + J1*src_bytes_per_line + I1*Bpp;
977
*((unsigned int *)dest)
978
= *((unsigned int *)src);
979
} else if (Bpp == 2) {
980
*((unsigned short *)dest)
981
= *((unsigned short *)src);
982
} else if (Bpp == 1) {
984
} else if (Bpp == 3) {
986
for (k=0; k<=2; k++) {
987
*(dest+k) = *(src+k);
994
if (shrink && ! interpolate) {
995
I2 = (int) CEIL(x2) - 1;
996
if (I2 >= Nx) I2 = Nx - 1;
998
I2 = I1 + 1; /* simple interpolation */
1002
/* Zero out accumulators for next pixel average: */
1003
for (b=0; b<4; b++) {
1004
pixave[b] = 0.0; /* for RGB weighted sums */
1008
* wtot is for accumulating the total weight.
1009
* It should always sum to 1/(scale_fac * scale_fac).
1014
* Loop over source pixels covered by this dest pixel.
1016
* These "extra" loops over "J" and "I" make
1017
* the cache/cacheline performance unclear.
1018
* For example, will the data brought in from
1019
* src for j, i, and J=0 still be in the cache
1020
* after the J > 0 data have been accessed and
1021
* we are at j, i+1, J=0? The stride in J is
1022
* main_bytes_per_line, and so ~4 KB.
1024
* Typical case when shrinking are 2x2 loop, so
1025
* just two lines to worry about.
1027
for (J=J1; J<=J2; J++) {
1028
/* see comments for I, x1, x2, etc. below */
1029
if (constant_weights) {
1031
} else if (! blend) {
1037
/* interpolation scheme: */
1038
} else if (! shrink || interpolate) {
1041
} else if (J == J1) {
1043
} else if (J != J1) {
1047
/* integration scheme: */
1048
} else if (J < y1) {
1050
} else if (J+1 > y2) {
1056
src = src_fb + J*src_bytes_per_line + I1*Bpp;
1058
for (I=I1; I<=I2; I++) {
1060
/* Work out the weight: */
1062
if (constant_weights) {
1064
} else if (! blend) {
1066
* Ugh, PseudoColor colormap is
1067
* bad news, to avoid random
1068
* colors just take the first
1069
* pixel. Or user may have
1070
* specified :nb to fraction.
1071
* The :fb will force blending
1079
/* interpolation scheme: */
1080
} else if (! shrink || interpolate) {
1082
continue; /* off edge */
1083
} else if (I == I1) {
1085
} else if (I != I1) {
1089
/* integration scheme: */
1090
} else if (I < x1) {
1092
* source left edge (I) to the
1093
* left of dest left edge (x1):
1097
} else if (I+1 > x2) {
1099
* source right edge (I+1) to the
1100
* right of dest right edge (x2):
1106
* source edges (I and I+1) completely
1107
* inside dest edges (x1 and x2):
1117
* We average the unsigned char value
1118
* instead of char value: otherwise
1119
* the minimum (char 0) is right next
1120
* to the maximum (char -1)! This way
1121
* they are spread between 0 and 255.
1124
/* unroll the loops, can give 20% */
1126
((unsigned char) *(src ));
1128
((unsigned char) *(src+1));
1130
((unsigned char) *(src+2));
1132
((unsigned char) *(src+3));
1133
} else if (Bpp == 2) {
1135
* 16bpp: trickier with green
1136
* split over two bytes, so we
1139
us = *((unsigned short *) src);
1140
pixave[0] += w*(us & main_red_mask);
1141
pixave[1] += w*(us & main_green_mask);
1142
pixave[2] += w*(us & main_blue_mask);
1143
} else if (Bpp == 1) {
1145
((unsigned char) *(src));
1147
for (b=0; b<Bpp; b++) {
1149
((unsigned char) *(src+b));
1159
wtot = 1.0/wtot; /* normalization factor */
1161
/* place weighted average pixel in the scaled fb: */
1163
*(dest ) = (char) (wtot * pixave[0]);
1164
*(dest+1) = (char) (wtot * pixave[1]);
1165
*(dest+2) = (char) (wtot * pixave[2]);
1166
*(dest+3) = (char) (wtot * pixave[3]);
1167
} else if (Bpp == 2) {
1168
/* 16bpp / 565 case: */
1172
us = (main_red_mask & (int) pixave[0])
1173
| (main_green_mask & (int) pixave[1])
1174
| (main_blue_mask & (int) pixave[2]);
1175
*( (unsigned short *) dest ) = us;
1176
} else if (Bpp == 1) {
1177
*(dest) = (char) (wtot * pixave[0]);
1179
for (b=0; b<Bpp; b++) {
1180
*(dest+b) = (char) (wtot * pixave[b]);
1188
mark_rect_as_modified(i1, j1, i2, j2, 1);
1193
Framebuffers data flow:
1196
-------- -------- -------- --------
1197
----- |8to24_fb| |main_fb | |snap_fb | | X |
1198
|rfbfb| <== | | <== | | <== | | <== | Server |
1199
----- -------- -------- -------- --------
1200
(to vnc) (optional) (usu = rfbfb) (optional) (read only)
1202
8to24_fb mode will create side fbs: poll24_fb and poll8_fb for
1203
bookkeepping the different regions (merged into 8to24_fb).
1208
|= rfb_fb| <== | Server |
1213
----- |main_fb | | X |
1214
|rfbfb| <== | | <== | Server |
1215
----- -------- --------
1218
-------- -------- --------
1219
|main_fb | |snap_fb | | Video |
1220
| | <== | | <== | device |
1221
-------- -------- --------
1223
If we ever do a -rr rotation/reflection tran, it probably should
1224
be done after any scaling (need a rr_fb for intermediate results)
1226
-rr option: transformation:
1246
+90y x -> h - y - 1;
1254
xy: yx, +180, -180, 180
1261
void scale_and_mark_rect(int X1, int Y1, int X2, int Y2, int mark) {
1262
char *dst_fb, *src_fb = main_fb;
1263
int dst_bpl, Bpp = bpp/8, fac = 1;
1265
if (!screen || !rfb_fb || !main_fb) {
1268
if (! screen->serverFormat.trueColour) {
1270
* PseudoColor colormap... blending leads to random colors.
1271
* User can override with ":fb"
1273
if (scaling_blend == 1) {
1274
/* :fb option sets it to 2 */
1275
if (default_visual->class == StaticGray) {
1277
* StaticGray can be blended OK, otherwise
1278
* user can disable with :nb
1287
if (cmap8to24 && cmap8to24_fb) {
1288
src_fb = cmap8to24_fb;
1289
if (scaling && depth == 8) {
1294
dst_bpl = rfb_bytes_per_line;
1296
scale_rect(scale_fac, scaling_blend, scaling_interpolate, fac * Bpp,
1297
src_fb, fac * main_bytes_per_line, dst_fb, dst_bpl, dpy_x, dpy_y,
1298
scaled_x, scaled_y, X1, Y1, X2, Y2, mark);
1301
void rotate_coords(int x, int y, int *xo, int *yo, int dxi, int dyi) {
1308
} else if (scaling) {
1318
if (rotating == ROTATE_NONE) {
1321
} else if (rotating == ROTATE_X) {
1324
} else if (rotating == ROTATE_Y) {
1327
} else if (rotating == ROTATE_XY) {
1330
} else if (rotating == ROTATE_90) {
1333
} else if (rotating == ROTATE_90X) {
1336
} else if (rotating == ROTATE_90Y) {
1339
} else if (rotating == ROTATE_270) {
1345
void rotate_coords_inverse(int x, int y, int *xo, int *yo, int dxi, int dyi) {
1353
} else if (scaling) {
1360
if (! rotating_same) {
1366
if (rotating == ROTATE_NONE) {
1369
} else if (rotating == ROTATE_X) {
1372
} else if (rotating == ROTATE_Y) {
1375
} else if (rotating == ROTATE_XY) {
1378
} else if (rotating == ROTATE_90) {
1381
} else if (rotating == ROTATE_90X) {
1384
} else if (rotating == ROTATE_90Y) {
1387
} else if (rotating == ROTATE_270) {
1393
/* unroll the Bpp loop to be used in each case: */
1395
src = src_0 + fbl*y + Bpp*x; \
1396
dst = dst_0 + rbl*yn + Bpp*xn; \
1399
} else if (Bpp == 2) { \
1400
*(dst+0) = *(src+0); \
1401
*(dst+1) = *(src+1); \
1402
} else if (Bpp == 3) { \
1403
*(dst+0) = *(src+0); \
1404
*(dst+1) = *(src+1); \
1405
*(dst+2) = *(src+2); \
1406
} else if (Bpp == 4) { \
1407
*(dst+0) = *(src+0); \
1408
*(dst+1) = *(src+1); \
1409
*(dst+2) = *(src+2); \
1410
*(dst+3) = *(src+3); \
1413
void rotate_fb(int x1, int y1, int x2, int y2) {
1414
int x, y, xn, yn, r_x1, r_y1, r_x2, r_y2, Bpp = bpp/8;
1415
int fbl = rfb_bytes_per_line;
1416
int rbl = rot_bytes_per_line;
1419
char *src_0 = rfb_fb;
1420
char *dst_0 = rot_fb;
1422
if (! rotating || ! rot_fb) {
1433
rotate_coords(x1, y1, &r_x1, &r_y1, -1, -1);
1434
rotate_coords(x2, y2, &r_x2, &r_y2, -1, -1);
1438
if (rotating == ROTATE_X) {
1439
for (y = y1; y < y2; y++) {
1440
for (x = x1; x < x2; x++) {
1446
} else if (rotating == ROTATE_Y) {
1447
for (y = y1; y < y2; y++) {
1448
for (x = x1; x < x2; x++) {
1454
} else if (rotating == ROTATE_XY) {
1455
for (y = y1; y < y2; y++) {
1456
for (x = x1; x < x2; x++) {
1462
} else if (rotating == ROTATE_90) {
1463
for (y = y1; y < y2; y++) {
1464
for (x = x1; x < x2; x++) {
1470
} else if (rotating == ROTATE_90X) {
1471
for (y = y1; y < y2; y++) {
1472
for (x = x1; x < x2; x++) {
1478
} else if (rotating == ROTATE_90Y) {
1479
for (y = y1; y < y2; y++) {
1480
for (x = x1; x < x2; x++) {
1486
} else if (rotating == ROTATE_270) {
1487
for (y = y1; y < y2; y++) {
1488
for (x = x1; x < x2; x++) {
1497
void rotate_curs(char *dst_0, char *src_0, int Dx, int Dy, int Bpp) {
1507
if (rotating_same) {
1513
if (rotating == ROTATE_X) {
1514
for (y = 0; y < Dy; y++) {
1515
for (x = 0; x < Dx; x++) {
1519
if (0) fprintf(stderr, "rcurs: %d %d %d %d\n", x, y, xn, yn);
1522
} else if (rotating == ROTATE_Y) {
1523
for (y = 0; y < Dy; y++) {
1524
for (x = 0; x < Dx; x++) {
1530
} else if (rotating == ROTATE_XY) {
1531
for (y = 0; y < Dy; y++) {
1532
for (x = 0; x < Dx; x++) {
1538
} else if (rotating == ROTATE_90) {
1539
for (y = 0; y < Dy; y++) {
1540
for (x = 0; x < Dx; x++) {
1546
} else if (rotating == ROTATE_90X) {
1547
for (y = 0; y < Dy; y++) {
1548
for (x = 0; x < Dx; x++) {
1554
} else if (rotating == ROTATE_90Y) {
1555
for (y = 0; y < Dy; y++) {
1556
for (x = 0; x < Dx; x++) {
1562
} else if (rotating == ROTATE_270) {
1563
for (y = 0; y < Dy; y++) {
1564
for (x = 0; x < Dx; x++) {
1573
void mark_wrapper(int x1, int y1, int x2, int y2) {
1574
int t, r_x1 = x1, r_y1 = y1, r_x2 = x2, r_y2 = y2;
1577
/* well we hope rot_fb will always be the last one... */
1578
rotate_coords(x1, y1, &r_x1, &r_y1, -1, -1);
1579
rotate_coords(x2, y2, &r_x2, &r_y2, -1, -1);
1580
rotate_fb(x1, y1, x2, y2);
1591
/* painting errors */
1597
rfbMarkRectAsModified(screen, r_x1, r_y1, r_x2, r_y2);
1600
void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force) {
1602
if (damage_time != 0) {
1604
* This is not XDAMAGE, rather a hack for testing
1605
* where we allow the framebuffer to be corrupted for
1606
* damage_delay seconds.
1609
if (time(NULL) > damage_time + damage_delay) {
1611
rfbLog("damaging turned off.\n");
1617
rfbLog("damaging viewer fb by not marking "
1618
"rect: %d,%d,%d,%d\n", x1, y1, x2, y2);
1625
if (rfb_fb == main_fb || force) {
1626
mark_wrapper(x1, y1, x2, y2);
1631
bpp8to24(x1, y1, x2, y2);
1635
scale_and_mark_rect(x1, y1, x2, y2, 1);
1637
mark_wrapper(x1, y1, x2, y2);
1642
* Notifies libvncserver of a changed hint rectangle.
1644
static void mark_hint(hint_t hint) {
1650
mark_rect_as_modified(x, y, x + w, y + h, 0);
1654
* copy_tiles() gives a slight improvement over copy_tile() since
1655
* adjacent runs of tiles are done all at once there is some savings
1656
* due to contiguous memory access. Not a great speedup, but in some
1657
* cases it can be up to 2X. Even more on a SunRay or ShadowFB where
1658
* no graphics hardware is involved in the read. Generally, graphics
1659
* devices are optimized for write, not read, so we are limited by the
1660
* read bandwidth, sometimes only 5 MB/sec on otherwise fast hardware.
1662
static int *first_line = NULL, *last_line = NULL;
1663
static unsigned short *left_diff = NULL, *right_diff = NULL;
1665
static int copy_tiles(int tx, int ty, int nt) {
1667
int size_x, size_y, width1, width2;
1668
int off, len, n, dw, dx, t;
1669
int w1, w2, dx1, dx2; /* tmps for normal and short tiles */
1670
int pixelsize = bpp/8;
1671
int first_min, last_max;
1672
int first_x = -1, last_x = -1;
1673
static int prev_ntiles_x = -1;
1675
char *src, *dst, *s_src, *s_dst, *m_src, *m_dst;
1676
char *h_src, *h_dst;
1677
if (unixpw_in_progress) return 0;
1679
if (ntiles_x != prev_ntiles_x && first_line != NULL) {
1680
free(first_line); first_line = NULL;
1681
free(last_line); last_line = NULL;
1682
free(left_diff); left_diff = NULL;
1683
free(right_diff); right_diff = NULL;
1686
if (first_line == NULL) {
1687
/* allocate arrays first time in. */
1688
int n = ntiles_x + 1;
1689
rfbLog("copy_tiles: allocating first_line at size %d\n", n);
1690
first_line = (int *) malloc((size_t) (n * sizeof(int)));
1691
last_line = (int *) malloc((size_t) (n * sizeof(int)));
1692
left_diff = (unsigned short *)
1693
malloc((size_t) (n * sizeof(unsigned short)));
1694
right_diff = (unsigned short *)
1695
malloc((size_t) (n * sizeof(unsigned short)));
1697
prev_ntiles_x = ntiles_x;
1703
if ( size_x > tile_x * nt ) {
1704
size_x = tile_x * nt;
1709
width1 = tile_x; /* internal tile */
1710
width2 = size_x - (nt - 1) * tile_x; /* right hand tile */
1714
if ( size_y > tile_y ) {
1718
n = tx + ty * ntiles_x; /* number of the first tile */
1720
if (blackouts && tile_blackout[n].cover == 2) {
1722
* If there are blackouts and this tile is completely covered
1723
* no need to poll screen or do anything else..
1724
* n.b. we are in single copy_tile mode: nt=1
1726
tile_has_diff[n] = 0;
1731
XRANDR_SET_TRAP_RET(-1, "copy_tile-set");
1732
/* read in the whole tile run at once: */
1733
copy_image(tile_row[nt], x, y, size_x, size_y);
1734
XRANDR_CHK_TRAP_RET(-1, "copy_tile-chk");
1738
if (blackouts && tile_blackout[n].cover == 1) {
1740
* If there are blackouts and this tile is partially covered
1741
* we should re-black-out the portion.
1742
* n.b. we are in single copy_tile mode: nt=1
1744
int x1, x2, y1, y2, b;
1747
for (b=0; b < tile_blackout[n].count; b++) {
1748
char *b_dst = tile_row[nt]->data;
1750
x1 = tile_blackout[n].bo[b].x1 - x;
1751
y1 = tile_blackout[n].bo[b].y1 - y;
1752
x2 = tile_blackout[n].bo[b].x2 - x;
1753
y2 = tile_blackout[n].bo[b].y2 - y;
1755
w = (x2 - x1) * pixelsize;
1758
for (line = 0; line < size_y; line++) {
1759
if (y1 <= line && line < y2) {
1760
memset(b_dst + s, fill, (size_t) w);
1762
b_dst += tile_row[nt]->bytes_per_line;
1767
src = tile_row[nt]->data;
1768
dst = main_fb + y * main_bytes_per_line + x * pixelsize;
1773
for (t=1; t <= nt; t++) {
1777
/* find the first line with difference: */
1778
w1 = width1 * pixelsize;
1779
w2 = width2 * pixelsize;
1782
for (line = 0; line < size_y; line++) {
1783
/* foreach horizontal tile: */
1784
for (t=1; t <= nt; t++) {
1785
if (first_line[t] != -1) {
1791
len = w2; /* possible short tile */
1796
if (memcmp(s_dst + off, s_src + off, len)) {
1797
first_line[t] = line;
1800
s_src += tile_row[nt]->bytes_per_line;
1801
s_dst += main_bytes_per_line;
1804
/* see if there were any differences for any tile: */
1806
for (t=1; t <= nt; t++) {
1807
tile_tried[n+(t-1)] = 1;
1808
if (first_line[t] != -1) {
1809
if (first_min == -1 || first_line[t] < first_min) {
1810
first_min = first_line[t];
1814
if (first_min == -1) {
1815
/* no tile has a difference, note this and get out: */
1816
for (t=1; t <= nt; t++) {
1817
tile_has_diff[n+(t-1)] = 0;
1822
* at least one tile has a difference. make sure info
1823
* is recorded (e.g. sometimes we guess tiles and they
1824
* came in with tile_has_diff 0)
1826
for (t=1; t <= nt; t++) {
1827
if (first_line[t] == -1) {
1828
tile_has_diff[n+(t-1)] = 0;
1830
tile_has_diff[n+(t-1)] = 1;
1835
m_src = src + (tile_row[nt]->bytes_per_line * size_y);
1836
m_dst = dst + (main_bytes_per_line * size_y);
1838
for (t=1; t <= nt; t++) {
1839
last_line[t] = first_line[t];
1842
/* find the last line with difference: */
1843
w1 = width1 * pixelsize;
1844
w2 = width2 * pixelsize;
1847
for (line = size_y - 1; line > first_min; line--) {
1849
m_src -= tile_row[nt]->bytes_per_line;
1850
m_dst -= main_bytes_per_line;
1853
for (t=1; t <= nt; t++) {
1854
if (first_line[t] == -1
1855
|| last_line[t] != first_line[t]) {
1856
/* tile has no changes or already done */
1862
len = w2; /* possible short tile */
1866
if (memcmp(m_dst + off, m_src + off, len)) {
1867
last_line[t] = line;
1873
* determine the farthest down last changed line
1874
* will be used below to limit our memcpy() to the framebuffer.
1877
for (t=1; t <= nt; t++) {
1878
if (first_line[t] == -1) {
1881
if (last_max == -1 || last_line[t] > last_max) {
1882
last_max = last_line[t];
1886
/* look for differences on left and right hand edges: */
1887
for (t=1; t <= nt; t++) {
1895
w1 = width1 * pixelsize;
1896
w2 = width2 * pixelsize;
1898
dx1 = (width1 - tile_fuzz) * pixelsize;
1899
dx2 = (width2 - tile_fuzz) * pixelsize;
1900
dw = tile_fuzz * pixelsize;
1903
for (line = 0; line < size_y; line++) {
1905
for (t=1; t <= nt; t++) {
1906
if (first_line[t] == -1) {
1907
/* tile has no changes at all */
1913
dx = dx2; /* possible short tile */
1921
if (! left_diff[t] && memcmp(h_dst + off,
1925
if (! right_diff[t] && memcmp(h_dst + off + dx,
1926
h_src + off + dx, dw) ) {
1930
h_src += tile_row[nt]->bytes_per_line;
1931
h_dst += main_bytes_per_line;
1934
/* now finally copy the difference to the rfb framebuffer: */
1935
s_src = src + tile_row[nt]->bytes_per_line * first_min;
1936
s_dst = dst + main_bytes_per_line * first_min;
1938
for (line = first_min; line <= last_max; line++) {
1939
/* for I/O speed we do not do this tile by tile */
1940
memcpy(s_dst, s_src, size_x * pixelsize);
1943
* optimization for tall skinny lines, e.g. wm
1944
* frame. try to find first_x and last_x to limit
1945
* the size of the hint. could help for a slow
1946
* link. Unfortunately we spent a lot of time
1947
* reading in the many tiles.
1949
* BTW, we like to think the above memcpy leaves
1950
* the data we use below in the cache... (but
1951
* it could be two 128 byte segments at 32bpp)
1952
* so this inner loop is not as bad as it seems.
1956
for (k=0; k<size_x; k++) {
1957
if (memcmp(s_dst + k*kx, s_src + k*kx, kx)) {
1958
if (first_x == -1 || k < first_x) {
1961
if (last_x == -1 || k > last_x) {
1967
s_src += tile_row[nt]->bytes_per_line;
1968
s_dst += main_bytes_per_line;
1971
/* record all the info in the region array for this tile: */
1972
for (t=1; t <= nt; t++) {
1975
if (first_line[t] == -1) {
1976
/* tile unchanged */
1979
tile_region[n+s].first_line = first_line[t];
1980
tile_region[n+s].last_line = last_line[t];
1982
tile_region[n+s].first_x = first_x;
1983
tile_region[n+s].last_x = last_x;
1985
tile_region[n+s].top_diff = 0;
1986
tile_region[n+s].bot_diff = 0;
1987
if ( first_line[t] < tile_fuzz ) {
1988
tile_region[n+s].top_diff = 1;
1990
if ( last_line[t] > (size_y - 1) - tile_fuzz ) {
1991
tile_region[n+s].bot_diff = 1;
1994
tile_region[n+s].left_diff = left_diff[t];
1995
tile_region[n+s].right_diff = right_diff[t];
1997
tile_copied[n+s] = 1;
2004
* The copy_tile() call in the loop below copies the changed tile into
2005
* the rfb framebuffer. Note that copy_tile() sets the tile_region
2006
* struct to have info about the y-range of the changed region and also
2007
* whether the tile edges contain diffs (within distance tile_fuzz).
2009
* We use this tile_region info to try to guess if the downward and right
2010
* tiles will have diffs. These tiles will be checked later in the loop
2011
* (since y+1 > y and x+1 > x).
2013
* See copy_tiles_backward_pass() for analogous checking upward and
2016
static int copy_all_tiles(void) {
2020
if (unixpw_in_progress) return 0;
2022
for (y=0; y < ntiles_y; y++) {
2023
for (x=0; x < ntiles_x; x++) {
2024
n = x + y * ntiles_x;
2026
if (tile_has_diff[n]) {
2027
ct = copy_tiles(x, y, 1);
2028
if (ct < 0) return ct; /* fatal */
2030
if (! tile_has_diff[n]) {
2032
* n.b. copy_tiles() may have detected
2033
* no change and reset tile_has_diff to 0.
2039
/* neighboring tile downward: */
2040
if ( (y+1) < ntiles_y && tile_region[n].bot_diff) {
2041
m = x + (y+1) * ntiles_x;
2042
if (! tile_has_diff[m]) {
2043
tile_has_diff[m] = 2;
2046
/* neighboring tile to right: */
2047
if ( (x+1) < ntiles_x && tile_region[n].right_diff) {
2048
m = (x+1) + y * ntiles_x;
2049
if (! tile_has_diff[m]) {
2050
tile_has_diff[m] = 2;
2059
* Routine analogous to copy_all_tiles() above, but for horizontal runs
2060
* of adjacent changed tiles.
2062
static int copy_all_tile_runs(void) {
2065
int in_run = 0, run = 0;
2066
int ntave = 0, ntcnt = 0;
2068
if (unixpw_in_progress) return 0;
2070
for (y=0; y < ntiles_y; y++) {
2071
for (x=0; x < ntiles_x + 1; x++) {
2072
n = x + y * ntiles_x;
2074
if (x != ntiles_x && tile_has_diff[n]) {
2083
ct = copy_tiles(x - run, y, run);
2084
if (ct < 0) return ct; /* fatal */
2090
/* neighboring tile downward: */
2091
for (i=1; i <= run; i++) {
2092
if ((y+1) < ntiles_y
2093
&& tile_region[n-i].bot_diff) {
2094
m = (x-i) + (y+1) * ntiles_x;
2095
if (! tile_has_diff[m]) {
2096
tile_has_diff[m] = 2;
2101
/* neighboring tile to right: */
2102
if (((x-1)+1) < ntiles_x
2103
&& tile_region[n-1].right_diff) {
2104
m = ((x-1)+1) + y * ntiles_x;
2105
if (! tile_has_diff[m]) {
2106
tile_has_diff[m] = 2;
2109
/* note that this starts a new run */
2119
* Could some activity go here, to emulate threaded
2120
* behavior by servicing some libvncserver tasks?
2127
* Here starts a bunch of heuristics to guess/detect changed tiles.
2129
* copy_tiles_backward_pass, fill_tile_gaps/gap_try, grow_islands/island_try
2133
* Try to predict whether the upward and/or leftward tile has been modified.
2134
* copy_all_tiles() has already done downward and rightward tiles.
2136
static int copy_tiles_backward_pass(void) {
2140
if (unixpw_in_progress) return 0;
2142
for (y = ntiles_y - 1; y >= 0; y--) {
2143
for (x = ntiles_x - 1; x >= 0; x--) {
2144
n = x + y * ntiles_x; /* number of this tile */
2146
if (! tile_has_diff[n]) {
2150
m = x + (y-1) * ntiles_x; /* neighboring tile upward */
2152
if (y >= 1 && ! tile_has_diff[m] && tile_region[n].top_diff) {
2153
if (! tile_tried[m]) {
2154
tile_has_diff[m] = 2;
2155
ct = copy_tiles(x, y-1, 1);
2156
if (ct < 0) return ct; /* fatal */
2160
m = (x-1) + y * ntiles_x; /* neighboring tile to left */
2162
if (x >= 1 && ! tile_has_diff[m] && tile_region[n].left_diff) {
2163
if (! tile_tried[m]) {
2164
tile_has_diff[m] = 2;
2165
ct = copy_tiles(x-1, y, 1);
2166
if (ct < 0) return ct; /* fatal */
2171
for (n=0; n < ntiles; n++) {
2172
if (tile_has_diff[n]) {
2179
static int copy_tiles_additional_pass(void) {
2183
if (unixpw_in_progress) return 0;
2185
for (y=0; y < ntiles_y; y++) {
2186
for (x=0; x < ntiles_x; x++) {
2187
n = x + y * ntiles_x; /* number of this tile */
2189
if (! tile_has_diff[n]) {
2192
if (tile_copied[n]) {
2196
ct = copy_tiles(x, y, 1);
2197
if (ct < 0) return ct; /* fatal */
2200
for (n=0; n < ntiles; n++) {
2201
if (tile_has_diff[n]) {
2208
static int gap_try(int x, int y, int *run, int *saw, int along_x) {
2209
int n, m, i, xt, yt, ct;
2211
n = x + y * ntiles_x;
2213
if (! tile_has_diff[n]) {
2215
(*run)++; /* extend the gap run. */
2219
if (! *saw || *run == 0 || *run > gaps_fill) {
2220
*run = 0; /* unacceptable run. */
2225
for (i=1; i <= *run; i++) { /* iterate thru the run. */
2234
m = xt + yt * ntiles_x;
2235
if (tile_tried[m]) { /* do not repeat tiles */
2239
ct = copy_tiles(xt, yt, 1);
2240
if (ct < 0) return ct; /* fatal */
2248
* Look for small gaps of unchanged tiles that may actually contain changes.
2249
* E.g. when paging up and down in a web broswer or terminal there can
2250
* be a distracting delayed filling in of such gaps. gaps_fill is the
2251
* tweak parameter that sets the width of the gaps that are checked.
2253
* BTW, grow_islands() is actually pretty successful at doing this too...
2255
static int fill_tile_gaps(void) {
2257
int n, diffs = 0, ct;
2260
for (y=0; y < ntiles_y; y++) {
2263
for (x=0; x < ntiles_x; x++) {
2264
ct = gap_try(x, y, &run, &saw, 1);
2265
if (ct < 0) return ct; /* fatal */
2270
for (x=0; x < ntiles_x; x++) {
2273
for (y=0; y < ntiles_y; y++) {
2274
ct = gap_try(x, y, &run, &saw, 0);
2275
if (ct < 0) return ct; /* fatal */
2279
for (n=0; n < ntiles; n++) {
2280
if (tile_has_diff[n]) {
2287
static int island_try(int x, int y, int u, int v, int *run) {
2290
n = x + y * ntiles_x;
2291
m = u + v * ntiles_x;
2293
if (tile_has_diff[n]) {
2299
if (tile_has_diff[n] && ! tile_has_diff[m]) {
2300
/* found a discontinuity */
2302
if (tile_tried[m]) {
2304
} else if (*run < grow_fill) {
2308
ct = copy_tiles(u, v, 1);
2309
if (ct < 0) return ct; /* fatal */
2315
* Scan looking for discontinuities in tile_has_diff[]. Try to extend
2316
* the boundary of the discontinuity (i.e. make the island larger).
2317
* Vertical scans are skipped since they do not seem to yield much...
2319
static int grow_islands(void) {
2324
* n.b. the way we scan here should keep an extension going,
2325
* and so also fill in gaps effectively...
2328
/* left to right: */
2329
for (y=0; y < ntiles_y; y++) {
2331
for (x=0; x <= ntiles_x - 2; x++) {
2332
ct = island_try(x, y, x+1, y, &run);
2333
if (ct < 0) return ct; /* fatal */
2336
/* right to left: */
2337
for (y=0; y < ntiles_y; y++) {
2339
for (x = ntiles_x - 1; x >= 1; x--) {
2340
ct = island_try(x, y, x-1, y, &run);
2341
if (ct < 0) return ct; /* fatal */
2344
for (n=0; n < ntiles; n++) {
2345
if (tile_has_diff[n]) {
2353
* Fill the framebuffer with zeros for each blackout region
2355
static void blackout_regions(void) {
2357
for (i=0; i < blackouts; i++) {
2358
zero_fb(blackr[i].x1, blackr[i].y1, blackr[i].x2, blackr[i].y2);
2363
* copy the whole X screen to the rfb framebuffer. For a large enough
2364
* number of changed tiles, this is faster than tiles scheme at retrieving
2365
* the info from the X server. Bandwidth to client and compression time
2366
* are other issues... use -fs 1.0 to disable.
2368
int copy_screen(void) {
2370
int i, y, block_size;
2375
if (debug_tiles) fprintf(stderr, "copy_screen\n");
2377
if (unixpw_in_progress) return 0;
2384
block_size = ((dpy_y/fs_factor) * main_bytes_per_line);
2391
/* screen may be too big for 1 shm area, so broken into fs_factor */
2392
for (i=0; i < fs_factor; i++) {
2393
XRANDR_SET_TRAP_RET(-1, "copy_screen-set");
2394
copy_image(fullscreen, 0, y, 0, 0);
2395
XRANDR_CHK_TRAP_RET(-1, "copy_screen-chk");
2397
memcpy(fbp, fullscreen->data, (size_t) block_size);
2399
y += dpy_y / fs_factor;
2409
mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
2413
static void snap_all_rawfb(void) {
2414
int pixelsize = bpp/8;
2417
static char *unclipped_dst = NULL;
2418
static int unclipped_len = 0;
2422
if (xform24to32 && bpp == 32) {
2425
sz = dpy_y * snap->bytes_per_line;
2427
if (wdpy_x > dpy_x || wdpy_y > dpy_y) {
2428
sz = wdpy_x * wdpy_y * pixelsize;
2429
if (sz > unclipped_len || unclipped_dst == NULL) {
2430
if (unclipped_dst) {
2431
free(unclipped_dst);
2433
unclipped_dst = (char *) malloc(sz+4);
2436
dst = unclipped_dst;
2439
if (! raw_fb_seek) {
2440
memcpy(dst, raw_fb_addr + raw_fb_offset, sz);
2443
int len = sz, del = 0;
2444
off_t off = (off_t) raw_fb_offset;
2446
lseek(raw_fb_fd, off, SEEK_SET);
2448
n = read(raw_fb_fd, dst + del, len);
2452
} else if (n == 0) {
2454
} else if (errno != EINTR && errno != EAGAIN) {
2460
if (dst == unclipped_dst) {
2463
int x = off_x + coff_x;
2464
int y = off_y + coff_y;
2466
src = unclipped_dst + y * wdpy_x * pixelsize +
2470
for (h = 0; h < dpy_y; h++) {
2471
memcpy(dst, src, dpy_x * pixelsize);
2472
src += wdpy_x * pixelsize;
2473
dst += snap->bytes_per_line;
2478
int copy_snap(void) {
2481
int i, y, block_size;
2483
static int first = 1, snapcnt = 0;
2486
int read_all_at_once = 1;
2487
double start = dnow();
2488
if (rawfb_reset < 0) {
2489
if (getenv("SNAPFB_RAWFB_RESET")) {
2495
if (snap_fb == NULL || snap == NULL) {
2496
rfbLog("copy_snap: rawfb mode and null snap fb\n");
2500
initialize_raw_fb(1);
2502
if (raw_fb_bytes_per_line != snap->bytes_per_line) {
2503
read_all_at_once = 0;
2505
if (read_all_at_once) {
2508
/* this goes line by line, XXX not working for video */
2509
copy_raw_fb(snap, 0, 0, dpy_x, dpy_y);
2511
if (db && snapcnt++ < 5) rfbLog("rawfb copy_snap took: %.5f secs\n", dnow() - start);
2521
if (! snap_fb || ! snap || ! snaprect) {
2524
block_size = ((dpy_y/fs_factor) * snap->bytes_per_line);
2533
/* screen may be too big for 1 shm area, so broken into fs_factor */
2534
for (i=0; i < fs_factor; i++) {
2535
XRANDR_SET_TRAP_RET(-1, "copy_snap-set");
2536
copy_image(snaprect, 0, y, 0, 0);
2537
XRANDR_CHK_TRAP_RET(-1, "copy_snap-chk");
2539
memcpy(fbp, snaprect->data, (size_t) block_size);
2541
y += dpy_y / fs_factor;
2548
rfbLog("copy_snap: time for -snapfb snapshot: %.3f sec\n", dt);
2557
* debugging: print out a picture of the tiles.
2559
static void print_tiles(void) {
2560
/* hack for viewing tile diffs on the screen. */
2561
static char *prev = NULL;
2562
int n, x, y, ms = 1500;
2567
prev = (char *) malloc((size_t) ntiles);
2568
for (n=0; n < ntiles; n++) {
2572
fprintf(stderr, " ");
2573
for (x=0; x < ntiles_x; x++) {
2574
fprintf(stderr, "%1d", x % 10);
2576
fprintf(stderr, "\n");
2578
for (y=0; y < ntiles_y; y++) {
2579
fprintf(stderr, "%2d ", y);
2580
for (x=0; x < ntiles_x; x++) {
2581
if (tile_has_diff[n]) {
2582
fprintf(stderr, "X");
2583
} else if (prev[n]) {
2584
fprintf(stderr, "o");
2586
fprintf(stderr, ".");
2590
fprintf(stderr, "\n");
2592
for (n=0; n < ntiles; n++) {
2593
prev[n] = tile_has_diff[n];
2599
* Utilities for managing the "naps" to cut down on amount of polling.
2601
static void nap_set(int tile_cnt) {
2602
int nap_in = nap_ok;
2603
time_t now = time(NULL);
2605
if (scan_count == 0) {
2606
/* roll up check for all NSCAN scans */
2608
if (naptile && nap_diff_count < 2 * NSCAN * naptile) {
2609
/* "2" is a fudge to permit a bit of bg drawing */
2614
if (nap_ok && ! nap_in && use_xdamage) {
2615
if (XD_skip > 0.8 * XD_tot) {
2616
/* X DAMAGE is keeping load low, so skip nap */
2620
if (! nap_ok && client_count) {
2621
if(now > last_fb_bytes_sent + no_fbu_blank) {
2622
if (debug_tiles > 1) {
2623
printf("nap_set: nap_ok=1: now: %d last: %d\n",
2624
(int) now, (int) last_fb_bytes_sent);
2631
/* kludge for the up to 4 tiles the mouse patch could occupy */
2632
if ( tile_cnt > 4) {
2635
} else if (tile_cnt != 0) {
2641
* split up a long nap to improve the wakeup time
2643
void nap_sleep(int ms, int split) {
2644
int i, input = got_user_input;
2645
int gd = got_local_pointer_input;
2647
for (i=0; i<split; i++) {
2648
usleep(ms * 1000 / split);
2649
if (! use_threads && i != split - 1) {
2652
if (input != got_user_input) {
2655
if (gd != got_local_pointer_input) {
2662
* see if we should take a nap of some sort between polls
2664
static void nap_check(int tile_cnt) {
2667
nap_diff_count += tile_cnt;
2675
if (screen_blank > 0) {
2676
int dt_ev, dt_fbu, ms = 2000;
2678
/* if no activity, pause here for a second or so. */
2679
dt_ev = (int) (now - last_event);
2680
dt_fbu = (int) (now - last_fb_bytes_sent);
2681
if (dt_fbu > screen_blank) {
2682
/* sleep longer for no fb requests */
2683
nap_sleep(2 * ms, 16);
2686
if (dt_ev > screen_blank) {
2691
if (naptile && nap_ok && tile_cnt < naptile) {
2692
int ms = napfac * waitms;
2693
ms = ms > napmax ? napmax : ms;
2694
if (now - last_input <= 3) {
2696
} else if (now - last_local_input <= 3) {
2705
* This is called to avoid a ~20 second timeout in libvncserver.
2706
* May no longer be needed.
2708
static void ping_clients(int tile_cnt) {
2709
static time_t last_send = 0;
2710
time_t now = time(NULL);
2712
if (rfbMaxClientWait < 20000) {
2713
rfbMaxClientWait = 20000;
2714
rfbLog("reset rfbMaxClientWait to %d msec.\n",
2719
} else if (tile_cnt < 0) {
2720
if (now >= last_send - tile_cnt) {
2721
mark_rect_as_modified(0, 0, 1, 1, 1);
2724
} else if (now - last_send > 2) {
2725
/* Send small heartbeat to client */
2726
mark_rect_as_modified(0, 0, 1, 1, 1);
2732
* scan_display() wants to know if this tile can be skipped due to
2733
* blackout regions: (no data compare is done, just a quick geometric test)
2735
static int blackout_line_skip(int n, int x, int y, int rescan,
2738
if (tile_blackout[n].cover == 2) {
2739
tile_has_diff[n] = 0;
2740
return 1; /* skip it */
2742
} else if (tile_blackout[n].cover == 1) {
2743
int w, x1, y1, x2, y2, b, hit = 0;
2744
if (x + NSCAN > dpy_x) {
2750
for (b=0; b < tile_blackout[n].count; b++) {
2752
/* n.b. these coords are in full display space: */
2753
x1 = tile_blackout[n].bo[b].x1;
2754
x2 = tile_blackout[n].bo[b].x2;
2755
y1 = tile_blackout[n].bo[b].y1;
2756
y2 = tile_blackout[n].bo[b].y2;
2759
/* need to cover full width */
2762
if (y1 <= y && y < y2) {
2769
tile_has_diff[n] = 0;
2771
*tile_count += tile_has_diff[n];
2773
return 1; /* skip */
2776
return 0; /* do not skip */
2779
static int blackout_line_cmpskip(int n, int x, int y, char *dst, char *src,
2780
int w, int pixelsize) {
2782
int i, x1, y1, x2, y2, b, hit = 0;
2783
int beg = -1, end = -1;
2785
if (tile_blackout[n].cover == 0) {
2786
return 0; /* 0 means do not skip it. */
2787
} else if (tile_blackout[n].cover == 2) {
2788
return 1; /* 1 means skip it. */
2791
/* tile has partial coverage: */
2793
for (i=0; i < w * pixelsize; i++) {
2794
if (*(dst+i) != *(src+i)) {
2795
beg = i/pixelsize; /* beginning difference */
2799
for (i = w * pixelsize - 1; i >= 0; i--) {
2800
if (*(dst+i) != *(src+i)) {
2801
end = i/pixelsize; /* ending difference */
2805
if (beg < 0 || end < 0) {
2806
/* problem finding range... */
2810
/* loop over blackout rectangles: */
2811
for (b=0; b < tile_blackout[n].count; b++) {
2813
/* y in full display space: */
2814
y1 = tile_blackout[n].bo[b].y1;
2815
y2 = tile_blackout[n].bo[b].y2;
2817
/* x relative to tile origin: */
2818
x1 = tile_blackout[n].bo[b].x1 - x;
2819
x2 = tile_blackout[n].bo[b].x2 - x;
2821
if (y1 > y || y >= y2) {
2824
if (x1 <= beg && end <= x2) {
2837
* For the subwin case follows the window if it is moved.
2839
void set_offset(void) {
2845
xtranslate(window, rootwin, 0, 0, &off_x, &off_y, &w, 0);
2849
static int xd_samples = 0, xd_misses = 0, xd_do_check = 0;
2852
* Loop over 1-pixel tall horizontal scanlines looking for changes.
2853
* Record the changes in tile_has_diff[]. Scanlines in the loop are
2854
* equally spaced along y by NSCAN pixels, but have a slightly random
2855
* starting offset ystart ( < NSCAN ) from scanlines[].
2858
static int scan_display(int ystart, int rescan) {
2860
int pixelsize = bpp/8;
2863
int nodiffs = 0, diff_hint;
2864
int xd_check = 0, xd_freq = 1;
2865
static int xd_tck = 0;
2872
rfbLog("scan_display: no main_fb!\n");
2883
if (xdamage_hint_skip(y)) {
2884
if (xd_do_check && dpy && use_xdamage == 1) {
2886
xd_tck = xd_tck % xd_freq;
2898
if (xd_do_check && 0) {
2899
fprintf(stderr, "ns y=%d\n", y);
2904
/* grab the horizontal scanline from the display: */
2910
if (macosx_console) {
2911
if (macosx_checkevent(NULL)) {
2919
} else if (XEventsQueued(dpy, QueuedAlready) == 0) {
2921
} else if (XCheckTypedEvent(dpy, MapNotify, &ev)) {
2923
} else if (XCheckTypedEvent(dpy, UnmapNotify, &ev)) {
2925
} else if (XCheckTypedEvent(dpy, CreateNotify, &ev)) {
2927
} else if (XCheckTypedEvent(dpy, ConfigureNotify, &ev)) {
2929
} else if (XCheckTypedEvent(dpy, VisibilityNotify, &ev)) {
2933
XPutBackEvent(dpy, &ev);
2938
static int nomsg = 1;
2944
if (ncdb) fprintf(stderr, "\n*** SCAN_DISPLAY CHECK_NCACHE/%d *** %d rescan=%d\n", gotone, y, rescan);
2953
XRANDR_SET_TRAP_RET(-1, "scan_display-set");
2954
copy_image(scanline, 0, y, 0, 0);
2955
XRANDR_CHK_TRAP_RET(-1, "scan_display-chk");
2957
/* for better memory i/o try the whole line at once */
2958
src = scanline->data;
2959
dst = main_fb + y * main_bytes_per_line;
2961
if (! memcmp(dst, src, main_bytes_per_line)) {
2962
/* no changes anywhere in scan line */
2975
n = (x/tile_x) + (y/tile_y) * ntiles_x;
2979
if (blackout_line_skip(n, x, y, rescan,
2987
if (nodiffs || tile_has_diff[n]) {
2988
tile_count += tile_has_diff[n];
2992
} else if (xdamage_tile_count &&
2993
tile_has_xdamage_diff[n]) {
2994
tile_has_xdamage_diff[n] = 2;
2998
/* set ptrs to correspond to the x offset: */
2999
src = scanline->data + x * pixelsize;
3000
dst = main_fb + y * main_bytes_per_line + x * pixelsize;
3002
/* compute the width of data to be compared: */
3003
if (x + NSCAN > dpy_x) {
3009
if (diff_hint || memcmp(dst, src, w * pixelsize)) {
3010
/* found a difference, record it: */
3012
tile_has_diff[n] = 1;
3015
if (blackout_line_cmpskip(n, x, y,
3016
dst, src, w, pixelsize)) {
3017
tile_has_diff[n] = 0;
3019
tile_has_diff[n] = 1;
3035
int scanlines[NSCAN] = {
3036
0, 16, 8, 24, 4, 20, 12, 28,
3037
10, 26, 18, 2, 22, 6, 30, 14,
3038
1, 17, 9, 25, 7, 23, 15, 31,
3039
19, 3, 27, 11, 29, 13, 5, 21
3043
* toplevel for the scanning, rescanning, and applying the heuristics.
3044
* returns number of changed tiles.
3046
int scan_for_updates(int count_only) {
3047
int i, tile_count, tile_diffs;
3049
double frac1 = 0.1; /* tweak parameter to try a 2nd scan_display() */
3050
double frac2 = 0.35; /* or 3rd */
3051
double frac3 = 0.02; /* do scan_display() again after copy_tiles() */
3052
static double last_poll = 0.0;
3055
if (unixpw_in_progress) return 0;
3057
if (slow_fb > 0.0) {
3058
double now = dnow();
3059
if (now < last_poll + slow_fb) {
3065
for (i=0; i < ntiles; i++) {
3066
tile_has_diff[i] = 0;
3067
tile_has_xdamage_diff[i] = 0;
3071
for (i=0; i < ntiles_y; i++) {
3072
/* could be useful, currently not used */
3073
tile_row_has_xdamage_diff[i] = 0;
3075
xdamage_tile_count = 0;
3078
* n.b. this program has only been tested so far with
3079
* tile_x = tile_y = NSCAN = 32!
3084
scan_count %= NSCAN;
3086
/* some periodic maintenance */
3088
set_offset(); /* follow the subwindow */
3090
if (indexed_color && scan_count % 4 == 0) {
3091
/* check for changed colormap */
3094
if (cmap8to24 && scan_count % 1 == 0) {
3095
check_for_multivis();
3098
if (macosx_console) {
3099
macosx_event_loop();
3103
/* first pass collecting DAMAGE events: */
3105
if (macosx_console) {
3106
collect_non_X_xdamage(-1, -1, -1, -1, 0);
3110
if (rawfb_vnc_reflect) {
3111
collect_non_X_xdamage(-1, -1, -1, -1, 0);
3113
collect_xdamage(scan_count, 0);
3119
#define SCAN_FATAL(x) \
3121
scan_in_progress = 0; \
3122
fb_copy_in_progress = 0; \
3126
/* scan with the initial y to the jitter value from scanlines: */
3127
scan_in_progress = 1;
3128
tile_count = scan_display(scanlines[scan_count], 0);
3129
SCAN_FATAL(tile_count);
3132
* we do the XDAMAGE here too since after scan_display()
3133
* there is a better chance we have received the events from
3134
* the X server (otherwise the DAMAGE events will be processed
3135
* in the *next* call, usually too late and wasteful since
3136
* the unchanged tiles are read in again).
3140
if (macosx_console) {
3145
if (rawfb_vnc_reflect) {
3148
collect_xdamage(scan_count, 1);
3153
scan_in_progress = 0;
3154
fb_copy_in_progress = 0;
3158
if (xdamage_tile_count) {
3159
/* pick up "known" damaged tiles we missed in scan_display() */
3160
for (i=0; i < ntiles; i++) {
3161
if (tile_has_diff[i]) {
3164
if (tile_has_xdamage_diff[i]) {
3165
tile_has_diff[i] = 1;
3166
if (tile_has_xdamage_diff[i] == 1) {
3167
tile_has_xdamage_diff[i] = 2;
3173
if (dpy && use_xdamage == 1) {
3174
static time_t last_xd_check = 0;
3175
if (time(NULL) > last_xd_check + 2) {
3176
int cp = (scan_count + 3) % NSCAN;
3178
tile_count = scan_display(scanlines[cp], 0);
3180
SCAN_FATAL(tile_count);
3181
last_xd_check = time(NULL);
3182
if (xd_samples > 200) {
3184
if (xd_misses > (5 * xd_samples) / 100) {
3185
rfbLog("XDAMAGE is not working well... misses: %d/%d\n", xd_misses, xd_samples);
3186
rfbLog("Maybe a OpenGL app like Beryl is the problem? Use -noxdamage\n");
3187
rfbLog("To disable this check and warning specify -xdamage twice.\n");
3189
rfbLog("XDAMAGE appears broken (OpenGL app?), turning it off.\n");
3191
initialize_xdamage();
3192
destroy_xdamage_if_needed();
3201
nap_set(tile_count);
3203
if (fs_factor && frac1 >= fs_frac) {
3204
/* make frac1 < fs_frac if fullscreen updates are enabled */
3205
frac1 = fs_frac/2.0;
3208
if (tile_count > frac1 * ntiles) {
3210
* many tiles have changed, so try a rescan (since it should
3211
* be short compared to the many upcoming copy_tiles() calls)
3214
/* this check is done to skip the extra scan_display() call */
3215
if (! fs_factor || tile_count <= fs_frac * ntiles) {
3216
int cp, tile_count_old = tile_count;
3218
/* choose a different y shift for the 2nd scan: */
3219
cp = (NSCAN - scan_count) % NSCAN;
3221
tile_count = scan_display(scanlines[cp], 1);
3222
SCAN_FATAL(tile_count);
3224
if (tile_count >= (1 + frac2) * tile_count_old) {
3225
/* on a roll... do a 3rd scan */
3226
cp = (NSCAN - scan_count + 7) % NSCAN;
3227
tile_count = scan_display(scanlines[cp], 1);
3228
SCAN_FATAL(tile_count);
3231
scan_in_progress = 0;
3234
* At some number of changed tiles it is better to just
3235
* copy the full screen at once. I.e. time = c1 + m * r1
3236
* where m is number of tiles, r1 is the copy_tiles()
3237
* time, and c1 is the scan_display() time: for some m
3238
* it crosses the full screen update time.
3240
* We try to predict that crossover with the fs_frac
3241
* fudge factor... seems to be about 1/2 the total number
3242
* of tiles. n.b. this ignores network bandwidth,
3243
* compression time etc...
3245
* Use -fs 1.0 to disable on slow links.
3247
if (fs_factor && tile_count > fs_frac * ntiles) {
3249
fb_copy_in_progress = 1;
3251
fb_copy_in_progress = 0;
3253
if (use_threads && pointer_mode != 1) {
3254
pointer(-1, 0, 0, NULL);
3256
nap_check(tile_count);
3260
scan_in_progress = 0;
3262
/* copy all tiles with differences from display to rfb framebuffer: */
3263
fb_copy_in_progress = 1;
3265
if (single_copytile || tile_shm_count < ntiles_x) {
3267
* Old way, copy I/O one tile at a time.
3272
* New way, does runs of horizontal tiles at once.
3273
* Note that below, for simplicity, the extra tile finding
3274
* (e.g. copy_tiles_backward_pass) is done the old way.
3279
if (unixpw_in_progress) return 0;
3282
if (0 && tile_count > 20) print_tiles();
3289
if (old_copy_tile) {
3290
tile_diffs = copy_all_tiles();
3292
tile_diffs = copy_all_tile_runs();
3294
SCAN_FATAL(tile_diffs);
3297
if (tile_count) fprintf(stderr, "XX copytile: %.4f tile_count: %d\n", dnow() - dtmp, tile_count);
3301
* This backward pass for upward and left tiles complements what
3302
* was done in copy_all_tiles() for downward and right tiles.
3304
tile_diffs = copy_tiles_backward_pass();
3305
SCAN_FATAL(tile_diffs);
3307
if (tile_diffs > frac3 * ntiles) {
3309
* we spent a lot of time in those copy_tiles, run
3310
* another scan, maybe more of the screen changed.
3312
int cp = (NSCAN - scan_count + 13) % NSCAN;
3314
scan_in_progress = 1;
3315
tile_count = scan_display(scanlines[cp], 1);
3316
SCAN_FATAL(tile_count);
3317
scan_in_progress = 0;
3319
tile_diffs = copy_tiles_additional_pass();
3320
SCAN_FATAL(tile_diffs);
3323
/* Given enough tile diffs, try the islands: */
3324
if (grow_fill && tile_diffs > 4) {
3325
tile_diffs = grow_islands();
3327
SCAN_FATAL(tile_diffs);
3329
/* Given enough tile diffs, try the gaps: */
3330
if (gaps_fill && tile_diffs > 4) {
3331
tile_diffs = fill_tile_gaps();
3333
SCAN_FATAL(tile_diffs);
3335
fb_copy_in_progress = 0;
3336
if (use_threads && pointer_mode != 1) {
3338
* tell the pointer handler it can process any queued
3341
pointer(-1, 0, 0, NULL);
3345
/* ignore any diffs in completely covered tiles */
3347
for (y=0; y < ntiles_y; y++) {
3348
for (x=0; x < ntiles_x; x++) {
3349
n = x + y * ntiles_x;
3350
if (tile_blackout[n].cover == 2) {
3351
tile_has_diff[n] = 0;
3357
hint_updates(); /* use x0rfbserver hints algorithm */
3359
/* Work around threaded rfbProcessClientMessage() calls timeouts */
3361
ping_clients(tile_diffs);
3362
} else if (saw_ultra_chat || saw_ultra_file) {
3364
} else if (use_openssl && !tile_diffs) {
3368
if (ping_interval) {
3369
int td = ping_interval > 0 ? ping_interval : -ping_interval;
3374
nap_check(tile_diffs);