mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
9f64916da2
The vnc code uses *three* DisplaySurfaces: First is the surface of the actual QemuConsole, usually the guest screen, but could also be a text console (monitor/serial reachable via Ctrl-Alt-<nr> keys). This is left as-is. Second is the current server's view of the screen content. The vnc code uses this to figure which parts of the guest screen did _really_ change to reduce the amount of updates sent to the vnc clients. It is also used as data source when sending out the updates to the clients. This surface gets replaced by a pixman image. The format changes too, instead of using the guest screen format we'll use fixed 32bit rgb framebuffer and convert the pixels on the fly when comparing and updating the server framebuffer. Third surface carries the format expected by the vnc client. That isn't used to store image data. This surface is switched to PixelFormat and a boolean for bigendian byte order. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
211 lines
4.5 KiB
C
211 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)
|
|
{
|
|
VncDisplay *vd = vs->vd;
|
|
uint8_t *row = vnc_server_fb_ptr(vd, x, y);
|
|
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->client_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 += vnc_server_fb_stride(vd) / 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 (n_colors < 3 && (!*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 += vnc_server_fb_stride(vd) / 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->client_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->client_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 += vnc_server_fb_stride(vd) / 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. */
|
|
}
|
|
break;
|
|
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 * 4);
|
|
row += vnc_server_fb_stride(vd);
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef NAME
|
|
#undef pixel_t
|
|
#undef CONCAT_I
|
|
#undef CONCAT
|