📄 vnc-backoff-screen-scan
字号:
Index: ioemu/vnc.c===================================================================--- ioemu.orig/vnc.c 2007-05-10 15:18:01.000000000 +0100+++ ioemu/vnc.c 2007-05-10 15:18:58.000000000 +0100@@ -28,7 +28,19 @@ #include "qemu_socket.h" #include <assert.h> -#define VNC_REFRESH_INTERVAL (1000 / 30)+/* The refresh interval starts at BASE. If we scan the buffer and+ find no change, we increase by INC, up to MAX. If the mouse moves+ or we get a keypress, the interval is set back to BASE. If we find+ an update, halve the interval.++ All times in milliseconds. */+#define VNC_REFRESH_INTERVAL_BASE 30+#define VNC_REFRESH_INTERVAL_INC 50+#define VNC_REFRESH_INTERVAL_MAX 2000++/* Wait at most one second between updates, so that we can detect a+ minimised vncviewer reasonably quickly. */+#define VNC_MAX_UPDATE_INTERVAL 5000 #include "vnc_keysym.h" #include "keymaps.c"@@ -61,10 +73,11 @@ struct VncState { QEMUTimer *timer;+ int timer_interval;+ int64_t last_update_time; int lsock; int csock; DisplayState *ds;- int need_update; int width; int height; uint64_t *dirty_row; /* screen regions which are possibly dirty */@@ -102,8 +115,6 @@ int visible_w; int visible_h; - int slow_client;- /* input */ uint8_t modifiers_state[256]; };@@ -408,7 +419,7 @@ int y = 0; int pitch = ds->linesize; VncState *vs = ds->opaque;- int updating_client = !vs->slow_client;+ int updating_client = 1; if (src_x < vs->visible_x || src_y < vs->visible_y || dst_x < vs->visible_x || dst_y < vs->visible_y ||@@ -418,10 +429,8 @@ (dst_y + h) > (vs->visible_y + vs->visible_h)) updating_client = 0; - if (updating_client) {- vs->need_update = 1;+ if (updating_client) _vnc_update_client(vs);- } if (dst_y > src_y) { y = h - 1;@@ -473,110 +482,149 @@ static void _vnc_update_client(void *opaque) { VncState *vs = opaque;- int64_t now = qemu_get_clock(rt_clock);-- if (vs->need_update && vs->csock != -1) {- int y;- char *row;- char *old_row;- uint64_t width_mask;- int n_rectangles;- int saved_offset;- int maxx, maxy;- int tile_bytes = vs->depth * DP2X(vs, 1);+ int64_t now;+ int y;+ char *row;+ char *old_row;+ uint64_t width_mask;+ int n_rectangles;+ int saved_offset;+ int maxx, maxy;+ int tile_bytes = vs->depth * DP2X(vs, 1); - qemu_mod_timer(vs->timer, now + VNC_REFRESH_INTERVAL);+ if (vs->csock == -1)+ return; - if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS))- width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1;- else- width_mask = ~(0ULL);+ now = qemu_get_clock(rt_clock); - /* Walk through the dirty map and eliminate tiles that- really aren't dirty */- row = vs->ds->data;- old_row = vs->old_data;-- for (y = 0; y < vs->ds->height; y++) {- if (vs->dirty_row[y] & width_mask) {- int x;- char *ptr, *old_ptr;-- ptr = row;- old_ptr = old_row;-- for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) {- if (vs->dirty_row[y] & (1ULL << x)) {- if (memcmp(old_ptr, ptr, tile_bytes)) {- vs->has_update = 1;- vs->update_row[y] |= (1ULL << x);- memcpy(old_ptr, ptr, tile_bytes);- }- vs->dirty_row[y] &= ~(1ULL << x);- }+ if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS))+ width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1;+ else+ width_mask = ~(0ULL); - ptr += tile_bytes;- old_ptr += tile_bytes;- }- }+ /* Walk through the dirty map and eliminate tiles that really+ aren't dirty */+ row = vs->ds->data;+ old_row = vs->old_data; - row += vs->ds->linesize;- old_row += vs->ds->linesize;- }+ for (y = 0; y < vs->ds->height; y++) {+ if (vs->dirty_row[y] & width_mask) {+ int x;+ char *ptr, *old_ptr; - if (!vs->has_update || vs->visible_y >= vs->ds->height ||- vs->visible_x >= vs->ds->width)- return;+ ptr = row;+ old_ptr = old_row; - /* Count rectangles */- n_rectangles = 0;- vnc_write_u8(vs, 0); /* msg id */- vnc_write_u8(vs, 0);- saved_offset = vs->output.offset;- vnc_write_u16(vs, 0);+ for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) {+ if (vs->dirty_row[y] & (1ULL << x)) {+ if (memcmp(old_ptr, ptr, tile_bytes)) {+ vs->has_update = 1;+ vs->update_row[y] |= (1ULL << x);+ memcpy(old_ptr, ptr, tile_bytes);+ }+ vs->dirty_row[y] &= ~(1ULL << x);+ } - maxy = vs->visible_y + vs->visible_h;- if (maxy > vs->ds->height)- maxy = vs->ds->height;- maxx = vs->visible_x + vs->visible_w;- if (maxx > vs->ds->width)- maxx = vs->ds->width;+ ptr += tile_bytes;+ old_ptr += tile_bytes;+ }+ }+ + row += vs->ds->linesize;+ old_row += vs->ds->linesize;+ } - for (y = vs->visible_y; y < maxy; y++) {- int x;- int last_x = -1;- for (x = X2DP_DOWN(vs, vs->visible_x);- x < X2DP_UP(vs, maxx); x++) {- if (vs->update_row[y] & (1ULL << x)) {- if (last_x == -1)- last_x = x;- vs->update_row[y] &= ~(1ULL << x);- } else {- if (last_x != -1) {- int h = find_update_height(vs, y, maxy, last_x, x);+ if (!vs->has_update || vs->visible_y >= vs->ds->height ||+ vs->visible_x >= vs->ds->width)+ goto backoff;++ /* Count rectangles */+ n_rectangles = 0;+ vnc_write_u8(vs, 0); /* msg id */+ vnc_write_u8(vs, 0);+ saved_offset = vs->output.offset;+ vnc_write_u16(vs, 0);+ + maxy = vs->visible_y + vs->visible_h;+ if (maxy > vs->ds->height)+ maxy = vs->ds->height;+ maxx = vs->visible_x + vs->visible_w;+ if (maxx > vs->ds->width)+ maxx = vs->ds->width;++ for (y = vs->visible_y; y < maxy; y++) {+ int x;+ int last_x = -1;+ for (x = X2DP_DOWN(vs, vs->visible_x);+ x < X2DP_UP(vs, maxx); x++) {+ if (vs->update_row[y] & (1ULL << x)) {+ if (last_x == -1)+ last_x = x;+ vs->update_row[y] &= ~(1ULL << x);+ } else {+ if (last_x != -1) {+ int h = find_update_height(vs, y, maxy, last_x, x);+ if (h != 0) { send_framebuffer_update(vs, DP2X(vs, last_x), y, DP2X(vs, (x - last_x)), h); n_rectangles++; }- last_x = -1; }+ last_x = -1; }- if (last_x != -1) {- int h = find_update_height(vs, y, maxy, last_x, x);+ }+ if (last_x != -1) {+ int h = find_update_height(vs, y, maxy, last_x, x);+ if (h != 0) { send_framebuffer_update(vs, DP2X(vs, last_x), y, DP2X(vs, (x - last_x)), h); n_rectangles++; } }- vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;- vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;+ }+ vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;+ vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF; - vs->has_update = 0;- vs->need_update = 0;- vnc_flush(vs);- vs->slow_client = 0;- } else- vs->slow_client = 1;+ if (n_rectangles == 0)+ goto backoff;++ vs->has_update = 0;+ vnc_flush(vs);+ vs->last_update_time = now;++ vs->timer_interval /= 2;+ if (vs->timer_interval < VNC_REFRESH_INTERVAL_BASE)+ vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;++ return;++ backoff:+ /* No update -> back off a bit */+ vs->timer_interval += VNC_REFRESH_INTERVAL_INC;+ if (vs->timer_interval > VNC_REFRESH_INTERVAL_MAX) {+ vs->timer_interval = VNC_REFRESH_INTERVAL_MAX;+ if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL) {+ /* Send a null update. If the client is no longer+ interested (e.g. minimised) it'll ignore this, and we+ can stop scanning the buffer until it sends another+ update request. */+ /* It turns out that there's a bug in realvncviewer 4.1.2+ which means that if you send a proper null update (with+ no update rectangles), it gets a bit out of sync and+ never sends any further requests, regardless of whether+ it needs one or not. Fix this by sending a single 1x1+ update rectangle instead. */+ vnc_write_u8(vs, 0);+ vnc_write_u8(vs, 0);+ vnc_write_u16(vs, 1);+ send_framebuffer_update(vs, 0, 0, 1, 1);+ vnc_flush(vs);+ vs->last_update_time = now;+ return;+ }+ }+ qemu_mod_timer(vs->timer, now + vs->timer_interval);+ return; } static void vnc_update_client(void *opaque)@@ -589,8 +637,10 @@ static void vnc_timer_init(VncState *vs) {- if (vs->timer == NULL)+ if (vs->timer == NULL) { vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);+ vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;+ } } static void vnc_dpy_refresh(DisplayState *ds)@@ -650,7 +700,6 @@ vs->csock = -1; buffer_reset(&vs->input); buffer_reset(&vs->output);- vs->need_update = 0; return 0; } return ret;@@ -957,7 +1006,6 @@ int x_position, int y_position, int w, int h) {- vs->need_update = 1; if (!incremental) framebuffer_set_updated(vs, x_position, y_position, w, h); vs->visible_x = x_position;@@ -1087,6 +1135,7 @@ { int i; uint16_t limit;+ int64_t now; switch (data[0]) { case 0:@@ -1130,12 +1179,18 @@ if (len == 1) return 8; + vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;+ qemu_advance_timer(vs->timer,+ qemu_get_clock(rt_clock) + vs->timer_interval); key_event(vs, read_u8(data, 1), read_u32(data, 4)); break; case 5: if (len == 1) return 6; + vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;+ qemu_advance_timer(vs->timer,+ qemu_get_clock(rt_clock) + vs->timer_interval); pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4)); break; case 6:Index: ioemu/vl.c===================================================================--- ioemu.orig/vl.c 2007-05-10 15:18:01.000000000 +0100+++ ioemu/vl.c 2007-05-10 15:18:58.000000000 +0100@@ -811,6 +811,12 @@ } } +void qemu_advance_timer(QEMUTimer *ts, int64_t expire_time)+{+ if (ts->expire_time > expire_time || !qemu_timer_pending(ts))+ qemu_mod_timer(ts, expire_time);+}+ /* modify the current timer so that it will be fired when current_time >= expire_time. The corresponding callback will be called. */ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)Index: ioemu/vl.h===================================================================--- ioemu.orig/vl.h 2007-05-10 15:18:01.000000000 +0100+++ ioemu/vl.h 2007-05-10 15:18:58.000000000 +0100@@ -441,6 +441,7 @@ void qemu_free_timer(QEMUTimer *ts); void qemu_del_timer(QEMUTimer *ts); void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);+void qemu_advance_timer(QEMUTimer *ts, int64_t expire_time); int qemu_timer_pending(QEMUTimer *ts); extern int64_t ticks_per_sec;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -