mirror of
https://github.com/qemu/qemu.git
synced 2024-11-25 20:03:37 +08:00
6baebed769
This patch killes the old_data hack in the qemu server and replaces it with a clean separation of the guest-visible display surface and the vnc server display surface. Both guest and server surface have their own dirty bitmap for tracking screen updates. Workflow is this: (1) The guest writes to the guest surface. With shared buffers being active the guest writes are directly visible to the vnc server code. Note that this may happen in parallel to the vnc server code running (today only in xenfb, once we have vcpu threads in qemu also for other display adapters). (2) vnc_update() callback tags the specified area in the guest dirty map. (3) vnc_update_client() will first walk through the guest dirty map. It will compare guest and server surface for all regions tagged dirty and in case the screen content really did change the server surface and dirty map are updated. Note: old code used old_data in a simliar way, so this does *not* introduce an extra memcpy. (4) Then vnc_update_cient() will send the updates to the vnc client using the server surface and dirty map. Note: old code used the guest-visible surface instead, causing screen corruption in case of guest screen updates running in parallel. The separate dirty bitmap also has the nice effect that forced screen updates can be done cleanly by simply tagging the area in both guest and server dirty map. The old, hackish way was memset(old_data, 42, size) to trick the code checking for screen changes. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6860 c046a42c-6fe2-441c-8c8c-71466251a162
210 lines
4.5 KiB
C
210 lines
4.5 KiB
C
#define CONCAT_I(a, b) a ## b
|
|
#define CONCAT(a, b) CONCAT_I(a, b)
|
|
#define pixel_t CONCAT(uint, CONCAT(BPP, _t))
|
|
#ifdef GENERIC
|
|
#define NAME CONCAT(generic_, BPP)
|
|
#else
|
|
#define NAME BPP
|
|
#endif
|
|
|
|
static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
|
|
int x, int y, int w, int h,
|
|
void *last_bg_,
|
|
void *last_fg_,
|
|
int *has_bg, int *has_fg)
|
|
{
|
|
uint8_t *row = vs->server.ds->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds);
|
|
pixel_t *irow = (pixel_t *)row;
|
|
int j, i;
|
|
pixel_t *last_bg = (pixel_t *)last_bg_;
|
|
pixel_t *last_fg = (pixel_t *)last_fg_;
|
|
pixel_t bg = 0;
|
|
pixel_t fg = 0;
|
|
int n_colors = 0;
|
|
int bg_count = 0;
|
|
int fg_count = 0;
|
|
int flags = 0;
|
|
uint8_t data[(vs->clientds.pf.bytes_per_pixel + 2) * 16 * 16];
|
|
int n_data = 0;
|
|
int n_subtiles = 0;
|
|
|
|
for (j = 0; j < h; j++) {
|
|
for (i = 0; i < w; i++) {
|
|
switch (n_colors) {
|
|
case 0:
|
|
bg = irow[i];
|
|
n_colors = 1;
|
|
break;
|
|
case 1:
|
|
if (irow[i] != bg) {
|
|
fg = irow[i];
|
|
n_colors = 2;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (irow[i] != bg && irow[i] != fg) {
|
|
n_colors = 3;
|
|
} else {
|
|
if (irow[i] == bg)
|
|
bg_count++;
|
|
else if (irow[i] == fg)
|
|
fg_count++;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (n_colors > 2)
|
|
break;
|
|
irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
|
|
}
|
|
|
|
if (n_colors > 1 && fg_count > bg_count) {
|
|
pixel_t tmp = fg;
|
|
fg = bg;
|
|
bg = tmp;
|
|
}
|
|
|
|
if (!*has_bg || *last_bg != bg) {
|
|
flags |= 0x02;
|
|
*has_bg = 1;
|
|
*last_bg = bg;
|
|
}
|
|
|
|
if (!*has_fg || *last_fg != fg) {
|
|
flags |= 0x04;
|
|
*has_fg = 1;
|
|
*last_fg = fg;
|
|
}
|
|
|
|
switch (n_colors) {
|
|
case 1:
|
|
n_data = 0;
|
|
break;
|
|
case 2:
|
|
flags |= 0x08;
|
|
|
|
irow = (pixel_t *)row;
|
|
|
|
for (j = 0; j < h; j++) {
|
|
int min_x = -1;
|
|
for (i = 0; i < w; i++) {
|
|
if (irow[i] == fg) {
|
|
if (min_x == -1)
|
|
min_x = i;
|
|
} else if (min_x != -1) {
|
|
hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
|
|
n_data += 2;
|
|
n_subtiles++;
|
|
min_x = -1;
|
|
}
|
|
}
|
|
if (min_x != -1) {
|
|
hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
|
|
n_data += 2;
|
|
n_subtiles++;
|
|
}
|
|
irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
|
|
}
|
|
break;
|
|
case 3:
|
|
flags |= 0x18;
|
|
|
|
irow = (pixel_t *)row;
|
|
|
|
if (!*has_bg || *last_bg != bg)
|
|
flags |= 0x02;
|
|
|
|
for (j = 0; j < h; j++) {
|
|
int has_color = 0;
|
|
int min_x = -1;
|
|
pixel_t color = 0; /* shut up gcc */
|
|
|
|
for (i = 0; i < w; i++) {
|
|
if (!has_color) {
|
|
if (irow[i] == bg)
|
|
continue;
|
|
color = irow[i];
|
|
min_x = i;
|
|
has_color = 1;
|
|
} else if (irow[i] != color) {
|
|
has_color = 0;
|
|
#ifdef GENERIC
|
|
vnc_convert_pixel(vs, data + n_data, color);
|
|
n_data += vs->clientds.pf.bytes_per_pixel;
|
|
#else
|
|
memcpy(data + n_data, &color, sizeof(color));
|
|
n_data += sizeof(pixel_t);
|
|
#endif
|
|
hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
|
|
n_data += 2;
|
|
n_subtiles++;
|
|
|
|
min_x = -1;
|
|
if (irow[i] != bg) {
|
|
color = irow[i];
|
|
min_x = i;
|
|
has_color = 1;
|
|
}
|
|
}
|
|
}
|
|
if (has_color) {
|
|
#ifdef GENERIC
|
|
vnc_convert_pixel(vs, data + n_data, color);
|
|
n_data += vs->clientds.pf.bytes_per_pixel;
|
|
#else
|
|
memcpy(data + n_data, &color, sizeof(color));
|
|
n_data += sizeof(pixel_t);
|
|
#endif
|
|
hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
|
|
n_data += 2;
|
|
n_subtiles++;
|
|
}
|
|
irow += ds_get_linesize(vs->ds) / sizeof(pixel_t);
|
|
}
|
|
|
|
/* A SubrectsColoured subtile invalidates the foreground color */
|
|
*has_fg = 0;
|
|
if (n_data > (w * h * sizeof(pixel_t))) {
|
|
n_colors = 4;
|
|
flags = 0x01;
|
|
*has_bg = 0;
|
|
|
|
/* we really don't have to invalidate either the bg or fg
|
|
but we've lost the old values. oh well. */
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (n_colors > 3) {
|
|
flags = 0x01;
|
|
*has_fg = 0;
|
|
*has_bg = 0;
|
|
n_colors = 4;
|
|
}
|
|
|
|
vnc_write_u8(vs, flags);
|
|
if (n_colors < 4) {
|
|
if (flags & 0x02)
|
|
vs->write_pixels(vs, last_bg, sizeof(pixel_t));
|
|
if (flags & 0x04)
|
|
vs->write_pixels(vs, last_fg, sizeof(pixel_t));
|
|
if (n_subtiles) {
|
|
vnc_write_u8(vs, n_subtiles);
|
|
vnc_write(vs, data, n_data);
|
|
}
|
|
} else {
|
|
for (j = 0; j < h; j++) {
|
|
vs->write_pixels(vs, row, w * ds_get_bytes_per_pixel(vs->ds));
|
|
row += ds_get_linesize(vs->ds);
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef NAME
|
|
#undef pixel_t
|
|
#undef CONCAT_I
|
|
#undef CONCAT
|