static int vnc_refresh_server_surface(VncDisplay *vd) { int width = MIN(pixman_image_get_width(vd->guest.fb), pixman_image_get_width(vd->server)); int height = MIN(pixman_image_get_height(vd->guest.fb), pixman_image_get_height(vd->server)); int cmp_bytes, server_stride, min_stride, guest_stride, y = 0; uint8_t *guest_row0 = NULL, *server_row0; VncState *vs; int has_dirty = 0; pixman_image_t *tmpbuf = NULL; struct timeval tv = { 0, 0 }; if (!vd->non_adaptive) { gettimeofday(&tv, NULL); has_dirty = vnc_update_stats(vd, &tv); } /* * Walk through the guest dirty map. * Check and copy modified bits from guest to server surface. * Update server dirty map. */ server_row0 = (uint8_t *)pixman_image_get_data(vd->server); server_stride = guest_stride = pixman_image_get_stride(vd->server); cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES, server_stride); if (vd->guest.format != VNC_SERVER_FB_FORMAT) { int width = pixman_image_get_width(vd->server); tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width); } else { guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb); guest_stride = pixman_image_get_stride(vd->guest.fb); } min_stride = MIN(server_stride, guest_stride); for (;;) { int x; uint8_t *guest_ptr, *server_ptr; unsigned long offset = find_next_bit((unsigned long *) &vd->guest.dirty, height * VNC_DIRTY_BPL(&vd->guest), y * VNC_DIRTY_BPL(&vd->guest)); if (offset == height * VNC_DIRTY_BPL(&vd->guest)) { /* no more dirty bits */ break; } y = offset / VNC_DIRTY_BPL(&vd->guest); x = offset % VNC_DIRTY_BPL(&vd->guest); server_ptr = server_row0 + y * server_stride + x * cmp_bytes; if (vd->guest.format != VNC_SERVER_FB_FORMAT) { qemu_pixman_linebuf_fill(tmpbuf, vd->guest.fb, width, 0, y); guest_ptr = (uint8_t *)pixman_image_get_data(tmpbuf); } else { guest_ptr = guest_row0 + y * guest_stride; } guest_ptr += x * cmp_bytes; for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT); x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) { int _cmp_bytes = cmp_bytes; if (!test_and_clear_bit(x, vd->guest.dirty[y])) { continue; } if ((x + 1) * cmp_bytes > min_stride) { _cmp_bytes = min_stride - x * cmp_bytes; } if (memcmp(server_ptr, guest_ptr, _cmp_bytes) == 0) { continue; } memcpy(server_ptr, guest_ptr, _cmp_bytes); if (!vd->non_adaptive) { vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT, y, &tv); } QTAILQ_FOREACH(vs, &vd->clients, next) { set_bit(x, vs->dirty[y]); } has_dirty++; } y++; } qemu_pixman_image_unref(tmpbuf); return has_dirty; }