vnc dirty tracking optinizations.
various vnc bugfixes. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTHbKaAAoJEEy22O7T6HE4zwAP/0Auz/T/Q+r3KQQfAgICFg4F wdWUQFi+M9+iub8tR+MAJLxJDGjyT3QQcYk7wyQTbttEHJawlhrHNFZYPlbsPOI1 VuS/hATioUD815ch5gcuGt8yS7z9YfGwn84yopoge3L6SkW9x9jp/uXLvVe5WzJ1 +5pGVVKH22aHG7kurrfGuqh1Uofj/GlPy6D5hX3DtLu1WPoTJN53ODwU35qR9j+o m1y1kDKN6KXICSDSzieLgSV4P6f4vu9zM3yiArK31tEWR+gBMH1lysoqYWIc+NCG R4QQZjDOYGIyXfCAPZJ0iV1wcoep2mPOxF0e+3WwXtBK0yRIFPEHwT5/geTpTsWK 9+ERRflEYIx5evbw2+LHlW7AAeW7R8HhJggwp4UeWC9grjFNbS86JHsJDQ4Op84k oDtr11uG9z+GBCXDOLEe2/1WpPSTnd/K1bMW5x/AvDX8MiVrE67gmErL4GM9WOnC C4LRZnfmzqCN4hfBeMoEWuqIekI4Q/5+0f2WRBpWWU5KMV9W6CLR6c9HGI3E/1sx 21DFzspK+97vG+T/LrmW0WKXTq3ll6H4QaoLDPccH4Pqy9x7FkgWXhWBPhWlTxsH Q+gvxW8XhspdyZnjLwovybo65o+JlXZ01eDLIINELr5Gx62MtWdnGUZqbdpH8V7P duCaAkU7tpjk9RtBFCN6 =7t/O -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/pull-vnc-1' into staging vnc dirty tracking optinizations. various vnc bugfixes. # gpg: Signature made Mon 10 Mar 2014 12:39:54 GMT using RSA key ID D3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" * remotes/kraxel/tags/pull-vnc-1: ui/vnc: disable adaptive update calculations if not needed ui/vnc: optimize setting in vnc_dpy_update() ui/vnc: optimize clearing in find_and_clear_dirty_height() ui/vnc: optimize dirty bitmap tracking ui/vnc: derive cmp_bytes from VNC_DIRTY_PIXELS_PER_BIT ui/vnc: introduce VNC_DIRTY_PIXELS_PER_BIT macro vnc: fix use-after-free in vnc_update_client_sync vnc: Fix qemu crashed when vnc client disconnect suddenly vnc: Fix tight_detect_smooth_image() for lossless case Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						fe6c53b4bb
					
				| 
						 | 
				
			
			@ -330,7 +330,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h)
 | 
			
		|||
    } else {
 | 
			
		||||
        errors = tight_detect_smooth_image16(vs, w, h);
 | 
			
		||||
    }
 | 
			
		||||
    if (quality != -1) {
 | 
			
		||||
    if (quality != (uint8_t)-1) {
 | 
			
		||||
        return (errors < tight_conf[quality].jpeg_threshold);
 | 
			
		||||
    }
 | 
			
		||||
    return (errors < tight_conf[compression].gradient_threshold);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -252,6 +252,8 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
 | 
			
		|||
 | 
			
		||||
        if (job->vs->csock == -1) {
 | 
			
		||||
            vnc_unlock_display(job->vs->vd);
 | 
			
		||||
            /* Copy persistent encoding data */
 | 
			
		||||
            vnc_async_encoding_end(job->vs, &vs);
 | 
			
		||||
            goto disconnected;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -278,6 +280,9 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
 | 
			
		|||
        vnc_async_encoding_end(job->vs, &vs);
 | 
			
		||||
 | 
			
		||||
	qemu_bh_schedule(job->vs->bh);
 | 
			
		||||
    }  else {
 | 
			
		||||
        /* Copy persistent encoding data */
 | 
			
		||||
        vnc_async_encoding_end(job->vs, &vs);
 | 
			
		||||
    }
 | 
			
		||||
    vnc_unlock_output(job->vs);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										227
									
								
								ui/vnc.c
								
								
								
								
							
							
						
						
									
										227
									
								
								ui/vnc.c
								
								
								
								
							| 
						 | 
				
			
			@ -417,8 +417,7 @@ out_error:
 | 
			
		|||
   3) resolutions > 1024
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
static int vnc_update_client(VncState *vs, int has_dirty);
 | 
			
		||||
