diff --git a/qemu-timer.h b/qemu-timer.h index 3f8880ddfa..8f6946763b 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -24,6 +24,7 @@ void qemu_free_timer(QEMUTimer *ts); void qemu_del_timer(QEMUTimer *ts); void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); int qemu_timer_pending(QEMUTimer *ts); +int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time); extern int64_t ticks_per_sec; diff --git a/vl.c b/vl.c index 9b390e74d9..978041f339 100644 --- a/vl.c +++ b/vl.c @@ -992,7 +992,7 @@ int qemu_timer_pending(QEMUTimer *ts) return 0; } -static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) +int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) { if (!timer_head) return 0; diff --git a/vnc.c b/vnc.c index cfaf7ba29c..4fde9aae5d 100644 --- a/vnc.c +++ b/vnc.c @@ -30,7 +30,9 @@ #include "qemu-timer.h" #include "acl.h" -#define VNC_REFRESH_INTERVAL (1000 / 30) +#define VNC_REFRESH_INTERVAL_BASE 30 +#define VNC_REFRESH_INTERVAL_INC 50 +#define VNC_REFRESH_INTERVAL_MAX 2000 #include "vnc_keysym.h" #include "d3des.h" @@ -215,7 +217,7 @@ static inline uint32_t vnc_has_feature(VncState *vs, int feature) { 3) resolutions > 1024 */ -static void vnc_update_client(VncState *vs, int has_dirty); +static int vnc_update_client(VncState *vs, int has_dirty); static void vnc_disconnect_start(VncState *vs); static void vnc_disconnect_finish(VncState *vs); static void vnc_init_timer(VncDisplay *vd); @@ -751,7 +753,7 @@ static int find_and_clear_dirty_height(struct VncState *vs, return h; } -static void vnc_update_client(VncState *vs, int has_dirty) +static int vnc_update_client(VncState *vs, int has_dirty) { if (vs->need_update && vs->csock != -1) { VncDisplay *vd = vs->vd; @@ -761,10 +763,10 @@ static void vnc_update_client(VncState *vs, int has_dirty) if (vs->output.offset && !vs->audio_cap && !vs->force_update) /* kernel send buffers are full -> drop frames to throttle */ - return; + return 0; if (!has_dirty && !vs->audio_cap && !vs->force_update) - return; + return 0; /* * Send screen updates to the vnc client using the server @@ -806,11 +808,13 @@ static void vnc_update_client(VncState *vs, int has_dirty) vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF; vnc_flush(vs); vs->force_update = 0; - + return n_rectangles; } if (vs->csock == -1) vnc_disconnect_finish(vs); + + return 0; } /* audio */ @@ -1701,6 +1705,13 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) { int i; uint16_t limit; + VncDisplay *vd = vs->vd; + + if (data[0] > 3) { + vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; + if (!qemu_timer_expired(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval)) + qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval); + } switch (data[0]) { case 0: @@ -2104,7 +2115,7 @@ static void vnc_refresh(void *opaque) { VncDisplay *vd = opaque; VncState *vs = NULL; - int has_dirty = 0; + int has_dirty = 0, rects = 0; vga_hw_update(); @@ -2112,15 +2123,25 @@ static void vnc_refresh(void *opaque) vs = vd->clients; while (vs != NULL) { - vnc_update_client(vs, has_dirty); + rects += vnc_update_client(vs, has_dirty); vs = vs->next; } - qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL); + if (has_dirty && rects) { + vd->timer_interval /= 2; + if (vd->timer_interval < VNC_REFRESH_INTERVAL_BASE) + vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; + } else { + vd->timer_interval += VNC_REFRESH_INTERVAL_INC; + if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX) + vd->timer_interval = VNC_REFRESH_INTERVAL_MAX; + } + qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval); } static void vnc_init_timer(VncDisplay *vd) { + vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; if (vd->timer == NULL && vd->clients != NULL) { vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd); vnc_refresh(vd); diff --git a/vnc.h b/vnc.h index 5c903dec75..fcc6824127 100644 --- a/vnc.h +++ b/vnc.h @@ -93,6 +93,7 @@ struct VncSurface struct VncDisplay { QEMUTimer *timer; + int timer_interval; int lsock; DisplayState *ds; VncState *clients;