diff options
Diffstat (limited to 'x11vnc/xdamage.c')
-rw-r--r-- | x11vnc/xdamage.c | 840 |
1 files changed, 0 insertions, 840 deletions
diff --git a/x11vnc/xdamage.c b/x11vnc/xdamage.c deleted file mode 100644 index 3eb12f5..0000000 --- a/x11vnc/xdamage.c +++ /dev/null @@ -1,840 +0,0 @@ -/* - Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com> - All rights reserved. - -This file is part of x11vnc. - -x11vnc is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -x11vnc is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with x11vnc; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA -or see <http://www.gnu.org/licenses/>. - -In addition, as a special exception, Karl J. Runge -gives permission to link the code of its release of x11vnc with the -OpenSSL project's "OpenSSL" library (or with modified versions of it -that use the same license as the "OpenSSL" library), and distribute -the linked executables. You must obey the GNU General Public License -in all respects for all of the code used other than "OpenSSL". If you -modify this file, you may extend this exception to your version of the -file, but you are not obligated to do so. If you do not wish to do -so, delete this exception statement from your version. -*/ - -/* -- xdamage.c -- */ - -#include "x11vnc.h" -#include "xwrappers.h" -#include "userinput.h" -#include "unixpw.h" - -#if LIBVNCSERVER_HAVE_LIBXDAMAGE -Damage xdamage = 0; -#endif - -#ifndef XDAMAGE -#define XDAMAGE 1 -#endif -int use_xdamage = XDAMAGE; /* use the xdamage rects for scanline hints */ -int xdamage_present = 0; - -#ifdef MACOSX -int xdamage_max_area = 50000; -#else -int xdamage_max_area = 20000; /* pixels */ -#endif - -double xdamage_memory = 1.0; /* in units of NSCAN */ -int xdamage_tile_count = 0, xdamage_direct_count = 0; -double xdamage_scheduled_mark = 0.0; -double xdamage_crazy_time = 0.0; -double xdamage_crazy_delay = 300.0; -sraRegionPtr xdamage_scheduled_mark_region = NULL; -sraRegionPtr *xdamage_regions = NULL; -int xdamage_ticker = 0; -int XD_skip = 0, XD_tot = 0, XD_des = 0; /* for stats */ - -void add_region_xdamage(sraRegionPtr new_region); -void clear_xdamage_mark_region(sraRegionPtr markregion, int flush); -int collect_non_X_xdamage(int x_in, int y_in, int w_in, int h_in, int call); -int collect_xdamage(int scancnt, int call); -int xdamage_hint_skip(int y); -void initialize_xdamage(void); -void create_xdamage_if_needed(int force); -void destroy_xdamage_if_needed(void); -void check_xdamage_state(void); - -static void record_desired_xdamage_rect(int x, int y, int w, int h); - - -static void record_desired_xdamage_rect(int x, int y, int w, int h) { - /* - * Unfortunately we currently can't trust an xdamage event - * to correspond to real screen damage. E.g. focus-in for - * mozilla (depending on wm) will mark the whole toplevel - * area as damaged, when only the border has changed. - * Similar things for terminal windows. - * - * This routine uses some heuristics to detect small enough - * damage regions that we will not have a performance problem - * if we believe them even though they are wrong. We record - * the corresponding tiles the damage regions touch. - */ - int dt_x, dt_y, nt_x1, nt_y1, nt_x2, nt_y2, nt; - int ix, iy, cnt = 0; - int area = w*h, always_accept = 0; - /* - * XXX: not working yet, slow and overlaps with scan_display() - * probably slow because tall skinny rectangles very inefficient - * in general and in direct_fb_copy() (100X slower then horizontal). - */ - int use_direct_fb_copy = 0; - int wh_min, wh_max; - static int first = 1, udfb = 0; - - /* compiler warning: */ - nt_x1 = 0; nt_y1 = 0; nt_x2 = 0; nt_y2 = 0; - - if (first) { - if (getenv("XD_DFC")) { - udfb = 1; - } - first = 0; - } - if (udfb) { - use_direct_fb_copy = 1; - } - - if (xdamage_max_area <= 0) { - always_accept = 1; - } - - if (!always_accept && area > xdamage_max_area) { - return; - } - - dt_x = w / tile_x; - dt_y = h / tile_y; - - if (w < h) { - wh_min = w; - wh_max = h; - } else { - wh_min = h; - wh_max = w; - } - - if (!always_accept && dt_y >= 3 && area > 4000) { - /* - * if it is real it should be caught by a normal scanline - * poll, but we might as well keep if small (tall line?). - */ - return; - } - - if (use_direct_fb_copy) { - X_UNLOCK; - direct_fb_copy(x, y, x + w, y + h, 1); - xdamage_direct_count++; - X_LOCK; - } else if (0 && wh_min < tile_x/4 && wh_max > 30 * wh_min) { - /* try it for long, skinny rects, XXX still no good */ - X_UNLOCK; - direct_fb_copy(x, y, x + w, y + h, 1); - xdamage_direct_count++; - X_LOCK; - } else { - - if (ntiles_x == 0 || ntiles_y == 0) { - /* too early. */ - return; - } - nt_x1 = nfix( (x)/tile_x, ntiles_x); - nt_x2 = nfix((x+w)/tile_x, ntiles_x); - nt_y1 = nfix( (y)/tile_y, ntiles_y); - nt_y2 = nfix((y+h)/tile_y, ntiles_y); - - /* - * loop over the rectangle of tiles (1 tile for a small - * input rect). - */ - for (ix = nt_x1; ix <= nt_x2; ix++) { - for (iy = nt_y1; iy <= nt_y2; iy++) { - nt = ix + iy * ntiles_x; - cnt++; - if (! tile_has_xdamage_diff[nt]) { - XD_des++; - tile_has_xdamage_diff[nt] = 1; - } - /* not used: */ - tile_row_has_xdamage_diff[iy] = 1; - xdamage_tile_count++; - } - } - } - if (debug_xdamage > 1) { - fprintf(stderr, "xdamage: desired: %dx%d+%d+%d\tA: %6d tiles=" - "%02d-%02d/%02d-%02d tilecnt: %d\n", w, h, x, y, - w * h, nt_x1, nt_x2, nt_y1, nt_y2, cnt); - } -} - -void add_region_xdamage(sraRegionPtr new_region) { - sraRegionPtr reg; - int prev_tick, nreg; - - if (! xdamage_regions) { - return; - } - - nreg = (xdamage_memory * NSCAN) + 1; - prev_tick = xdamage_ticker - 1; - if (prev_tick < 0) { - prev_tick = nreg - 1; - } - - reg = xdamage_regions[prev_tick]; - if (reg != NULL && new_region != NULL) { -if (debug_xdamage > 1) fprintf(stderr, "add_region_xdamage: prev_tick: %d reg %p new_region %p\n", prev_tick, (void *)reg, (void *)new_region); - sraRgnOr(reg, new_region); - } -} - -void clear_xdamage_mark_region(sraRegionPtr markregion, int flush) { -#if LIBVNCSERVER_HAVE_LIBXDAMAGE - XEvent ev; - sraRegionPtr tmpregion; - int count = 0; - - RAWFB_RET_VOID - - if (! xdamage_present || ! use_xdamage) { - return; - } - if (! xdamage) { - return; - } - if (! xdamage_base_event_type) { - return; - } - if (unixpw_in_progress) return; - - X_LOCK; - if (flush) { - XFlush_wr(dpy); - } - while (XCheckTypedEvent(dpy, xdamage_base_event_type+XDamageNotify, &ev)) { - count++; - } - /* clear the whole damage region */ - XDamageSubtract(dpy, xdamage, None, None); - X_UNLOCK; - - if (debug_tiles || debug_xdamage) { - fprintf(stderr, "clear_xdamage_mark_region: %d\n", count); - } - - if (! markregion) { - /* NULL means mark the whole display */ - tmpregion = sraRgnCreateRect(0, 0, dpy_x, dpy_y); - add_region_xdamage(tmpregion); - sraRgnDestroy(tmpregion); - } else { - add_region_xdamage(markregion); - } -#else - if (0) flush++; /* compiler warnings */ - if (0) markregion = NULL; -#endif -} - -int collect_non_X_xdamage(int x_in, int y_in, int w_in, int h_in, int call) { - sraRegionPtr tmpregion; - sraRegionPtr reg; - static int rect_count = 0; - int nreg, ccount = 0, dcount = 0, ecount = 0; - static time_t last_rpt = 0; - time_t now; - double tm, dt; - int x, y, w, h, x2, y2; - -if (call && debug_xdamage > 1) fprintf(stderr, "collect_non_X_xdamage: %d %d %d %d - %d / %d\n", x_in, y_in, w_in, h_in, call, use_xdamage); - - if (! use_xdamage) { - return 0; - } - if (! xdamage_regions) { - return 0; - } - - dtime0(&tm); - - nreg = (xdamage_memory * NSCAN) + 1; - - if (call == 0) { - xdamage_ticker = (xdamage_ticker+1) % nreg; - xdamage_direct_count = 0; - reg = xdamage_regions[xdamage_ticker]; - if (reg != NULL) { - sraRgnMakeEmpty(reg); - } - } else { - if (xdamage_ticker < 0) { - xdamage_ticker = 0; - } - reg = xdamage_regions[xdamage_ticker]; - } - if (reg == NULL) { - return 0; - } - - if (x_in < 0) { - return 0; - } - - - x = x_in; - y = y_in; - w = w_in; - h = h_in; - - /* translate if needed */ - if (clipshift) { - /* set coords relative to fb origin */ - if (0 && rootshift) { - /* - * Note: not needed because damage is - * relative to subwin, not rootwin. - */ - x = x - off_x; - y = y - off_y; - } - if (clipshift) { - x = x - coff_x; - y = y - coff_y; - } - - x2 = x + w; /* upper point */ - x = nfix(x, dpy_x); /* place both in fb area */ - x2 = nfix(x2, dpy_x+1); - w = x2 - x; /* recompute w */ - - y2 = y + h; - y = nfix(y, dpy_y); - y2 = nfix(y2, dpy_y+1); - h = y2 - y; - - if (w <= 0 || h <= 0) { - return 0; - } - } - if (debug_xdamage > 2) { - fprintf(stderr, "xdamage: -> event %dx%d+%d+%d area:" - " %d dups: %d %s reg: %p\n", w, h, x, y, w*h, dcount, - (w*h > xdamage_max_area) ? "TOO_BIG" : "", (void *)reg); - } - - record_desired_xdamage_rect(x, y, w, h); - - tmpregion = sraRgnCreateRect(x, y, x + w, y + h); - sraRgnOr(reg, tmpregion); - sraRgnDestroy(tmpregion); - rect_count++; - ccount++; - - if (0 && xdamage_direct_count) { - fb_push(); - } - - dt = dtime(&tm); - if ((debug_tiles > 1 && ecount) || (debug_tiles && ecount > 200) - || debug_xdamage > 1) { - fprintf(stderr, "collect_non_X_xdamage(%d): %.4f t: %.4f ev/dup/accept" - "/direct %d/%d/%d/%d\n", call, dt, tm - x11vnc_start, ecount, - dcount, ccount, xdamage_direct_count); - } - now = time(NULL); - if (! last_rpt) { - last_rpt = now; - } - if (now > last_rpt + 15) { - double rat = -1.0; - - if (XD_tot) { - rat = ((double) XD_skip)/XD_tot; - } - if (debug_tiles || debug_xdamage) { - fprintf(stderr, "xdamage: == scanline skip/tot: " - "%04d/%04d =%.3f rects: %d desired: %d\n", - XD_skip, XD_tot, rat, rect_count, XD_des); - } - - XD_skip = 0; - XD_tot = 0; - XD_des = 0; - rect_count = 0; - last_rpt = now; - } - return 0; -} - -int collect_xdamage(int scancnt, int call) { -#if LIBVNCSERVER_HAVE_LIBXDAMAGE - XDamageNotifyEvent *dev; - XEvent ev; - sraRegionPtr tmpregion; - sraRegionPtr reg; - static int rect_count = 0; - int nreg, ccount = 0, dcount = 0, ecount = 0; - static time_t last_rpt = 0; - time_t now; - int x, y, w, h, x2, y2; - int i, dup, next = 0, dup_max = 0; -#define DUPSZ 32 - int dup_x[DUPSZ], dup_y[DUPSZ], dup_w[DUPSZ], dup_h[DUPSZ]; - double tm, dt; - int mark_all = 0, retries = 0, too_many = 1000, tot_ev = 0; - - RAWFB_RET(0) - - if (scancnt) {} /* unused vars warning: */ - - if (! xdamage_present || ! use_xdamage) { - return 0; - } - if (! xdamage) { - return 0; - } - if (! xdamage_base_event_type) { - return 0; - } - if (! xdamage_regions) { - return 0; - } - - dtime0(&tm); - - nreg = (xdamage_memory * NSCAN) + 1; - - if (call == 0) { - xdamage_ticker = (xdamage_ticker+1) % nreg; - xdamage_direct_count = 0; - reg = xdamage_regions[xdamage_ticker]; - if (reg != NULL) { - sraRgnMakeEmpty(reg); - } - } else { - if (xdamage_ticker < 0) { - xdamage_ticker = 0; - } - reg = xdamage_regions[xdamage_ticker]; - } - if (reg == NULL) { - return 0; - } - - - X_LOCK; -if (0) XFlush_wr(dpy); -if (0) XEventsQueued(dpy, QueuedAfterFlush); - - come_back_for_more: - - while (XCheckTypedEvent(dpy, xdamage_base_event_type+XDamageNotify, &ev)) { - /* - * TODO max cut off time in this loop? - * Could check QLength and if huge just mark the whole - * screen. - */ - ecount++; - tot_ev++; - - if (mark_all) { - continue; - } - if (ecount == too_many) { - int nqa = XEventsQueued(dpy, QueuedAlready); - if (nqa >= too_many) { - static double last_msg = 0.0; - tmpregion = sraRgnCreateRect(0, 0, dpy_x, dpy_y); - sraRgnOr(reg, tmpregion); - sraRgnDestroy(tmpregion); - if (dnow() > last_msg + xdamage_crazy_delay) { - rfbLog("collect_xdamage: too many xdamage events %d+%d\n", ecount, nqa); - last_msg = dnow(); - } - mark_all = 1; - } - } - - if (ev.type != xdamage_base_event_type + XDamageNotify) { - break; - } - dev = (XDamageNotifyEvent *) &ev; - if (dev->damage != xdamage) { - continue; /* not ours! */ - } - - x = dev->area.x; - y = dev->area.y; - w = dev->area.width; - h = dev->area.height; - - /* - * we try to manually remove some duplicates because - * certain activities can lead to many 10's of dups - * in a row. The region work can be costly and reg is - * later used in xdamage_hint_skip loops, so it is good - * to skip them if possible. - */ - dup = 0; - for (i=0; i < dup_max; i++) { - if (dup_x[i] == x && dup_y[i] == y && dup_w[i] == w && - dup_h[i] == h) { - dup = 1; - break; - } - } - if (dup) { - dcount++; - continue; - } - if (dup_max < DUPSZ) { - next = dup_max; - dup_max++; - } else { - next = (next+1) % DUPSZ; - } - dup_x[next] = x; - dup_y[next] = y; - dup_w[next] = w; - dup_h[next] = h; - - /* translate if needed */ - if (clipshift) { - /* set coords relative to fb origin */ - if (0 && rootshift) { - /* - * Note: not needed because damage is - * relative to subwin, not rootwin. - */ - x = x - off_x; - y = y - off_y; - } - if (clipshift) { - x = x - coff_x; - y = y - coff_y; - } - - x2 = x + w; /* upper point */ - x = nfix(x, dpy_x); /* place both in fb area */ - x2 = nfix(x2, dpy_x+1); - w = x2 - x; /* recompute w */ - - y2 = y + h; - y = nfix(y, dpy_y); - y2 = nfix(y2, dpy_y+1); - h = y2 - y; - - if (w <= 0 || h <= 0) { - continue; - } - } - if (debug_xdamage > 2) { - fprintf(stderr, "xdamage: -> event %dx%d+%d+%d area:" - " %d dups: %d %s\n", w, h, x, y, w*h, dcount, - (w*h > xdamage_max_area) ? "TOO_BIG" : ""); - } - - record_desired_xdamage_rect(x, y, w, h); - - tmpregion = sraRgnCreateRect(x, y, x + w, y + h); - sraRgnOr(reg, tmpregion); - sraRgnDestroy(tmpregion); - rect_count++; - ccount++; - } - - if (mark_all) { - if (ecount + XEventsQueued(dpy, QueuedAlready) >= 3 * too_many && retries < 3) { - retries++; - XFlush_wr(dpy); - usleep(20 * 1000); - XFlush_wr(dpy); - ecount = 0; - goto come_back_for_more; - } - } - - /* clear the whole damage region for next time. XXX check */ - if (call == 1) { - XDamageSubtract(dpy, xdamage, None, None); - } - X_UNLOCK; - - if (tot_ev > 20 * too_many) { - rfbLog("collect_xdamage: xdamage has gone crazy (screensaver or game?) ev: %d ret: %d\n", tot_ev, retries); - rfbLog("collect_xdamage: disabling xdamage for %d seconds.\n", (int) xdamage_crazy_delay); - destroy_xdamage_if_needed(); - X_LOCK; - XSync(dpy, False); - while (XCheckTypedEvent(dpy, xdamage_base_event_type+XDamageNotify, &ev)) { - ; - } - X_UNLOCK; - xdamage_crazy_time = dnow(); - } - - if (0 && xdamage_direct_count) { - fb_push(); - } - - dt = dtime(&tm); - if ((debug_tiles > 1 && ecount) || (debug_tiles && ecount > 200) - || debug_xdamage > 1) { - fprintf(stderr, "collect_xdamage(%d): %.4f t: %.4f ev/dup/accept" - "/direct %d/%d/%d/%d\n", call, dt, tm - x11vnc_start, ecount, - dcount, ccount, xdamage_direct_count); - } - now = time(NULL); - if (! last_rpt) { - last_rpt = now; - } - if (now > last_rpt + 15) { - double rat = -1.0; - - if (XD_tot) { - rat = ((double) XD_skip)/XD_tot; - } - if (debug_tiles || debug_xdamage) { - fprintf(stderr, "xdamage: == scanline skip/tot: " - "%04d/%04d =%.3f rects: %d desired: %d\n", - XD_skip, XD_tot, rat, rect_count, XD_des); - } - - XD_skip = 0; - XD_tot = 0; - XD_des = 0; - rect_count = 0; - last_rpt = now; - } -#else - if (0) scancnt++; /* compiler warnings */ - if (0) call++; - if (0) record_desired_xdamage_rect(0, 0, 0, 0); -#endif - return 0; -} - -int xdamage_hint_skip(int y) { - static sraRegionPtr scanline = NULL; - static sraRegionPtr tmpl_y = NULL; - int fast_tmpl = 1; - sraRegionPtr reg, tmpl; - int ret, i, n, nreg; -#ifndef NO_NCACHE - static int ncache_no_skip = 0; - static double last_ncache_no_skip = 0.0; - static double last_ncache_no_skip_long = 0.0, ncache_fac = 0.25; -#endif - - if (! xdamage_present || ! use_xdamage) { - return 0; /* cannot skip */ - } - if (! xdamage_regions) { - return 0; /* cannot skip */ - } - - if (! scanline) { - /* keep it around to avoid malloc etc, recreate */ - scanline = sraRgnCreate(); - } - if (! tmpl_y) { - tmpl_y = sraRgnCreateRect(0, 0, dpy_x, 1); - } - - nreg = (xdamage_memory * NSCAN) + 1; - -#ifndef NO_NCACHE - if (ncache > 0) { - if (ncache_no_skip == 0) { - double now = g_now; - if (now > last_ncache_no_skip + 8.0) { - ncache_no_skip = 1; - } else if (now < last_bs_restore + 0.5) { - ncache_no_skip = 1; - } else if (now < last_su_restore + 0.5) { - ncache_no_skip = 1; - } else if (now < last_copyrect + 0.5) { - ncache_no_skip = 1; - } - if (ncache_no_skip) { - last_ncache_no_skip = dnow(); - if (now > last_ncache_no_skip_long + 60.0) { - ncache_fac = 2.0; - last_ncache_no_skip_long = now; - } else { - ncache_fac = 0.25; - } - return 0; - } - } else { - if (ncache_no_skip++ >= ncache_fac*nreg + 4) { - ncache_no_skip = 0; - } else { - return 0; - } - } - } -#endif - - if (fast_tmpl) { - sraRgnOffset(tmpl_y, 0, y); - tmpl = tmpl_y; - } else { - tmpl = sraRgnCreateRect(0, y, dpy_x, y+1); - } - - ret = 1; - for (i=0; i<nreg; i++) { - /* go back thru the history starting at most recent */ - n = (xdamage_ticker + nreg - i) % nreg; - reg = xdamage_regions[n]; - if (reg == NULL) { - continue; - } - if (sraRgnEmpty(reg)) { - /* checking for emptiness is very fast */ - continue; - } - sraRgnMakeEmpty(scanline); - sraRgnOr(scanline, tmpl); - if (sraRgnAnd(scanline, reg)) { - ret = 0; - break; - } - } - if (fast_tmpl) { - sraRgnOffset(tmpl_y, 0, -y); - } else { - sraRgnDestroy(tmpl); - } -if (0) fprintf(stderr, "xdamage_hint_skip: %d -> %d\n", y, ret); - - return ret; -} - -void initialize_xdamage(void) { - sraRegionPtr *ptr; - int i, nreg; - - if (! xdamage_present) { - use_xdamage = 0; - } - if (xdamage_regions) { - ptr = xdamage_regions; - while (*ptr != NULL) { - sraRgnDestroy(*ptr); - ptr++; - } - free(xdamage_regions); - xdamage_regions = NULL; - } - if (use_xdamage) { - nreg = (xdamage_memory * NSCAN) + 2; - xdamage_regions = (sraRegionPtr *) - malloc(nreg * sizeof(sraRegionPtr)); - for (i = 0; i < nreg; i++) { - ptr = xdamage_regions+i; - if (i == nreg - 1) { - *ptr = NULL; - } else { - *ptr = sraRgnCreate(); - sraRgnMakeEmpty(*ptr); - } - } - /* set so will be 0 in first collect_xdamage call */ - xdamage_ticker = -1; - } -} - -void create_xdamage_if_needed(int force) { - - RAWFB_RET_VOID - - if (force) {} - -#if LIBVNCSERVER_HAVE_LIBXDAMAGE - if (! xdamage || force) { - X_LOCK; - xdamage = XDamageCreate(dpy, window, XDamageReportRawRectangles); - XDamageSubtract(dpy, xdamage, None, None); - X_UNLOCK; - rfbLog("created xdamage object: 0x%lx\n", xdamage); - } -#endif -} - -void destroy_xdamage_if_needed(void) { - - RAWFB_RET_VOID - -#if LIBVNCSERVER_HAVE_LIBXDAMAGE - if (xdamage) { - XEvent ev; - X_LOCK; - XDamageDestroy(dpy, xdamage); - XFlush_wr(dpy); - if (xdamage_base_event_type) { - while (XCheckTypedEvent(dpy, - xdamage_base_event_type+XDamageNotify, &ev)) { - ; - } - } - X_UNLOCK; - rfbLog("destroyed xdamage object: 0x%lx\n", xdamage); - xdamage = 0; - } -#endif -} - -void check_xdamage_state(void) { - if (! xdamage_present) { - return; - } - /* - * Create or destroy the Damage object as needed, we don't want - * one if no clients are connected. - */ - if (xdamage_crazy_time > 0.0 && dnow() < xdamage_crazy_time + xdamage_crazy_delay) { - return; - } - if (client_count && use_xdamage) { - create_xdamage_if_needed(0); - if (xdamage_scheduled_mark > 0.0 && dnow() > - xdamage_scheduled_mark) { - if (xdamage_scheduled_mark_region) { - mark_region_for_xdamage( - xdamage_scheduled_mark_region); - sraRgnDestroy(xdamage_scheduled_mark_region); - xdamage_scheduled_mark_region = NULL; - } else { - mark_for_xdamage(0, 0, dpy_x, dpy_y); - } - xdamage_scheduled_mark = 0.0; - } - } else { - destroy_xdamage_if_needed(); - } -} - - |