static int vnc_update_client_sync(VncState *vs, int has_dirty);
 | 
			
		||||
static int vnc_update_client(VncState *vs, int has_dirty, bool sync);
 | 
			
		||||
static void vnc_disconnect_start(VncState *vs);
 | 
			
		||||
 | 
			
		||||
static void vnc_colordepth(VncState *vs);
 | 
			
		||||
| 
						 | 
				
			
			@ -431,29 +430,25 @@ static int vnc_refresh_server_surface(VncDisplay *vd);
 | 
			
		|||
static void vnc_dpy_update(DisplayChangeListener *dcl,
 | 
			
		||||
                           int x, int y, int w, int h)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
 | 
			
		||||
    struct VncSurface *s = &vd->guest;
 | 
			
		||||
    int width = surface_width(vd->ds);
 | 
			
		||||
    int height = surface_height(vd->ds);
 | 
			
		||||
 | 
			
		||||
    h += y;
 | 
			
		||||
 | 
			
		||||
    /* round x down to ensure the loop only spans one 16-pixel block per,
 | 
			
		||||
       iteration.  otherwise, if (x % 16) != 0, the last iteration may span
 | 
			
		||||
       two 16-pixel blocks but we only mark the first as dirty
 | 
			
		||||
    */
 | 
			
		||||
    w += (x % 16);
 | 
			
		||||
    x -= (x % 16);
 | 
			
		||||
    /* this is needed this to ensure we updated all affected
 | 
			
		||||
     * blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */
 | 
			
		||||
    w += (x % VNC_DIRTY_PIXELS_PER_BIT);
 | 
			
		||||
    x -= (x % VNC_DIRTY_PIXELS_PER_BIT);
 | 
			
		||||
 | 
			
		||||
    x = MIN(x, width);
 | 
			
		||||
    y = MIN(y, height);
 | 
			
		||||
    w = MIN(x + w, width) - x;
 | 
			
		||||
    h = MIN(h, height);
 | 
			
		||||
    h = MIN(y + h, height);
 | 
			
		||||
 | 
			
		||||
    for (; y < h; y++)
 | 
			
		||||
        for (i = 0; i < w; i += 16)
 | 
			
		||||
            set_bit((x + i) / 16, s->dirty[y]);
 | 
			
		||||
    for (; y < h; y++) {
 | 
			
		||||
        bitmap_set(s->dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
 | 
			
		||||
                   DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
 | 
			
		||||
| 
						 | 
				
			
			@ -571,6 +566,15 @@ void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
 | 
			
		|||
    ptr += x * VNC_SERVER_FB_BYTES;
 | 
			
		||||
    return ptr;
 | 
			
		||||
}
 | 
			
		||||
/* this sets only the visible pixels of a dirty bitmap */
 | 
			
		||||
#define VNC_SET_VISIBLE_PIXELS_DIRTY(bitmap, w, h) {\
 | 
			
		||||
        int y;\
 | 
			
		||||
        memset(bitmap, 0x00, sizeof(bitmap));\
 | 
			
		||||
        for (y = 0; y < h; y++) {\
 | 
			
		||||
            bitmap_set(bitmap[y], 0,\
 | 
			
		||||
                       DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));\
 | 
			
		||||
        } \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
static void vnc_dpy_switch(DisplayChangeListener *dcl,
 | 
			
		||||
                           DisplaySurface *surface)
 | 
			
		||||
