Revision 1fc62412 vnc.c
b/vnc.c | ||
---|---|---|
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 |
|
Also available in: Unified diff