mirror of https://github.com/xemu-project/xemu.git
vnc: two bugfixes (by Peter Lieven).
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTspxDAAoJEEy22O7T6HE4OpMQAKiCe8mUPJWQvNKOHBMOe1Fu 8jEj9zaH65e+XoFKQsI86VgWSUPM8Iout/YcBJOslUjI5agIUwkAdd8w7wxUUBU9 OI0cBn0CzB3F0nAZc/CS8ZyqD0LZnx9ByVgM0XnbemNtg/bi3TvM4S0G0xBEMxtm eEv7eQ4PCAfipthz3gyAcBu2BZmokk8kbQwHWKZataBeV6Q2HRKjymxRc8D+eEBw zU001HYcpJmJ0yh+rVzx5o2yDscvCLjaFotSGZiDB6UqRhTS369EgF09PlN28m80 1/y7Q7Utqg6EboYIFSgRBWjaKW4A/TEugwZYlUM04zdvIfKkAuWDmxZCB/X/jH8d UVvPR2ANG59bZAV/00zE1cT8VBXzLXp5OudZ1/Ao8iSGKlm7t6SY8juUV7uYz89+ bQ4FqyMJNNcmn2UoxwdZhA7fF9RqGNcnPiDP2zvJu1AT8j4mf7ivnjuIfg3q0Z5m fs+nP6IOjChILsNSkVT0IOJamUraoE2hMqWKcKu5jz5ytJvlPniimQgil3U33fTZ d0BA3WbmIgcEGGzSIH/ZvZo20dEAc9FPhq0h1LdGiWMqRrRejcDH1MivkMpmxZCB umrg5qgYZbZnKfgzrc/BUN8ZEaLdmdVjoY5gW9Mpkw/QKQhnWZTb7U3+2CtkAanx uZzknIf/7736zdlHvzDt =ueTm -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/pull-vnc-20140701-1' into staging vnc: two bugfixes (by Peter Lieven). # gpg: Signature made Tue 01 Jul 2014 12:32:19 BST 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-20140701-1: ui/vnc: fix potential memory corruption issues ui/vnc: limit client_cut_text msg payload size Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
f9119a2572
162
ui/vnc.c
162
ui/vnc.c
|
@ -432,14 +432,10 @@ static void framebuffer_update_request(VncState *vs, int incremental,
|
||||||
static void vnc_refresh(DisplayChangeListener *dcl);
|
static void vnc_refresh(DisplayChangeListener *dcl);
|
||||||
static int vnc_refresh_server_surface(VncDisplay *vd);
|
static int vnc_refresh_server_surface(VncDisplay *vd);
|
||||||
|
|
||||||
static void vnc_dpy_update(DisplayChangeListener *dcl,
|
static void vnc_set_area_dirty(DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
|
||||||
int x, int y, int w, int h)
|
VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT),
|
||||||
{
|
int width, int height,
|
||||||
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
|
int x, int y, int w, int h) {
|
||||||
struct VncSurface *s = &vd->guest;
|
|
||||||
int width = surface_width(vd->ds);
|
|
||||||
int height = surface_height(vd->ds);
|
|
||||||
|
|
||||||
/* this is needed this to ensure we updated all affected
|
/* this is needed this to ensure we updated all affected
|
||||||
* blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */
|
* blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */
|
||||||
w += (x % VNC_DIRTY_PIXELS_PER_BIT);
|
w += (x % VNC_DIRTY_PIXELS_PER_BIT);
|
||||||
|
@ -451,11 +447,22 @@ static void vnc_dpy_update(DisplayChangeListener *dcl,
|
||||||
h = MIN(y + h, height);
|
h = MIN(y + h, height);
|
||||||
|
|
||||||
for (; y < h; y++) {
|
for (; y < h; y++) {
|
||||||
bitmap_set(s->dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
|
bitmap_set(dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT,
|
||||||
DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));
|
DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vnc_dpy_update(DisplayChangeListener *dcl,
|
||||||
|
int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
|
||||||
|
struct VncSurface *s = &vd->guest;
|
||||||
|
int width = pixman_image_get_width(vd->server);
|
||||||
|
int height = pixman_image_get_height(vd->server);
|
||||||
|
|
||||||
|
vnc_set_area_dirty(s->dirty, width, height, x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
|
void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
|
||||||
int32_t encoding)
|
int32_t encoding)
|
||||||
{
|
{
|
||||||
|
@ -517,17 +524,15 @@ void buffer_advance(Buffer *buf, size_t len)
|
||||||
|
|
||||||
static void vnc_desktop_resize(VncState *vs)
|
static void vnc_desktop_resize(VncState *vs)
|
||||||
{
|
{
|
||||||
DisplaySurface *ds = vs->vd->ds;
|
|
||||||
|
|
||||||
if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
|
if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (vs->client_width == surface_width(ds) &&
|
if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
|
||||||
vs->client_height == surface_height(ds)) {
|
vs->client_height == pixman_image_get_height(vs->vd->server)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vs->client_width = surface_width(ds);
|
vs->client_width = pixman_image_get_width(vs->vd->server);
|
||||||
vs->client_height = surface_height(ds);
|
vs->client_height = pixman_image_get_height(vs->vd->server);
|
||||||
vnc_lock_output(vs);
|
vnc_lock_output(vs);
|
||||||
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
|
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
|
||||||
vnc_write_u8(vs, 0);
|
vnc_write_u8(vs, 0);
|
||||||
|
@ -571,31 +576,24 @@ void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y)
|
||||||
ptr += x * VNC_SERVER_FB_BYTES;
|
ptr += x * VNC_SERVER_FB_BYTES;
|
||||||
return ptr;
|
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,
|
static void vnc_dpy_switch(DisplayChangeListener *dcl,
|
||||||
DisplaySurface *surface)
|
DisplaySurface *surface)
|
||||||
{
|
{
|
||||||
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
|
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
|
||||||
VncState *vs;
|
VncState *vs;
|
||||||
|
int width, height;
|
||||||
|
|
||||||
vnc_abort_display_jobs(vd);
|
vnc_abort_display_jobs(vd);
|
||||||
|
|
||||||
/* server surface */
|
/* server surface */
|
||||||
qemu_pixman_image_unref(vd->server);
|
qemu_pixman_image_unref(vd->server);
|
||||||
vd->ds = surface;
|
vd->ds = surface;
|
||||||
|
width = MIN(VNC_MAX_WIDTH, ROUND_UP(surface_width(vd->ds),
|
||||||
|
VNC_DIRTY_PIXELS_PER_BIT));
|
||||||
|
height = MIN(VNC_MAX_HEIGHT, surface_height(vd->ds));
|
||||||
vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
|
vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
|
||||||
surface_width(vd->ds),
|
width, height, NULL, 0);
|
||||||
surface_height(vd->ds),
|
|
||||||
NULL, 0);
|
|
||||||
|
|
||||||
/* guest surface */
|
/* guest surface */
|
||||||
#if 0 /* FIXME */
|
#if 0 /* FIXME */
|
||||||
|
@ -605,9 +603,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
|
||||||
qemu_pixman_image_unref(vd->guest.fb);
|
qemu_pixman_image_unref(vd->guest.fb);
|
||||||
vd->guest.fb = pixman_image_ref(surface->image);
|
vd->guest.fb = pixman_image_ref(surface->image);
|
||||||
vd->guest.format = surface->format;
|
vd->guest.format = surface->format;
|
||||||
VNC_SET_VISIBLE_PIXELS_DIRTY(vd->guest.dirty,
|
memset(vd->guest.dirty, 0x00, sizeof(vd->guest.dirty));
|
||||||
surface_width(vd->ds),
|
vnc_set_area_dirty(vd->guest.dirty, width, height, 0, 0,
|
||||||
surface_height(vd->ds));
|
width, height);
|
||||||
|
|
||||||
QTAILQ_FOREACH(vs, &vd->clients, next) {
|
QTAILQ_FOREACH(vs, &vd->clients, next) {
|
||||||
vnc_colordepth(vs);
|
vnc_colordepth(vs);
|
||||||
|
@ -615,9 +613,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
|
||||||
if (vs->vd->cursor) {
|
if (vs->vd->cursor) {
|
||||||
vnc_cursor_define(vs);
|
vnc_cursor_define(vs);
|
||||||
}
|
}
|
||||||
VNC_SET_VISIBLE_PIXELS_DIRTY(vs->dirty,
|
memset(vs->dirty, 0x00, sizeof(vs->dirty));
|
||||||
surface_width(vd->ds),
|
vnc_set_area_dirty(vs->dirty, width, height, 0, 0,
|
||||||
surface_height(vd->ds));
|
width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -911,8 +909,8 @@ static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
|
||||||
*/
|
*/
|
||||||
job = vnc_job_new(vs);
|
job = vnc_job_new(vs);
|
||||||
|
|
||||||
height = MIN(pixman_image_get_height(vd->server), vs->client_height);
|
height = pixman_image_get_height(vd->server);
|
||||||
width = MIN(pixman_image_get_width(vd->server), vs->client_width);
|
width = pixman_image_get_width(vd->server);
|
||||||
|
|
||||||
y = 0;
|
y = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -1501,8 +1499,8 @@ static void check_pointer_type_change(Notifier *notifier, void *data)
|
||||||
vnc_write_u8(vs, 0);
|
vnc_write_u8(vs, 0);
|
||||||
vnc_write_u16(vs, 1);
|
vnc_write_u16(vs, 1);
|
||||||
vnc_framebuffer_update(vs, absolute, 0,
|
vnc_framebuffer_update(vs, absolute, 0,
|
||||||
surface_width(vs->vd->ds),
|
pixman_image_get_width(vs->vd->server),
|
||||||
surface_height(vs->vd->ds),
|
pixman_image_get_height(vs->vd->server),
|
||||||
VNC_ENCODING_POINTER_TYPE_CHANGE);
|
VNC_ENCODING_POINTER_TYPE_CHANGE);
|
||||||
vnc_unlock_output(vs);
|
vnc_unlock_output(vs);
|
||||||
vnc_flush(vs);
|
vnc_flush(vs);
|
||||||
|
@ -1520,8 +1518,8 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
|
||||||
[INPUT_BUTTON_WHEEL_DOWN] = 0x10,
|
[INPUT_BUTTON_WHEEL_DOWN] = 0x10,
|
||||||
};
|
};
|
||||||
QemuConsole *con = vs->vd->dcl.con;
|
QemuConsole *con = vs->vd->dcl.con;
|
||||||
int width = surface_width(vs->vd->ds);
|
int width = pixman_image_get_width(vs->vd->server);
|
||||||
int height = surface_height(vs->vd->ds);
|
int height = pixman_image_get_height(vs->vd->server);
|
||||||
|
|
||||||
if (vs->last_bmask != button_mask) {
|
if (vs->last_bmask != button_mask) {
|
||||||
qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask);
|
qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask);
|
||||||
|
@ -1869,29 +1867,18 @@ static void ext_key_event(VncState *vs, int down,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void framebuffer_update_request(VncState *vs, int incremental,
|
static void framebuffer_update_request(VncState *vs, int incremental,
|
||||||
int x_position, int y_position,
|
int x, int y, int w, int h)
|
||||||
int w, int h)
|
|
||||||
{
|
{
|
||||||
int i;
|
int width = pixman_image_get_width(vs->vd->server);
|
||||||
const size_t width = surface_width(vs->vd->ds) / VNC_DIRTY_PIXELS_PER_BIT;
|
int height = pixman_image_get_height(vs->vd->server);
|
||||||
const size_t height = surface_height(vs->vd->ds);
|
|
||||||
|
|
||||||
if (y_position > height) {
|
|
||||||
y_position = height;
|
|
||||||
}
|
|
||||||
if (y_position + h >= height) {
|
|
||||||
h = height - y_position;
|
|
||||||
}
|
|
||||||
|
|
||||||
vs->need_update = 1;
|
vs->need_update = 1;
|
||||||
if (!incremental) {
|
|
||||||
vs->force_update = 1;
|
if (incremental) {
|
||||||
for (i = 0; i < h; i++) {
|
return;
|
||||||
bitmap_set(vs->dirty[y_position + i], 0, width);
|
|
||||||
bitmap_clear(vs->dirty[y_position + i], width,
|
|
||||||
VNC_DIRTY_BITS - width);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vnc_set_area_dirty(vs->dirty, width, height, x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_ext_key_event_ack(VncState *vs)
|
static void send_ext_key_event_ack(VncState *vs)
|
||||||
|
@ -1901,8 +1888,8 @@ static void send_ext_key_event_ack(VncState *vs)
|
||||||
vnc_write_u8(vs, 0);
|
vnc_write_u8(vs, 0);
|
||||||
vnc_write_u16(vs, 1);
|
vnc_write_u16(vs, 1);
|
||||||
vnc_framebuffer_update(vs, 0, 0,
|
vnc_framebuffer_update(vs, 0, 0,
|
||||||
surface_width(vs->vd->ds),
|
pixman_image_get_width(vs->vd->server),
|
||||||
surface_height(vs->vd->ds),
|
pixman_image_get_height(vs->vd->server),
|
||||||
VNC_ENCODING_EXT_KEY_EVENT);
|
VNC_ENCODING_EXT_KEY_EVENT);
|
||||||
vnc_unlock_output(vs);
|
vnc_unlock_output(vs);
|
||||||
vnc_flush(vs);
|
vnc_flush(vs);
|
||||||
|
@ -1915,8 +1902,8 @@ static void send_ext_audio_ack(VncState *vs)
|
||||||
vnc_write_u8(vs, 0);
|
vnc_write_u8(vs, 0);
|
||||||
vnc_write_u16(vs, 1);
|
vnc_write_u16(vs, 1);
|
||||||
vnc_framebuffer_update(vs, 0, 0,
|
vnc_framebuffer_update(vs, 0, 0,
|
||||||
surface_width(vs->vd->ds),
|
pixman_image_get_width(vs->vd->server),
|
||||||
surface_height(vs->vd->ds),
|
pixman_image_get_height(vs->vd->server),
|
||||||
VNC_ENCODING_AUDIO);
|
VNC_ENCODING_AUDIO);
|
||||||
vnc_unlock_output(vs);
|
vnc_unlock_output(vs);
|
||||||
vnc_flush(vs);
|
vnc_flush(vs);
|
||||||
|
@ -2094,8 +2081,8 @@ static void vnc_colordepth(VncState *vs)
|
||||||
vnc_write_u8(vs, 0);
|
vnc_write_u8(vs, 0);
|
||||||
vnc_write_u16(vs, 1); /* number of rects */
|
vnc_write_u16(vs, 1); /* number of rects */
|
||||||
vnc_framebuffer_update(vs, 0, 0,
|
vnc_framebuffer_update(vs, 0, 0,
|
||||||
surface_width(vs->vd->ds),
|
pixman_image_get_width(vs->vd->server),
|
||||||
surface_height(vs->vd->ds),
|
pixman_image_get_height(vs->vd->server),
|
||||||
VNC_ENCODING_WMVi);
|
VNC_ENCODING_WMVi);
|
||||||
pixel_format_message(vs);
|
pixel_format_message(vs);
|
||||||
vnc_unlock_output(vs);
|
vnc_unlock_output(vs);
|
||||||
|
@ -2165,13 +2152,20 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
|
||||||
pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
|
pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4));
|
||||||
break;
|
break;
|
||||||
case VNC_MSG_CLIENT_CUT_TEXT:
|
case VNC_MSG_CLIENT_CUT_TEXT:
|
||||||
if (len == 1)
|
if (len == 1) {
|
||||||
return 8;
|
return 8;
|
||||||
|
}
|
||||||
if (len == 8) {
|
if (len == 8) {
|
||||||
uint32_t dlen = read_u32(data, 4);
|
uint32_t dlen = read_u32(data, 4);
|
||||||
if (dlen > 0)
|
if (dlen > (1 << 20)) {
|
||||||
|
error_report("vnc: client_cut_text msg payload has %u bytes"
|
||||||
|
" which exceeds our limit of 1MB.", dlen);
|
||||||
|
vnc_client_error(vs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dlen > 0) {
|
||||||
return 8 + dlen;
|
return 8 + dlen;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client_cut_text(vs, read_u32(data, 4), data + 8);
|
client_cut_text(vs, read_u32(data, 4), data + 8);
|
||||||
|
@ -2310,8 +2304,8 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
|
||||||
}
|
}
|
||||||
vnc_set_share_mode(vs, mode);
|
vnc_set_share_mode(vs, mode);
|
||||||
|
|
||||||
vs->client_width = surface_width(vs->vd->ds);
|
vs->client_width = pixman_image_get_width(vs->vd->server);
|
||||||
vs->client_height = surface_height(vs->vd->ds);
|
vs->client_height = pixman_image_get_height(vs->vd->server);
|
||||||
vnc_write_u16(vs, vs->client_width);
|
vnc_write_u16(vs, vs->client_width);
|
||||||
vnc_write_u16(vs, vs->client_height);
|
vnc_write_u16(vs, vs->client_height);
|
||||||
|
|
||||||
|
@ -2678,12 +2672,12 @@ static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
|
||||||
|
|
||||||
static int vnc_refresh_server_surface(VncDisplay *vd)
|
static int vnc_refresh_server_surface(VncDisplay *vd)
|
||||||
{
|
{
|
||||||
int width = pixman_image_get_width(vd->guest.fb);
|
int width = MIN(pixman_image_get_width(vd->guest.fb),
|
||||||
int height = pixman_image_get_height(vd->guest.fb);
|
pixman_image_get_width(vd->server));
|
||||||
int y;
|
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;
|
uint8_t *guest_row0 = NULL, *server_row0;
|
||||||
int guest_stride = 0, server_stride;
|
|
||||||
int cmp_bytes;
|
|
||||||
VncState *vs;
|
VncState *vs;
|
||||||
int has_dirty = 0;
|
int has_dirty = 0;
|
||||||
pixman_image_t *tmpbuf = NULL;
|
pixman_image_t *tmpbuf = NULL;
|
||||||
|
@ -2700,10 +2694,10 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
|
||||||
* Check and copy modified bits from guest to server surface.
|
* Check and copy modified bits from guest to server surface.
|
||||||
* Update server dirty map.
|
* Update server dirty map.
|
||||||
*/
|
*/
|
||||||
cmp_bytes = VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES;
|
server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
|
||||||
if (cmp_bytes > vnc_server_fb_stride(vd)) {
|
server_stride = guest_stride = pixman_image_get_stride(vd->server);
|
||||||
cmp_bytes = vnc_server_fb_stride(vd);
|
cmp_bytes = MIN(VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES,
|
||||||
}
|
server_stride);
|
||||||
if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
|
if (vd->guest.format != VNC_SERVER_FB_FORMAT) {
|
||||||
int width = pixman_image_get_width(vd->server);
|
int width = pixman_image_get_width(vd->server);
|
||||||
tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width);
|
tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width);
|
||||||
|
@ -2711,10 +2705,8 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
|
||||||
guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb);
|
guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb);
|
||||||
guest_stride = pixman_image_get_stride(vd->guest.fb);
|
guest_stride = pixman_image_get_stride(vd->guest.fb);
|
||||||
}
|
}
|
||||||
server_row0 = (uint8_t *)pixman_image_get_data(vd->server);
|
min_stride = MIN(server_stride, guest_stride);
|
||||||
server_stride = pixman_image_get_stride(vd->server);
|
|
||||||
|
|
||||||
y = 0;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int x;
|
int x;
|
||||||
uint8_t *guest_ptr, *server_ptr;
|
uint8_t *guest_ptr, *server_ptr;
|
||||||
|
@ -2740,13 +2732,17 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
|
||||||
|
|
||||||
for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT);
|
for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT);
|
||||||
x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
|
x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) {
|
||||||
|
int _cmp_bytes = cmp_bytes;
|
||||||
if (!test_and_clear_bit(x, vd->guest.dirty[y])) {
|
if (!test_and_clear_bit(x, vd->guest.dirty[y])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0) {
|
if ((x + 1) * cmp_bytes > min_stride) {
|
||||||
|
_cmp_bytes = min_stride - x * cmp_bytes;
|
||||||
|
}
|
||||||
|
if (memcmp(server_ptr, guest_ptr, _cmp_bytes) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
memcpy(server_ptr, guest_ptr, cmp_bytes);
|
memcpy(server_ptr, guest_ptr, _cmp_bytes);
|
||||||
if (!vd->non_adaptive) {
|
if (!vd->non_adaptive) {
|
||||||
vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT,
|
vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT,
|
||||||
y, &tv);
|
y, &tv);
|
||||||
|
|
14
ui/vnc.h
14
ui/vnc.h
|
@ -77,14 +77,15 @@ typedef void VncSendHextileTile(VncState *vs,
|
||||||
void *last_fg,
|
void *last_fg,
|
||||||
int *has_bg, int *has_fg);
|
int *has_bg, int *has_fg);
|
||||||
|
|
||||||
/* VNC_MAX_WIDTH must be a multiple of 16. */
|
|
||||||
#define VNC_MAX_WIDTH 2560
|
|
||||||
#define VNC_MAX_HEIGHT 2048
|
|
||||||
|
|
||||||
/* VNC_DIRTY_PIXELS_PER_BIT is the number of dirty pixels represented
|
/* VNC_DIRTY_PIXELS_PER_BIT is the number of dirty pixels represented
|
||||||
* by one bit in the dirty bitmap */
|
* by one bit in the dirty bitmap, should be a power of 2 */
|
||||||
#define VNC_DIRTY_PIXELS_PER_BIT 16
|
#define VNC_DIRTY_PIXELS_PER_BIT 16
|
||||||
|
|
||||||
|
/* VNC_MAX_WIDTH must be a multiple of VNC_DIRTY_PIXELS_PER_BIT. */
|
||||||
|
|
||||||
|
#define VNC_MAX_WIDTH ROUND_UP(2560, VNC_DIRTY_PIXELS_PER_BIT)
|
||||||
|
#define VNC_MAX_HEIGHT 2048
|
||||||
|
|
||||||
/* VNC_DIRTY_BITS is the number of bits in the dirty bitmap. */
|
/* VNC_DIRTY_BITS is the number of bits in the dirty bitmap. */
|
||||||
#define VNC_DIRTY_BITS (VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT)
|
#define VNC_DIRTY_BITS (VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT)
|
||||||
|
|
||||||
|
@ -126,7 +127,8 @@ typedef struct VncRectStat VncRectStat;
|
||||||
struct VncSurface
|
struct VncSurface
|
||||||
{
|
{
|
||||||
struct timeval last_freq_check;
|
struct timeval last_freq_check;
|
||||||
DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_MAX_WIDTH / 16);
|
DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT],
|
||||||
|
VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT);
|
||||||
VncRectStat stats[VNC_STAT_ROWS][VNC_STAT_COLS];
|
VncRectStat stats[VNC_STAT_ROWS][VNC_STAT_COLS];
|
||||||
pixman_image_t *fb;
|
pixman_image_t *fb;
|
||||||
pixman_format_code_t format;
|
pixman_format_code_t format;
|
||||||
|
|
Loading…
Reference in New Issue