source: trunk/packages/xen-common/xen-common/tools/ioemu/patches/vnc-backoff-screen-scan @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 10.6 KB
Line 
1Index: ioemu/vnc.c
2===================================================================
3--- ioemu.orig/vnc.c    2007-05-03 10:07:56.000000000 +0100
4+++ ioemu/vnc.c 2007-05-03 10:07:56.000000000 +0100
5@@ -28,7 +28,19 @@
6 #include "qemu_socket.h"
7 #include <assert.h>
8 
9-#define VNC_REFRESH_INTERVAL (1000 / 30)
10+/* The refresh interval starts at BASE.  If we scan the buffer and
11+   find no change, we increase by INC, up to MAX.  If the mouse moves
12+   or we get a keypress, the interval is set back to BASE.  If we find
13+   an update, halve the interval.
14+
15+   All times in milliseconds. */
16+#define VNC_REFRESH_INTERVAL_BASE 30
17+#define VNC_REFRESH_INTERVAL_INC  50
18+#define VNC_REFRESH_INTERVAL_MAX  2000
19+
20+/* Wait at most one second between updates, so that we can detect a
21+   minimised vncviewer reasonably quickly. */
22+#define VNC_MAX_UPDATE_INTERVAL   5000
23 
24 #include "vnc_keysym.h"
25 #include "keymaps.c"
26@@ -65,10 +77,11 @@
27 struct VncState
28 {
29     QEMUTimer *timer;
30+    int timer_interval;
31+    int64_t last_update_time;
32     int lsock;
33     int csock;
34     DisplayState *ds;
35-    int need_update;
36     int width;
37     int height;
38     uint64_t *dirty_row;       /* screen regions which are possibly dirty */
39@@ -99,8 +112,6 @@
40     int visible_w;
41     int visible_h;
42 
43-    int slow_client;
44-
45     int ctl_keys;               /* Ctrl+Alt starts calibration */
46 };
47 
48@@ -383,7 +394,7 @@
49     int y = 0;
50     int pitch = ds->linesize;
51     VncState *vs = ds->opaque;
52-    int updating_client = !vs->slow_client;
53+    int updating_client = 1;
54 
55     if (src_x < vs->visible_x || src_y < vs->visible_y ||
56        dst_x < vs->visible_x || dst_y < vs->visible_y ||
57@@ -393,10 +404,8 @@
58        (dst_y + h) > (vs->visible_y + vs->visible_h))
59        updating_client = 0;
60 
61-    if (updating_client) {
62-       vs->need_update = 1;
63+    if (updating_client)
64        _vnc_update_client(vs);
65-    }
66 
67     if (dst_y > src_y) {
68        y = h - 1;
69@@ -448,110 +457,149 @@
70 static void _vnc_update_client(void *opaque)
71 {
72     VncState *vs = opaque;
73-    int64_t now = qemu_get_clock(rt_clock);
74-
75-    if (vs->need_update && vs->csock != -1) {
76-       int y;
77-       char *row;
78-       char *old_row;
79-       uint64_t width_mask;
80-       int n_rectangles;
81-       int saved_offset;
82-       int maxx, maxy;
83-       int tile_bytes = vs->depth * DP2X(vs, 1);
84+    int64_t now;
85+    int y;
86+    char *row;
87+    char *old_row;
88+    uint64_t width_mask;
89+    int n_rectangles;
90+    int saved_offset;
91+    int maxx, maxy;
92+    int tile_bytes = vs->depth * DP2X(vs, 1);
93 
94-       qemu_mod_timer(vs->timer, now + VNC_REFRESH_INTERVAL);
95+    if (vs->csock == -1)
96+       return;
97 
98-       if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS))
99-           width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1;
100-       else
101-           width_mask = ~(0ULL);
102+    now = qemu_get_clock(rt_clock);
103 
104-       /* Walk through the dirty map and eliminate tiles that
105-          really aren't dirty */
106-       row = vs->ds->data;
107-       old_row = vs->old_data;
108-
109-       for (y = 0; y < vs->ds->height; y++) {
110-           if (vs->dirty_row[y] & width_mask) {
111-               int x;
112-               char *ptr, *old_ptr;
113-
114-               ptr = row;
115-               old_ptr = old_row;
116-
117-               for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) {
118-                   if (vs->dirty_row[y] & (1ULL << x)) {
119-                       if (memcmp(old_ptr, ptr, tile_bytes)) {
120-                           vs->has_update = 1;
121-                           vs->update_row[y] |= (1ULL << x);
122-                           memcpy(old_ptr, ptr, tile_bytes);
123-                       }
124-                       vs->dirty_row[y] &= ~(1ULL << x);
125-                   }
126+    if (vs->width != DP2X(vs, DIRTY_PIXEL_BITS))
127+       width_mask = (1ULL << X2DP_UP(vs, vs->ds->width)) - 1;
128+    else
129+       width_mask = ~(0ULL);
130 
131-                   ptr += tile_bytes;
132-                   old_ptr += tile_bytes;
133-               }
134-           }
135+    /* Walk through the dirty map and eliminate tiles that really
136+       aren't dirty */
137+    row = vs->ds->data;
138+    old_row = vs->old_data;
139 
140-           row += vs->ds->linesize;
141-           old_row += vs->ds->linesize;
142-       }
143+    for (y = 0; y < vs->ds->height; y++) {
144+       if (vs->dirty_row[y] & width_mask) {
145+           int x;
146+           char *ptr, *old_ptr;
147 
148-       if (!vs->has_update || vs->visible_y >= vs->ds->height ||
149-           vs->visible_x >= vs->ds->width)
150-           return;
151+           ptr = row;
152+           old_ptr = old_row;
153 
154-       /* Count rectangles */
155-       n_rectangles = 0;
156-       vnc_write_u8(vs, 0);  /* msg id */
157-       vnc_write_u8(vs, 0);
158-       saved_offset = vs->output.offset;
159-       vnc_write_u16(vs, 0);
160+           for (x = 0; x < X2DP_UP(vs, vs->ds->width); x++) {
161+               if (vs->dirty_row[y] & (1ULL << x)) {
162+                   if (memcmp(old_ptr, ptr, tile_bytes)) {
163+                       vs->has_update = 1;
164+                       vs->update_row[y] |= (1ULL << x);
165+                       memcpy(old_ptr, ptr, tile_bytes);
166+                   }
167+                   vs->dirty_row[y] &= ~(1ULL << x);
168+               }
169 
170-       maxy = vs->visible_y + vs->visible_h;
171-       if (maxy > vs->ds->height)
172-           maxy = vs->ds->height;
173-       maxx = vs->visible_x + vs->visible_w;
174-       if (maxx > vs->ds->width)
175-           maxx = vs->ds->width;
176+               ptr += tile_bytes;
177+               old_ptr += tile_bytes;
178+           }
179+       }
180
181+       row += vs->ds->linesize;
182+       old_row += vs->ds->linesize;
183+    }
184 
185-       for (y = vs->visible_y; y < maxy; y++) {
186-           int x;
187-           int last_x = -1;
188-           for (x = X2DP_DOWN(vs, vs->visible_x);
189-                x < X2DP_UP(vs, maxx); x++) {
190-               if (vs->update_row[y] & (1ULL << x)) {
191-                   if (last_x == -1)
192-                       last_x = x;
193-                   vs->update_row[y] &= ~(1ULL << x);
194-               } else {
195-                   if (last_x != -1) {
196-                       int h = find_update_height(vs, y, maxy, last_x, x);
197+    if (!vs->has_update || vs->visible_y >= vs->ds->height ||
198+       vs->visible_x >= vs->ds->width)
199+       goto backoff;
200+
201+    /* Count rectangles */
202+    n_rectangles = 0;
203+    vnc_write_u8(vs, 0);  /* msg id */
204+    vnc_write_u8(vs, 0);
205+    saved_offset = vs->output.offset;
206+    vnc_write_u16(vs, 0);
207+   
208+    maxy = vs->visible_y + vs->visible_h;
209+    if (maxy > vs->ds->height)
210+       maxy = vs->ds->height;
211+    maxx = vs->visible_x + vs->visible_w;
212+    if (maxx > vs->ds->width)
213+       maxx = vs->ds->width;
214+
215+    for (y = vs->visible_y; y < maxy; y++) {
216+       int x;
217+       int last_x = -1;
218+       for (x = X2DP_DOWN(vs, vs->visible_x);
219+            x < X2DP_UP(vs, maxx); x++) {
220+           if (vs->update_row[y] & (1ULL << x)) {
221+               if (last_x == -1)
222+                   last_x = x;
223+               vs->update_row[y] &= ~(1ULL << x);
224+           } else {
225+               if (last_x != -1) {
226+                   int h = find_update_height(vs, y, maxy, last_x, x);
227+                   if (h != 0) {
228                        send_framebuffer_update(vs, DP2X(vs, last_x), y,
229                                                DP2X(vs, (x - last_x)), h);
230                        n_rectangles++;
231                    }
232-                   last_x = -1;
233                }
234+               last_x = -1;
235            }
236-           if (last_x != -1) {
237-               int h = find_update_height(vs, y, maxy, last_x, x);
238+       }
239+       if (last_x != -1) {
240+           int h = find_update_height(vs, y, maxy, last_x, x);
241+           if (h != 0) {
242                send_framebuffer_update(vs, DP2X(vs, last_x), y,
243                                        DP2X(vs, (x - last_x)), h);
244                n_rectangles++;
245            }
246        }
247-       vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
248-       vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
249+    }
250+    vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF;
251+    vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF;
252 
253-       vs->has_update = 0;
254-       vs->need_update = 0;
255-       vnc_flush(vs);
256-       vs->slow_client = 0;
257-    } else
258-       vs->slow_client = 1;
259+    if (n_rectangles == 0)
260+       goto backoff;
261+
262+    vs->has_update = 0;
263+    vnc_flush(vs);
264+    vs->last_update_time = now;
265+
266+    vs->timer_interval /= 2;
267+    if (vs->timer_interval < VNC_REFRESH_INTERVAL_BASE)
268+       vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
269+
270+    return;
271+
272+ backoff:
273+    /* No update -> back off a bit */
274+    vs->timer_interval += VNC_REFRESH_INTERVAL_INC;
275+    if (vs->timer_interval > VNC_REFRESH_INTERVAL_MAX) {
276+       vs->timer_interval = VNC_REFRESH_INTERVAL_MAX;
277+       if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL) {
278+           /* Send a null update.  If the client is no longer
279+              interested (e.g. minimised) it'll ignore this, and we
280+              can stop scanning the buffer until it sends another
281+              update request. */
282+           /* It turns out that there's a bug in realvncviewer 4.1.2
283+              which means that if you send a proper null update (with
284+              no update rectangles), it gets a bit out of sync and
285+              never sends any further requests, regardless of whether
286+              it needs one or not.  Fix this by sending a single 1x1
287+              update rectangle instead. */
288+           vnc_write_u8(vs, 0);
289+           vnc_write_u8(vs, 0);
290+           vnc_write_u16(vs, 1);
291+           send_framebuffer_update(vs, 0, 0, 1, 1);
292+           vnc_flush(vs);
293+           vs->last_update_time = now;
294+           return;
295+       }
296+    }
297+    qemu_mod_timer(vs->timer, now + vs->timer_interval);
298+    return;
299 }
300 
301 static void vnc_update_client(void *opaque)
302@@ -564,8 +612,10 @@
303 
304 static void vnc_timer_init(VncState *vs)
305 {
306-    if (vs->timer == NULL)
307+    if (vs->timer == NULL) {
308        vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
309+       vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
310+    }
311 }
312 
313 static void vnc_dpy_refresh(DisplayState *ds)
314@@ -625,7 +675,6 @@
315        vs->csock = -1;
316        buffer_reset(&vs->input);
317        buffer_reset(&vs->output);
318-       vs->need_update = 0;
319        return 0;
320     }
321     return ret;
322@@ -897,7 +946,6 @@
323                                       int x_position, int y_position,
324                                       int w, int h)
325 {
326-    vs->need_update = 1;
327     if (!incremental)
328        framebuffer_set_updated(vs, x_position, y_position, w, h);
329     vs->visible_x = x_position;
330@@ -1020,6 +1068,7 @@
331 {
332     int i;
333     uint16_t limit;
334+    int64_t now;
335 
336     switch (data[0]) {
337     case 0:
338@@ -1063,12 +1112,18 @@
339        if (len == 1)
340            return 8;
341 
342+       vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
343+       qemu_advance_timer(vs->timer,
344+                          qemu_get_clock(rt_clock) + vs->timer_interval);
345        key_event(vs, read_u8(data, 1), read_u32(data, 4));
346        break;
347     case 5:
348        if (len == 1)
349            return 6;
350 
351+       vs->timer_interval = VNC_REFRESH_INTERVAL_BASE;
352+       qemu_advance_timer(vs->timer,
353+                          qemu_get_clock(rt_clock) + vs->timer_interval);
354        pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
355        break;
356     case 6:
357Index: ioemu/vl.c
358===================================================================
359--- ioemu.orig/vl.c     2007-05-03 10:07:56.000000000 +0100
360+++ ioemu/vl.c  2007-05-03 10:07:56.000000000 +0100
361@@ -725,6 +725,12 @@
362     }
363 }
364 
365+void qemu_advance_timer(QEMUTimer *ts, int64_t expire_time)
366+{
367+    if (ts->expire_time > expire_time || !qemu_timer_pending(ts))
368+       qemu_mod_timer(ts, expire_time);
369+}
370+
371 /* modify the current timer so that it will be fired when current_time
372    >= expire_time. The corresponding callback will be called. */
373 void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
374Index: ioemu/vl.h
375===================================================================
376--- ioemu.orig/vl.h     2007-05-03 10:07:56.000000000 +0100
377+++ ioemu/vl.h  2007-05-03 10:07:56.000000000 +0100
378@@ -407,6 +407,7 @@
379 void qemu_free_timer(QEMUTimer *ts);
380 void qemu_del_timer(QEMUTimer *ts);
381 void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
382+void qemu_advance_timer(QEMUTimer *ts, int64_t expire_time);
383 int qemu_timer_pending(QEMUTimer *ts);
384 
385 extern int64_t ticks_per_sec;
Note: See TracBrowser for help on using the repository browser.