| 
						 | 
				
			
			@ -596,7 +600,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
 | 
			
		|||
    qemu_pixman_image_unref(vd->guest.fb);
 | 
			
		||||
    vd->guest.fb = pixman_image_ref(surface->image);
 | 
			
		||||
    vd->guest.format = surface->format;
 | 
			
		||||
    memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty));
 | 
			
		||||
    VNC_SET_VISIBLE_PIXELS_DIRTY(vd->guest.dirty,
 | 
			
		||||
                                 surface_width(vd->ds),
 | 
			
		||||
                                 surface_height(vd->ds));
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH(vs, &vd->clients, next) {
 | 
			
		||||
        vnc_colordepth(vs);
 | 
			
		||||
| 
						 | 
				
			
			@ -604,7 +610,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
 | 
			
		|||
        if (vs->vd->cursor) {
 | 
			
		||||
            vnc_cursor_define(vs);
 | 
			
		||||
        }
 | 
			
		||||
        memset(vs->dirty, 0xFF, sizeof(vs->dirty));
 | 
			
		||||
        VNC_SET_VISIBLE_PIXELS_DIRTY(vs->dirty,
 | 
			
		||||
                                     surface_width(vd->ds),
 | 
			
		||||
                                     surface_height(vd->ds));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -751,7 +759,7 @@ static void vnc_dpy_copy(DisplayChangeListener *dcl,
 | 
			
		|||
    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
 | 
			
		||||
        if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
 | 
			
		||||
            vs->force_update = 1;
 | 
			
		||||
            vnc_update_client_sync(vs, 1);
 | 
			
		||||
            vnc_update_client(vs, 1, true);
 | 
			
		||||
            /* vs might be free()ed here */
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -770,11 +778,12 @@ static void vnc_dpy_copy(DisplayChangeListener *dcl,
 | 
			
		|||
        y = dst_y + h - 1;
 | 
			
		||||
        inc = -1;
 | 
			
		||||
    }
 | 
			
		||||
    w_lim = w - (16 - (dst_x % 16));
 | 
			
		||||
    if (w_lim < 0)
 | 
			
		||||
    w_lim = w - (VNC_DIRTY_PIXELS_PER_BIT - (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
 | 
			
		||||
    if (w_lim < 0) {
 | 
			
		||||
        w_lim = w;
 | 
			
		||||
    else
 | 
			
		||||
        w_lim = w - (w_lim % 16);
 | 
			
		||||
    } else {
 | 
			
		||||
        w_lim = w - (w_lim % VNC_DIRTY_PIXELS_PER_BIT);
 | 
			
		||||
    }
 | 
			
		||||
    for (i = 0; i < h; i++) {
 | 
			
		||||
        for (x = 0; x <= w_lim;
 | 
			
		||||
                x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
 | 
			
		||||
| 
						 | 
				
			
			@ -782,10 +791,11 @@ static void vnc_dpy_copy(DisplayChangeListener *dcl,
 | 
			
		|||
                if ((s = w - w_lim) == 0)
 | 
			
		||||
                    break;
 | 
			
		||||
            } else if (!x) {
 | 
			
		||||
                s = (16 - (dst_x % 16));
 | 
			
		||||
                s = (VNC_DIRTY_PIXELS_PER_BIT -
 | 
			
		||||
                    (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
 | 
			
		||||
                s = MIN(s, w_lim);
 | 
			
		||||
            } else {
 | 
			
		||||
                s = 16;
 | 
			
		||||
                s = VNC_DIRTY_PIXELS_PER_BIT;
 | 
			
		||||
            }
 | 
			
		||||
            cmp_bytes = s * VNC_SERVER_FB_BYTES;
 | 
			
		||||
            if (memcmp(src_row, dst_row, cmp_bytes) == 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -793,7 +803,8 @@ static void vnc_dpy_copy(DisplayChangeListener *dcl,
 | 
			
		|||
            memmove(dst_row, src_row, cmp_bytes);
 | 
			
		||||
            QTAILQ_FOREACH(vs, &vd->clients, next) {
 | 
			
		||||
                if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
 | 
			
		||||
                    set_bit(((x + dst_x) / 16), vs->dirty[y]);
 | 
			
		||||
                    set_bit(((x + dst_x) / VNC_DIRTY_PIXELS_PER_BIT),
 | 
			
		||||
                            vs->dirty[y]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -862,35 +873,24 @@ static int find_and_clear_dirty_height(struct VncState *vs,
 | 
			
		|||
    int h;
 | 
			
		||||
 | 
			
		||||
    for (h = 1; h < (height - y); h++) {
 | 
			
		||||
        int tmp_x;
 | 
			
		||||
        if (!test_bit(last_x, vs->dirty[y + h])) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        for (tmp_x = last_x; tmp_x < x; tmp_x++) {
 | 
			
		||||
            clear_bit(tmp_x, vs->dirty[y + h]);
 | 
			
		||||
        }
 | 
			
		||||
        bitmap_clear(vs->dirty[y + h], last_x, x - last_x);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int vnc_update_client_sync(VncState *vs, int has_dirty)
 | 
			
		||||
{
 | 
			
		||||
    int ret = vnc_update_client(vs, has_dirty);
 | 
			
		||||
    vnc_jobs_join(vs);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int vnc_update_client(VncState *vs, int has_dirty)
 | 
			
		||||
static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
 | 
			
		||||
{
 | 
			
		||||
    if (vs->need_update && vs->csock != -1) {
 | 
			
		||||
        VncDisplay *vd = vs->vd;
 | 
			
		||||
        VncJob *job;
 | 
			
		||||
        int y;
 | 
			
		||||
        int width, height;
 | 
			
		||||
        int height;
 | 
			
		||||
        int n = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if (vs->output.offset && !vs->audio_cap && !vs->force_update)
 | 
			
		||||
            /* kernel send buffers are full -> drop frames to throttle */
 | 
			
		||||
            return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -906,33 +906,27 @@ static int vnc_update_client(VncState *vs, int has_dirty)
 | 
			
		|||
         */
 | 
			
		||||
        job = vnc_job_new(vs);
 | 
			
		||||
 | 
			
		||||
        width = MIN(pixman_image_get_width(vd->server), vs->client_width);
 | 
			
		||||
        height = MIN(pixman_image_get_height(vd->server), vs->client_height);
 | 
			
		||||
 | 
			
		||||
        for (y = 0; y < height; y++) {
 | 
			
		||||
            int x;
 | 
			
		||||
            int last_x = -1;
 | 
			
		||||
            for (x = 0; x < width / 16; x++) {
 | 
			
		||||
                if (test_and_clear_bit(x, vs->dirty[y])) {
 | 
			
		||||
                    if (last_x == -1) {
 | 
			
		||||
                        last_x = x;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    if (last_x != -1) {
 | 
			
		||||
                        int h = find_and_clear_dirty_height(vs, y, last_x, x,
 | 
			
		||||
                                                            height);
 | 
			
		||||
 | 
			
		||||
                        n += vnc_job_add_rect(job, last_x * 16, y,
 | 
			
		||||
                                              (x - last_x) * 16, h);
 | 
			
		||||
                    }
 | 
			
		||||
                    last_x = -1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (last_x != -1) {
 | 
			
		||||
                int h = find_and_clear_dirty_height(vs, y, last_x, x, height);
 | 
			
		||||
                n += vnc_job_add_rect(job, last_x * 16, y,
 | 
			
		||||
                                      (x - last_x) * 16, h);
 | 
			
		||||
        y = 0;
 | 
			
		||||
        for (;;) {
 | 
			
		||||
            int x, h;
 | 
			
		||||
            unsigned long x2;
 | 
			
		||||
            unsigned long offset = find_next_bit((unsigned long *) &vs->dirty,
 | 
			
		||||
                                                 height * VNC_DIRTY_BPL(vs),
 | 
			
		||||
                                                 y * VNC_DIRTY_BPL(vs));
 | 
			
		||||
            if (offset == height * VNC_DIRTY_BPL(vs)) {
 | 
			
		||||
                /* no more dirty bits */
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            y = offset / VNC_DIRTY_BPL(vs);
 | 
			
		||||
            x = offset % VNC_DIRTY_BPL(vs);
 | 
			
		||||
            x2 = find_next_zero_bit((unsigned long *) &vs->dirty[y],
 | 
			
		||||
                                    VNC_DIRTY_BPL(vs), x);
 | 
			
		||||
            bitmap_clear(vs->dirty[y], x, x2 - x);
 | 
			
		||||
            h = find_and_clear_dirty_height(vs, y, x, x2, height);
 | 
			
		||||
            n += vnc_job_add_rect(job, x * VNC_DIRTY_PIXELS_PER_BIT, y,
 | 
			
		||||
                                  (x2 - x) * VNC_DIRTY_PIXELS_PER_BIT, h);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        vnc_job_push(job);
 | 
			
		||||
| 
						 | 
				
			
			@ -940,8 +934,11 @@ static int vnc_update_client(VncState *vs, int has_dirty)
 | 
			
		|||
        return n;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (vs->csock == -1)
 | 
			
		||||
    if (vs->csock == -1) {
 | 
			
		||||
        vnc_disconnect_finish(vs);
 | 
			
		||||
    } else if (sync) {
 | 
			
		||||
        vnc_jobs_join(vs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1846,7 +1843,7 @@ static void framebuffer_update_request(VncState *vs, int incremental,
 | 
			
		|||
                                       int w, int h)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    const size_t width = surface_width(vs->vd->ds) / 16;
 | 
			
		||||
    const size_t width = surface_width(vs->vd->ds) / VNC_DIRTY_PIXELS_PER_BIT;
 | 
			
		||||
    const size_t height = surface_height(vs->vd->ds);
 | 
			
		||||
 | 
			
		||||
    if (y_position > height) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2548,7 +2545,9 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y)
 | 
			
		|||
 | 
			
		||||
        vs->lossy_rect[sty][stx] = 0;
 | 
			
		||||
        for (j = 0; j < VNC_STAT_RECT; ++j) {
 | 
			
		||||
            bitmap_set(vs->dirty[y + j], x / 16, VNC_STAT_RECT / 16);
 | 
			
		||||
            bitmap_set(vs->dirty[y + j],
 | 
			
		||||
                       x / VNC_DIRTY_PIXELS_PER_BIT,
 | 
			
		||||
                       VNC_STAT_RECT / VNC_DIRTY_PIXELS_PER_BIT);
 | 
			
		||||
        }
 | 
			
		||||
        has_dirty++;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -2652,8 +2651,8 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
 | 
			
		|||
    int width = pixman_image_get_width(vd->guest.fb);
 | 
			
		||||
    int height = pixman_image_get_height(vd->guest.fb);
 | 
			
		||||
    int y;
 | 
			
		||||
    uint8_t *guest_row;
 | 
			
		||||
    uint8_t *server_row;
 | 
			
		||||
    uint8_t *guest_row0 = NULL, *server_row0;
 | 
			
		||||
    int guest_stride = 0, server_stride;
 | 
			
		||||
    int cmp_bytes;
 | 
			
		||||
    VncState *vs;
 | 
			
		||||
    int has_dirty = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -2671,47 +2670,64 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
 | 
			
		|||
     * Check and copy modified bits from guest to server surface.
 | 
			
		||||
     * Update server dirty map.
 | 
			
		||||
     */
 | 
			
		||||
    cmp_bytes = 64;
 | 
			
		||||
    cmp_bytes = VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES;
 | 
			
		||||
    if (cmp_bytes > vnc_server_fb_stride(vd)) {
 | 
			
		||||
        cmp_bytes = vnc_server_fb_stride(vd);
 | 
			
		||||
    }
 | 
			
		||||
    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);
 | 
			
		||||
    }
 | 
			
		||||
    guest_row = (uint8_t *)pixman_image_get_data(vd->guest.fb);
 | 
			
		||||
    server_row = (uint8_t *)pixman_image_get_data(vd->server);
 | 
			
		||||
    for (y = 0; y < height; y++) {
 | 
			
		||||
        if (!bitmap_empty(vd->guest.dirty[y], VNC_DIRTY_BITS)) {
 | 
			
		||||
            int x;
 | 
			
		||||
            uint8_t *guest_ptr;
 | 
			
		||||
            uint8_t *server_ptr;
 | 
			
		||||
    server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
 | 
			
		||||
    server_stride = pixman_image_get_stride(vd->server);
 | 
			
		||||
 | 
			
		||||
            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_row;
 | 
			
		||||
            }
 | 
			
		||||
            server_ptr = server_row;
 | 
			
		||||
 | 
			
		||||
            for (x = 0; x + 15 < width;
 | 
			
		||||
                    x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
 | 
			
		||||
                if (!test_and_clear_bit((x / 16), vd->guest.dirty[y]))
 | 
			
		||||
                    continue;
 | 
			
		||||
                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, y, &tv);
 | 
			
		||||
                QTAILQ_FOREACH(vs, &vd->clients, next) {
 | 
			
		||||
                    set_bit((x / 16), vs->dirty[y]);
 | 
			
		||||
                }
 | 
			
		||||
                has_dirty++;
 | 
			
		||||
            }
 | 
			
		||||
    y = 0;
 | 
			
		||||
    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;
 | 
			
		||||
        }
 | 
			
		||||
        guest_row  += pixman_image_get_stride(vd->guest.fb);
 | 
			
		||||
        server_row += pixman_image_get_stride(vd->server);
 | 
			
		||||
        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) {
 | 
			
		||||
            if (!test_and_clear_bit(x, vd->guest.dirty[y])) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            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;
 | 
			
		||||
| 
						 | 
				
			
			@ -2734,7 +2750,7 @@ static void vnc_refresh(DisplayChangeListener *dcl)
 | 
			
		|||
    vnc_unlock_display(vd);
 | 
			
		||||
 | 
			
		||||
    QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
 | 
			
		||||
        rects += vnc_update_client(vs, has_dirty);
 | 
			
		||||
        rects += vnc_update_client(vs, has_dirty, false);
 | 
			
		||||
        /* vs might be free()ed here */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3134,7 +3150,9 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp)
 | 
			
		|||
            acl = 1;
 | 
			
		||||
#endif
 | 
			
		||||
        } else if (strncmp(options, "lossy", 5) == 0) {
 | 
			
		||||
#ifdef CONFIG_VNC_JPEG
 | 
			
		||||
            vs->lossy = true;
 | 
			
		||||
#endif
 | 
			
		||||
        } else if (strncmp(options, "non-adaptive", 12) == 0) {
 | 
			
		||||
            vs->non_adaptive = true;
 | 
			
		||||
        } else if (strncmp(options, "share=", 6) == 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3151,6 +3169,13 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp)
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* adaptive updates are only used with tight encoding and
 | 
			
		||||
     * if lossy updates are enabled so we can disable all the
 | 
			
		||||
     * calculations otherwise */
 | 
			
		||||
    if (!vs->lossy) {
 | 
			
		||||
        vs->non_adaptive = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_VNC_TLS
 | 
			
		||||
    if (acl && x509 && vs->tls.x509verify) {
 | 
			
		||||
        if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								ui/vnc.h
								
								
								
								
							
							
						
						
									
										10
									
								
								ui/vnc.h
								
								
								
								
							| 
						 | 
				
			
			@ -81,8 +81,16 @@ typedef void VncSendHextileTile(VncState *vs,
 | 
			
		|||
#define VNC_MAX_WIDTH 2560
 | 
			
		||||
#define VNC_MAX_HEIGHT 2048
 | 
			
		||||
 | 
			
		||||
/* VNC_DIRTY_PIXELS_PER_BIT is the number of dirty pixels represented
 | 
			
		||||
 * by one bit in the dirty bitmap */
 | 
			
		||||
#define VNC_DIRTY_PIXELS_PER_BIT 16
 | 
			
		||||
 | 
			
		||||
/* VNC_DIRTY_BITS is the number of bits in the dirty bitmap. */
 | 
			
		||||
#define VNC_DIRTY_BITS (VNC_MAX_WIDTH / 16)
 | 
			
		||||
#define VNC_DIRTY_BITS (VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT)
 | 
			
		||||
 | 
			
		||||
/* VNC_DIRTY_BPL (BPL = bits per line) might be greater than
 | 
			
		||||
 * VNC_DIRTY_BITS due to alignment */
 | 
			
		||||
#define VNC_DIRTY_BPL(x) (sizeof((x)->dirty) / VNC_MAX_HEIGHT * BITS_PER_BYTE)
 | 
			
		||||
 | 
			
		||||
#define VNC_STAT_RECT  64
 | 
			
		||||
#define VNC_STAT_COLS (VNC_MAX_WIDTH / VNC_STAT_RECT)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue