215 |
215 |
3) resolutions > 1024
|
216 |
216 |
*/
|
217 |
217 |
|
218 |
|
static void vnc_update_client(VncState *vs);
|
|
218 |
static void vnc_update_client(VncState *vs, int has_dirty);
|
219 |
219 |
static void vnc_disconnect_start(VncState *vs);
|
220 |
220 |
static void vnc_disconnect_finish(VncState *vs);
|
221 |
221 |
static void vnc_init_timer(VncDisplay *vd);
|
222 |
222 |
static void vnc_remove_timer(VncDisplay *vd);
|
223 |
223 |
|
224 |
224 |
static void vnc_colordepth(VncState *vs);
|
|
225 |
static void framebuffer_update_request(VncState *vs, int incremental,
|
|
226 |
int x_position, int y_position,
|
|
227 |
int w, int h);
|
|
228 |
static void vnc_refresh(void *opaque);
|
|
229 |
static int vnc_refresh_server_surface(VncDisplay *vd);
|
225 |
230 |
|
226 |
231 |
static inline void vnc_set_bit(uint32_t *d, int k)
|
227 |
232 |
{
|
... | ... | |
264 |
269 |
return 0;
|
265 |
270 |
}
|
266 |
271 |
|
267 |
|
static void vnc_update(VncState *vs, int x, int y, int w, int h)
|
|
272 |
static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
|
268 |
273 |
{
|
269 |
|
struct VncSurface *s = &vs->guest;
|
270 |
274 |
int i;
|
|
275 |
VncDisplay *vd = ds->opaque;
|
|
276 |
struct VncSurface *s = &vd->guest;
|
271 |
277 |
|
272 |
278 |
h += y;
|
273 |
279 |
|
... | ... | |
288 |
294 |
vnc_set_bit(s->dirty[y], (x + i) / 16);
|
289 |
295 |
}
|
290 |
296 |
|
291 |
|
static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
|
292 |
|
{
|
293 |
|
VncDisplay *vd = ds->opaque;
|
294 |
|
VncState *vs = vd->clients;
|
295 |
|
while (vs != NULL) {
|
296 |
|
vnc_update(vs, x, y, w, h);
|
297 |
|
vs = vs->next;
|
298 |
|
}
|
299 |
|
}
|
300 |
|
|
301 |
297 |
static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
|
302 |
298 |
int32_t encoding)
|
303 |
299 |
{
|
... | ... | |
342 |
338 |
buffer->offset += len;
|
343 |
339 |
}
|
344 |
340 |
|
345 |
|
static void vnc_resize(VncState *vs)
|
|
341 |
static void vnc_dpy_resize(DisplayState *ds)
|
346 |
342 |
{
|
347 |
|
DisplayState *ds = vs->ds;
|
348 |
343 |
int size_changed;
|
|
344 |
VncDisplay *vd = ds->opaque;
|
|
345 |
VncState *vs = vd->clients;
|
|
346 |
|
|
347 |
/* server surface */
|
|
348 |
if (!vd->server)
|
|
349 |
vd->server = qemu_mallocz(sizeof(*vd->server));
|
|
350 |
if (vd->server->data)
|
|
351 |
qemu_free(vd->server->data);
|
|
352 |
*(vd->server) = *(ds->surface);
|
|
353 |
vd->server->data = qemu_mallocz(vd->server->linesize *
|
|
354 |
vd->server->height);
|
349 |
355 |
|
350 |
356 |
/* guest surface */
|
351 |
|
if (!vs->guest.ds)
|
352 |
|
vs->guest.ds = qemu_mallocz(sizeof(*vs->guest.ds));
|
353 |
|
if (ds_get_bytes_per_pixel(ds) != vs->guest.ds->pf.bytes_per_pixel)
|
|
357 |
if (!vd->guest.ds)
|
|
358 |
vd->guest.ds = qemu_mallocz(sizeof(*vd->guest.ds));
|
|
359 |
if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel)
|
354 |
360 |
console_color_init(ds);
|
355 |
|
vnc_colordepth(vs);
|
356 |
|
size_changed = ds_get_width(ds) != vs->guest.ds->width ||
|
357 |
|
ds_get_height(ds) != vs->guest.ds->height;
|
358 |
|
*(vs->guest.ds) = *(ds->surface);
|
359 |
|
if (size_changed) {
|
360 |
|
if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
|
361 |
|
vnc_write_u8(vs, 0); /* msg id */
|
362 |
|
vnc_write_u8(vs, 0);
|
363 |
|
vnc_write_u16(vs, 1); /* number of rects */
|
364 |
|
vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds),
|
365 |
|
VNC_ENCODING_DESKTOPRESIZE);
|
366 |
|
vnc_flush(vs);
|
367 |
|
}
|
368 |
|
}
|
369 |
|
memset(vs->guest.dirty, 0xFF, sizeof(vs->guest.dirty));
|
|
361 |
size_changed = ds_get_width(ds) != vd->guest.ds->width ||
|
|
362 |
ds_get_height(ds) != vd->guest.ds->height;
|
|
363 |
*(vd->guest.ds) = *(ds->surface);
|
|
364 |
memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty));
|
370 |
365 |
|
371 |
|
/* server surface */
|
372 |
|
if (!vs->server.ds)
|
373 |
|
vs->server.ds = qemu_mallocz(sizeof(*vs->server.ds));
|
374 |
|
if (vs->server.ds->data)
|
375 |
|
qemu_free(vs->server.ds->data);
|
376 |
|
*(vs->server.ds) = *(ds->surface);
|
377 |
|
vs->server.ds->data = qemu_mallocz(vs->server.ds->linesize *
|
378 |
|
vs->server.ds->height);
|
379 |
|
memset(vs->server.dirty, 0xFF, sizeof(vs->guest.dirty));
|
380 |
|
}
|
381 |
|
|
382 |
|
static void vnc_dpy_resize(DisplayState *ds)
|
383 |
|
{
|
384 |
|
VncDisplay *vd = ds->opaque;
|
385 |
|
VncState *vs = vd->clients;
|
386 |
366 |
while (vs != NULL) {
|
387 |
|
vnc_resize(vs);
|
|
367 |
vnc_colordepth(vs);
|
|
368 |
if (size_changed) {
|
|
369 |
if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
|
|
370 |
vnc_write_u8(vs, 0); /* msg id */
|
|
371 |
vnc_write_u8(vs, 0);
|
|
372 |
vnc_write_u16(vs, 1); /* number of rects */
|
|
373 |
vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds),
|
|
374 |
VNC_ENCODING_DESKTOPRESIZE);
|
|
375 |
vnc_flush(vs);
|
|
376 |
}
|
|
377 |
}
|
|
378 |
memset(vs->dirty, 0xFF, sizeof(vs->dirty));
|
388 |
379 |
vs = vs->next;
|
389 |
380 |
}
|
390 |
381 |
}
|
... | ... | |
399 |
390 |
static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
|
400 |
391 |
{
|
401 |
392 |
uint8_t r, g, b;
|
402 |
|
|
403 |
|
r = ((((v & vs->server.ds->pf.rmask) >> vs->server.ds->pf.rshift) << vs->clientds.pf.rbits) >>
|
404 |
|
vs->server.ds->pf.rbits);
|
405 |
|
g = ((((v & vs->server.ds->pf.gmask) >> vs->server.ds->pf.gshift) << vs->clientds.pf.gbits) >>
|
406 |
|
vs->server.ds->pf.gbits);
|
407 |
|
b = ((((v & vs->server.ds->pf.bmask) >> vs->server.ds->pf.bshift) << vs->clientds.pf.bbits) >>
|
408 |
|
vs->server.ds->pf.bbits);
|
|
393 |
VncDisplay *vd = vs->vd;
|
|
394 |
|
|
395 |
r = ((((v & vd->server->pf.rmask) >> vd->server->pf.rshift) << vs->clientds.pf.rbits) >>
|
|
396 |
vd->server->pf.rbits);
|
|
397 |
g = ((((v & vd->server->pf.gmask) >> vd->server->pf.gshift) << vs->clientds.pf.gbits) >>
|
|
398 |
vd->server->pf.gbits);
|
|
399 |
b = ((((v & vd->server->pf.bmask) >> vd->server->pf.bshift) << vs->clientds.pf.bbits) >>
|
|
400 |
vd->server->pf.bbits);
|
409 |
401 |
v = (r << vs->clientds.pf.rshift) |
|
410 |
402 |
(g << vs->clientds.pf.gshift) |
|
411 |
403 |
(b << vs->clientds.pf.bshift);
|
... | ... | |
442 |
434 |
static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
|
443 |
435 |
{
|
444 |
436 |
uint8_t buf[4];
|
|
437 |
VncDisplay *vd = vs->vd;
|
445 |
438 |
|
446 |
|
if (vs->server.ds->pf.bytes_per_pixel == 4) {
|
|
439 |
if (vd->server->pf.bytes_per_pixel == 4) {
|
447 |
440 |
uint32_t *pixels = pixels1;
|
448 |
441 |
int n, i;
|
449 |
442 |
n = size >> 2;
|
... | ... | |
451 |
444 |
vnc_convert_pixel(vs, buf, pixels[i]);
|
452 |
445 |
vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
|
453 |
446 |
}
|
454 |
|
} else if (vs->server.ds->pf.bytes_per_pixel == 2) {
|
|
447 |
} else if (vd->server->pf.bytes_per_pixel == 2) {
|
455 |
448 |
uint16_t *pixels = pixels1;
|
456 |
449 |
int n, i;
|
457 |
450 |
n = size >> 1;
|
... | ... | |
459 |
452 |
vnc_convert_pixel(vs, buf, pixels[i]);
|
460 |
453 |
vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel);
|
461 |
454 |
}
|
462 |
|
} else if (vs->server.ds->pf.bytes_per_pixel == 1) {
|
|
455 |
} else if (vd->server->pf.bytes_per_pixel == 1) {
|
463 |
456 |
uint8_t *pixels = pixels1;
|
464 |
457 |
int n, i;
|
465 |
458 |
n = size;
|
... | ... | |
476 |
469 |
{
|
477 |
470 |
int i;
|
478 |
471 |
uint8_t *row;
|
|
472 |
VncDisplay *vd = vs->vd;
|
479 |
473 |
|
480 |
|
row = vs->server.ds->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
|
|
474 |
row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
|
481 |
475 |
for (i = 0; i < h; i++) {
|
482 |
476 |
vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
|
483 |
477 |
row += ds_get_linesize(vs->ds);
|
... | ... | |
525 |
519 |
int i, j;
|
526 |
520 |
int has_fg, has_bg;
|
527 |
521 |
uint8_t *last_fg, *last_bg;
|
|
522 |
VncDisplay *vd = vs->vd;
|
528 |
523 |
|
529 |
|
last_fg = (uint8_t *) qemu_malloc(vs->server.ds->pf.bytes_per_pixel);
|
530 |
|
last_bg = (uint8_t *) qemu_malloc(vs->server.ds->pf.bytes_per_pixel);
|
|
524 |
last_fg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
|
|
525 |
last_bg = (uint8_t *) qemu_malloc(vd->server->pf.bytes_per_pixel);
|
531 |
526 |
has_fg = has_bg = 0;
|
532 |
527 |
for (j = y; j < (y + h); j += 16) {
|
533 |
528 |
for (i = x; i < (x + w); i += 16) {
|
... | ... | |
656 |
651 |
|
657 |
652 |
static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
|
658 |
653 |
{
|
659 |
|
uint8_t *src_row;
|
660 |
|
uint8_t *dst_row;
|
661 |
|
int y,pitch,depth;
|
662 |
|
|
663 |
654 |
/* send bitblit op to the vnc client */
|
664 |
655 |
vnc_write_u8(vs, 0); /* msg id */
|
665 |
656 |
vnc_write_u8(vs, 0);
|
... | ... | |
668 |
659 |
vnc_write_u16(vs, src_x);
|
669 |
660 |
vnc_write_u16(vs, src_y);
|
670 |
661 |
vnc_flush(vs);
|
671 |
|
|
672 |
|
/* do bitblit op on the local surface too */
|
673 |
|
pitch = ds_get_linesize(vs->ds);
|
674 |
|
depth = ds_get_bytes_per_pixel(vs->ds);
|
675 |
|
src_row = vs->server.ds->data + pitch * src_y + depth * src_x;
|
676 |
|
dst_row = vs->server.ds->data + pitch * dst_y + depth * dst_x;
|
677 |
|
if (dst_y > src_y) {
|
678 |
|
/* copy backwards */
|
679 |
|
src_row += pitch * (h-1);
|
680 |
|
dst_row += pitch * (h-1);
|
681 |
|
pitch = -pitch;
|
682 |
|
}
|
683 |
|
for (y = 0; y < h; y++) {
|
684 |
|
memmove(dst_row, src_row, w * depth);
|
685 |
|
src_row += pitch;
|
686 |
|
dst_row += pitch;
|
687 |
|
}
|
688 |
662 |
}
|
689 |
663 |
|
690 |
664 |
static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
|
691 |
665 |
{
|
692 |
666 |
VncDisplay *vd = ds->opaque;
|
693 |
667 |
VncState *vs, *vn;
|
|
668 |
uint8_t *src_row;
|
|
669 |
uint8_t *dst_row;
|
|
670 |
int i,x,y,pitch,depth,inc,w_lim,s;
|
|
671 |
int cmp_bytes;
|
694 |
672 |
|
|
673 |
vnc_refresh_server_surface(vd);
|
695 |
674 |
for (vs = vd->clients; vs != NULL; vs = vn) {
|
696 |
675 |
vn = vs->next;
|
697 |
676 |
if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
|
698 |
677 |
vs->force_update = 1;
|
699 |
|
vnc_update_client(vs);
|
|
678 |
vnc_update_client(vs, 1);
|
700 |
679 |
/* vs might be free()ed here */
|
701 |
680 |
}
|
702 |
681 |
}
|
703 |
682 |
|
|
683 |
/* do bitblit op on the local surface too */
|
|
684 |
pitch = ds_get_linesize(vd->ds);
|
|
685 |
depth = ds_get_bytes_per_pixel(vd->ds);
|
|
686 |
src_row = vd->server->data + pitch * src_y + depth * src_x;
|
|
687 |
dst_row = vd->server->data + pitch * dst_y + depth * dst_x;
|
|
688 |
y = dst_y;
|
|
689 |
inc = 1;
|
|
690 |
if (dst_y > src_y) {
|
|
691 |
/* copy backwards */
|
|
692 |
src_row += pitch * (h-1);
|
|
693 |
dst_row += pitch * (h-1);
|
|
694 |
pitch = -pitch;
|
|
695 |
y = dst_y + h - 1;
|
|
696 |
inc = -1;
|
|
697 |
}
|
|
698 |
w_lim = w - (16 - (dst_x % 16));
|
|
699 |
if (w_lim < 0)
|
|
700 |
w_lim = w;
|
|
701 |
else
|
|
702 |
w_lim = w - (w_lim % 16);
|
|
703 |
for (i = 0; i < h; i++) {
|
|
704 |
for (x = 0; x <= w_lim;
|
|
705 |
x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
|
|
706 |
if (x == w_lim) {
|
|
707 |
if ((s = w - w_lim) == 0)
|
|
708 |
break;
|
|
709 |
} else if (!x) {
|
|
710 |
s = (16 - (dst_x % 16));
|
|
711 |
s = MIN(s, w_lim);
|
|
712 |
} else {
|
|
713 |
s = 16;
|
|
714 |
}
|
|
715 |
cmp_bytes = s * depth;
|
|
716 |
if (memcmp(src_row, dst_row, cmp_bytes) == 0)
|
|
717 |
continue;
|
|
718 |
memmove(dst_row, src_row, cmp_bytes);
|
|
719 |
vs = vd->clients;
|
|
720 |
while (vs != NULL) {
|
|
721 |
if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
|
|
722 |
vnc_set_bit(vs->dirty[y], ((x + dst_x) / 16));
|
|
723 |
vs = vs->next;
|
|
724 |
}
|
|
725 |
}
|
|
726 |
src_row += pitch - w * depth;
|
|
727 |
dst_row += pitch - w * depth;
|
|
728 |
y += inc;
|
|
729 |
}
|
|
730 |
|
704 |
731 |
for (vs = vd->clients; vs != NULL; vs = vs->next) {
|
705 |
732 |
if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
|
706 |
733 |
vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
|
707 |
|
else /* TODO */
|
708 |
|
vnc_update(vs, dst_x, dst_y, w, h);
|
709 |
734 |
}
|
710 |
735 |
}
|
711 |
736 |
|
712 |
|
static int find_and_clear_dirty_height(struct VncSurface *s,
|
|
737 |
static int find_and_clear_dirty_height(struct VncState *vs,
|
713 |
738 |
int y, int last_x, int x)
|
714 |
739 |
{
|
715 |
740 |
int h;
|
|
741 |
VncDisplay *vd = vs->vd;
|
716 |
742 |
|
717 |
|
for (h = 1; h < (s->ds->height - y); h++) {
|
|
743 |
for (h = 1; h < (vd->server->height - y); h++) {
|
718 |
744 |
int tmp_x;
|
719 |
|
if (!vnc_get_bit(s->dirty[y + h], last_x))
|
|
745 |
if (!vnc_get_bit(vs->dirty[y + h], last_x))
|
720 |
746 |
break;
|
721 |
747 |
for (tmp_x = last_x; tmp_x < x; tmp_x++)
|
722 |
|
vnc_clear_bit(s->dirty[y + h], tmp_x);
|
|
748 |
vnc_clear_bit(vs->dirty[y + h], tmp_x);
|
723 |
749 |
}
|
724 |
750 |
|
725 |
751 |
return h;
|
726 |
752 |
}
|
727 |
753 |
|
728 |
|
static void vnc_update_client(VncState *vs)
|
|
754 |
static void vnc_update_client(VncState *vs, int has_dirty)
|
729 |
755 |
{
|
730 |
756 |
if (vs->need_update && vs->csock != -1) {
|
|
757 |
VncDisplay *vd = vs->vd;
|
731 |
758 |
int y;
|
732 |
|
uint8_t *guest_row;
|
733 |
|
uint8_t *server_row;
|
734 |
|
int cmp_bytes;
|
735 |
|
uint32_t width_mask[VNC_DIRTY_WORDS];
|
736 |
759 |
int n_rectangles;
|
737 |
760 |
int saved_offset;
|
738 |
|
int has_dirty = 0;
|
739 |
761 |
|
740 |
762 |
if (vs->output.offset && !vs->audio_cap && !vs->force_update)
|
741 |
763 |
/* kernel send buffers are full -> drop frames to throttle */
|
742 |
764 |
return;
|
743 |
765 |
|
744 |
|
/*
|
745 |
|
* Walk through the guest dirty map.
|
746 |
|
* Check and copy modified bits from guest to server surface.
|
747 |
|
* Update server dirty map.
|
748 |
|
*/
|
749 |
|
vnc_set_bits(width_mask, (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
|
750 |
|
cmp_bytes = 16 * ds_get_bytes_per_pixel(vs->ds);
|
751 |
|
guest_row = vs->guest.ds->data;
|
752 |
|
server_row = vs->server.ds->data;
|
753 |
|
for (y = 0; y < vs->guest.ds->height; y++) {
|
754 |
|
if (vnc_and_bits(vs->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) {
|
755 |
|
int x;
|
756 |
|
uint8_t *guest_ptr;
|
757 |
|
uint8_t *server_ptr;
|
758 |
|
|
759 |
|
guest_ptr = guest_row;
|
760 |
|
server_ptr = server_row;
|
761 |
|
|
762 |
|
for (x = 0; x < vs->guest.ds->width;
|
763 |
|
x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
|
764 |
|
if (!vnc_get_bit(vs->guest.dirty[y], (x / 16)))
|
765 |
|
continue;
|
766 |
|
vnc_clear_bit(vs->guest.dirty[y], (x / 16));
|
767 |
|
if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
|
768 |
|
continue;
|
769 |
|
memcpy(server_ptr, guest_ptr, cmp_bytes);
|
770 |
|
vnc_set_bit(vs->server.dirty[y], (x / 16));
|
771 |
|
has_dirty++;
|
772 |
|
}
|
773 |
|
}
|
774 |
|
guest_row += ds_get_linesize(vs->ds);
|
775 |
|
server_row += ds_get_linesize(vs->ds);
|
776 |
|
}
|
777 |
|
|
778 |
766 |
if (!has_dirty && !vs->audio_cap && !vs->force_update)
|
779 |
767 |
return;
|
780 |
768 |
|
... | ... | |
790 |
778 |
saved_offset = vs->output.offset;
|
791 |
779 |
vnc_write_u16(vs, 0);
|
792 |
780 |
|
793 |
|
for (y = 0; y < vs->server.ds->height; y++) {
|
|
781 |
for (y = 0; y < vd->server->height; y++) {
|
794 |
782 |
int x;
|
795 |
783 |
int last_x = -1;
|
796 |
|
for (x = 0; x < vs->server.ds->width / 16; x++) {
|
797 |
|
if (vnc_get_bit(vs->server.dirty[y], x)) {
|
|
784 |
for (x = 0; x < vd->server->width / 16; x++) {
|
|
785 |
if (vnc_get_bit(vs->dirty[y], x)) {
|
798 |
786 |
if (last_x == -1) {
|
799 |
787 |
last_x = x;
|
800 |
788 |
}
|
801 |
|
vnc_clear_bit(vs->server.dirty[y], x);
|
|
789 |
vnc_clear_bit(vs->dirty[y], x);
|
802 |
790 |
} else {
|
803 |
791 |
if (last_x != -1) {
|
804 |
|
int h = find_and_clear_dirty_height(&vs->server, y, last_x, x);
|
|
792 |
int h = find_and_clear_dirty_height(vs, y, last_x, x);
|
805 |
793 |
send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
|
806 |
794 |
n_rectangles++;
|
807 |
795 |
}
|
... | ... | |
809 |
797 |
}
|
810 |
798 |
}
|
811 |
799 |
if (last_x != -1) {
|
812 |
|
int h = find_and_clear_dirty_height(&vs->server, y, last_x, x);
|
|
800 |
int h = find_and_clear_dirty_height(vs, y, last_x, x);
|
813 |
801 |
send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h);
|
814 |
802 |
n_rectangles++;
|
815 |
803 |
}
|
... | ... | |
926 |
914 |
if (!vs->vd->clients)
|
927 |
915 |
dcl->idle = 1;
|
928 |
916 |
|
929 |
|
qemu_free(vs->server.ds->data);
|
930 |
|
qemu_free(vs->server.ds);
|
931 |
|
qemu_free(vs->guest.ds);
|
932 |
917 |
qemu_free(vs);
|
933 |
918 |
vnc_remove_timer(vs->vd);
|
934 |
919 |
}
|
... | ... | |
1507 |
1492 |
if (!incremental) {
|
1508 |
1493 |
vs->force_update = 1;
|
1509 |
1494 |
for (i = 0; i < h; i++) {
|
1510 |
|
vnc_set_bits(vs->guest.dirty[y_position + i],
|
1511 |
|
(ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
|
1512 |
|
vnc_set_bits(vs->server.dirty[y_position + i],
|
|
1495 |
vnc_set_bits(vs->dirty[y_position + i],
|
1513 |
1496 |
(ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS);
|
1514 |
1497 |
}
|
1515 |
1498 |
}
|
... | ... | |
1638 |
1621 |
return;
|
1639 |
1622 |
}
|
1640 |
1623 |
|
1641 |
|
vs->clientds = *(vs->guest.ds);
|
|
1624 |
vs->clientds = *(vs->vd->guest.ds);
|
1642 |
1625 |
vs->clientds.pf.rmax = red_max;
|
1643 |
1626 |
count_bits(vs->clientds.pf.rbits, red_max);
|
1644 |
1627 |
vs->clientds.pf.rshift = red_shift;
|
... | ... | |
2067 |
2050 |
return 0;
|
2068 |
2051 |
}
|
2069 |
2052 |
|
|
2053 |
static int vnc_refresh_server_surface(VncDisplay *vd)
|
|
2054 |
{
|
|
2055 |
int y;
|
|
2056 |
uint8_t *guest_row;
|
|
2057 |
uint8_t *server_row;
|
|
2058 |
int cmp_bytes;
|
|
2059 |
uint32_t width_mask[VNC_DIRTY_WORDS];
|
|
2060 |
VncState *vs = NULL;
|
|
2061 |
int has_dirty = 0;
|
|
2062 |
|
|
2063 |
/*
|
|
2064 |
* Walk through the guest dirty map.
|
|
2065 |
* Check and copy modified bits from guest to server surface.
|
|
2066 |
* Update server dirty map.
|
|
2067 |
*/
|
|
2068 |
vnc_set_bits(width_mask, (ds_get_width(vd->ds) / 16), VNC_DIRTY_WORDS);
|
|
2069 |
cmp_bytes = 16 * ds_get_bytes_per_pixel(vd->ds);
|
|
2070 |
guest_row = vd->guest.ds->data;
|
|
2071 |
server_row = vd->server->data;
|
|
2072 |
for (y = 0; y < vd->guest.ds->height; y++) {
|
|
2073 |
if (vnc_and_bits(vd->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) {
|
|
2074 |
int x;
|
|
2075 |
uint8_t *guest_ptr;
|
|
2076 |
uint8_t *server_ptr;
|
|
2077 |
|
|
2078 |
guest_ptr = guest_row;
|
|
2079 |
server_ptr = server_row;
|
|
2080 |
|
|
2081 |
for (x = 0; x < vd->guest.ds->width;
|
|
2082 |
x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
|
|
2083 |
if (!vnc_get_bit(vd->guest.dirty[y], (x / 16)))
|
|
2084 |
continue;
|
|
2085 |
vnc_clear_bit(vd->guest.dirty[y], (x / 16));
|
|
2086 |
if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
|
|
2087 |
continue;
|
|
2088 |
memcpy(server_ptr, guest_ptr, cmp_bytes);
|
|
2089 |
vs = vd->clients;
|
|
2090 |
while (vs != NULL) {
|
|
2091 |
vnc_set_bit(vs->dirty[y], (x / 16));
|
|
2092 |
vs = vs->next;
|
|
2093 |
}
|
|
2094 |
has_dirty++;
|
|
2095 |
}
|
|
2096 |
}
|
|
2097 |
guest_row += ds_get_linesize(vd->ds);
|
|
2098 |
server_row += ds_get_linesize(vd->ds);
|
|
2099 |
}
|
|
2100 |
return has_dirty;
|
|
2101 |
}
|
|
2102 |
|
2070 |
2103 |
static void vnc_refresh(void *opaque)
|
2071 |
2104 |
{
|
2072 |
2105 |
VncDisplay *vd = opaque;
|
2073 |
|
VncState *vs = vd->clients;
|
|
2106 |
VncState *vs = NULL;
|
|
2107 |
int has_dirty = 0;
|
2074 |
2108 |
|
2075 |
2109 |
vga_hw_update();
|
2076 |
2110 |
|
|
2111 |
has_dirty = vnc_refresh_server_surface(vd);
|
|
2112 |
|
|
2113 |
vs = vd->clients;
|
2077 |
2114 |
while (vs != NULL) {
|
2078 |
|
vnc_update_client(vs);
|
|
2115 |
vnc_update_client(vs, has_dirty);
|
2079 |
2116 |
vs = vs->next;
|
2080 |
2117 |
}
|
2081 |
2118 |
|
... | ... | |
2086 |
2123 |
{
|
2087 |
2124 |
if (vd->timer == NULL && vd->clients != NULL) {
|
2088 |
2125 |
vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd);
|
2089 |
|
qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL);
|
|
2126 |
vnc_refresh(vd);
|
2090 |
2127 |
}
|
2091 |
2128 |
}
|
2092 |
2129 |
|
... | ... | |
2119 |
2156 |
vs->as.fmt = AUD_FMT_S16;
|
2120 |
2157 |
vs->as.endianness = 0;
|
2121 |
2158 |
|
2122 |
|
vnc_resize(vs);
|
|
2159 |
vs->next = vd->clients;
|
|
2160 |
vd->clients = vs;
|
|
2161 |
|
|
2162 |
vga_hw_update();
|
|
2163 |
|
2123 |
2164 |
vnc_write(vs, "RFB 003.008\n", 12);
|
2124 |
2165 |
vnc_flush(vs);
|
2125 |
2166 |
vnc_read_when(vs, protocol_version, 12);
|
2126 |
2167 |
reset_keys(vs);
|
2127 |
2168 |
|
2128 |
|
vs->next = vd->clients;
|
2129 |
|
vd->clients = vs;
|
2130 |
|
|
2131 |
2169 |
vnc_init_timer(vd);
|
2132 |
|
vnc_update_client(vs);
|
|
2170 |
|
2133 |
2171 |
/* vs might be free()ed here */
|
2134 |
2172 |
}
|
2135 |
2173 |
|