Commit 7eac3a87f132dd68139a6fe29b81c25c4c00e96d
1 parent
82b36dc3
vnc dynamic resolution (Stefano Stabellini)
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5229 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
177 additions
and
53 deletions
vnc.c
... | ... | @@ -71,8 +71,8 @@ typedef void VncWritePixels(VncState *vs, void *data, int size); |
71 | 71 | |
72 | 72 | typedef void VncSendHextileTile(VncState *vs, |
73 | 73 | int x, int y, int w, int h, |
74 | - uint32_t *last_bg, | |
75 | - uint32_t *last_fg, | |
74 | + void *last_bg, | |
75 | + void *last_fg, | |
76 | 76 | int *has_bg, int *has_fg); |
77 | 77 | |
78 | 78 | #define VNC_MAX_WIDTH 2048 |
... | ... | @@ -164,9 +164,9 @@ struct VncState |
164 | 164 | VncWritePixels *write_pixels; |
165 | 165 | VncSendHextileTile *send_hextile_tile; |
166 | 166 | int pix_bpp, pix_big_endian; |
167 | - int red_shift, red_max, red_shift1; | |
168 | - int green_shift, green_max, green_shift1; | |
169 | - int blue_shift, blue_max, blue_shift1; | |
167 | + int client_red_shift, client_red_max, server_red_shift, server_red_max; | |
168 | + int client_green_shift, client_green_max, server_green_shift, server_green_max; | |
169 | + int client_blue_shift, client_blue_max, server_blue_shift, server_blue_max; | |
170 | 170 | |
171 | 171 | VncReadEvent *read_handler; |
172 | 172 | size_t read_handler_expect; |
... | ... | @@ -208,6 +208,8 @@ static void vnc_flush(VncState *vs); |
208 | 208 | static void vnc_update_client(void *opaque); |
209 | 209 | static void vnc_client_read(void *opaque); |
210 | 210 | |
211 | +static void vnc_colordepth(DisplayState *ds, int depth); | |
212 | + | |
211 | 213 | static inline void vnc_set_bit(uint32_t *d, int k) |
212 | 214 | { |
213 | 215 | d[k >> 5] |= 1 << (k & 0x1f); |
... | ... | @@ -330,14 +332,17 @@ static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size) |
330 | 332 | /* slowest but generic code. */ |
331 | 333 | static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) |
332 | 334 | { |
333 | - unsigned int r, g, b; | |
334 | - | |
335 | - r = (v >> vs->red_shift1) & vs->red_max; | |
336 | - g = (v >> vs->green_shift1) & vs->green_max; | |
337 | - b = (v >> vs->blue_shift1) & vs->blue_max; | |
338 | - v = (r << vs->red_shift) | | |
339 | - (g << vs->green_shift) | | |
340 | - (b << vs->blue_shift); | |
335 | + uint8_t r, g, b; | |
336 | + | |
337 | + r = ((v >> vs->server_red_shift) & vs->server_red_max) * (vs->client_red_max + 1) / | |
338 | + (vs->server_red_max + 1); | |
339 | + g = ((v >> vs->server_green_shift) & vs->server_green_max) * (vs->client_green_max + 1) / | |
340 | + (vs->server_green_max + 1); | |
341 | + b = ((v >> vs->server_blue_shift) & vs->server_blue_max) * (vs->client_blue_max + 1) / | |
342 | + (vs->server_blue_max + 1); | |
343 | + v = (r << vs->client_red_shift) | | |
344 | + (g << vs->client_green_shift) | | |
345 | + (b << vs->client_blue_shift); | |
341 | 346 | switch(vs->pix_bpp) { |
342 | 347 | case 1: |
343 | 348 | buf[0] = v; |
... | ... | @@ -370,14 +375,34 @@ static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) |
370 | 375 | |
371 | 376 | static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size) |
372 | 377 | { |
373 | - uint32_t *pixels = pixels1; | |
374 | 378 | uint8_t buf[4]; |
375 | - int n, i; | |
376 | 379 | |
377 | - n = size >> 2; | |
378 | - for(i = 0; i < n; i++) { | |
379 | - vnc_convert_pixel(vs, buf, pixels[i]); | |
380 | - vnc_write(vs, buf, vs->pix_bpp); | |
380 | + if (vs->depth == 4) { | |
381 | + uint32_t *pixels = pixels1; | |
382 | + int n, i; | |
383 | + n = size >> 2; | |
384 | + for(i = 0; i < n; i++) { | |
385 | + vnc_convert_pixel(vs, buf, pixels[i]); | |
386 | + vnc_write(vs, buf, vs->pix_bpp); | |
387 | + } | |
388 | + } else if (vs->depth == 2) { | |
389 | + uint16_t *pixels = pixels1; | |
390 | + int n, i; | |
391 | + n = size >> 1; | |
392 | + for(i = 0; i < n; i++) { | |
393 | + vnc_convert_pixel(vs, buf, pixels[i]); | |
394 | + vnc_write(vs, buf, vs->pix_bpp); | |
395 | + } | |
396 | + } else if (vs->depth == 1) { | |
397 | + uint8_t *pixels = pixels1; | |
398 | + int n, i; | |
399 | + n = size; | |
400 | + for(i = 0; i < n; i++) { | |
401 | + vnc_convert_pixel(vs, buf, pixels[i]); | |
402 | + vnc_write(vs, buf, vs->pix_bpp); | |
403 | + } | |
404 | + } else { | |
405 | + fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n"); | |
381 | 406 | } |
382 | 407 | } |
383 | 408 | |
... | ... | @@ -414,6 +439,18 @@ static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h) |
414 | 439 | #undef BPP |
415 | 440 | |
416 | 441 | #define GENERIC |
442 | +#define BPP 8 | |
443 | +#include "vnchextile.h" | |
444 | +#undef BPP | |
445 | +#undef GENERIC | |
446 | + | |
447 | +#define GENERIC | |
448 | +#define BPP 16 | |
449 | +#include "vnchextile.h" | |
450 | +#undef BPP | |
451 | +#undef GENERIC | |
452 | + | |
453 | +#define GENERIC | |
417 | 454 | #define BPP 32 |
418 | 455 | #include "vnchextile.h" |
419 | 456 | #undef BPP |
... | ... | @@ -423,18 +460,23 @@ static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, i |
423 | 460 | { |
424 | 461 | int i, j; |
425 | 462 | int has_fg, has_bg; |
426 | - uint32_t last_fg32, last_bg32; | |
463 | + uint8_t *last_fg, *last_bg; | |
427 | 464 | |
428 | 465 | vnc_framebuffer_update(vs, x, y, w, h, 5); |
429 | 466 | |
467 | + last_fg = (uint8_t *) malloc(vs->depth); | |
468 | + last_bg = (uint8_t *) malloc(vs->depth); | |
430 | 469 | has_fg = has_bg = 0; |
431 | 470 | for (j = y; j < (y + h); j += 16) { |
432 | 471 | for (i = x; i < (x + w); i += 16) { |
433 | 472 | vs->send_hextile_tile(vs, i, j, |
434 | 473 | MIN(16, x + w - i), MIN(16, y + h - j), |
435 | - &last_bg32, &last_fg32, &has_bg, &has_fg); | |
474 | + last_bg, last_fg, &has_bg, &has_fg); | |
436 | 475 | } |
437 | 476 | } |
477 | + free(last_fg); | |
478 | + free(last_bg); | |
479 | + | |
438 | 480 | } |
439 | 481 | |
440 | 482 | static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) |
... | ... | @@ -1133,17 +1175,6 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) |
1133 | 1175 | check_pointer_type_change(vs, kbd_mouse_is_absolute()); |
1134 | 1176 | } |
1135 | 1177 | |
1136 | -static int compute_nbits(unsigned int val) | |
1137 | -{ | |
1138 | - int n; | |
1139 | - n = 0; | |
1140 | - while (val != 0) { | |
1141 | - n++; | |
1142 | - val >>= 1; | |
1143 | - } | |
1144 | - return n; | |
1145 | -} | |
1146 | - | |
1147 | 1178 | static void set_pixel_format(VncState *vs, |
1148 | 1179 | int bits_per_pixel, int depth, |
1149 | 1180 | int big_endian_flag, int true_color_flag, |
... | ... | @@ -1163,6 +1194,7 @@ static void set_pixel_format(VncState *vs, |
1163 | 1194 | return; |
1164 | 1195 | } |
1165 | 1196 | if (bits_per_pixel == 32 && |
1197 | + bits_per_pixel == vs->depth * 8 && | |
1166 | 1198 | host_big_endian_flag == big_endian_flag && |
1167 | 1199 | red_max == 0xff && green_max == 0xff && blue_max == 0xff && |
1168 | 1200 | red_shift == 16 && green_shift == 8 && blue_shift == 0) { |
... | ... | @@ -1171,6 +1203,7 @@ static void set_pixel_format(VncState *vs, |
1171 | 1203 | vs->send_hextile_tile = send_hextile_tile_32; |
1172 | 1204 | } else |
1173 | 1205 | if (bits_per_pixel == 16 && |
1206 | + bits_per_pixel == vs->depth * 8 && | |
1174 | 1207 | host_big_endian_flag == big_endian_flag && |
1175 | 1208 | red_max == 31 && green_max == 63 && blue_max == 31 && |
1176 | 1209 | red_shift == 11 && green_shift == 5 && blue_shift == 0) { |
... | ... | @@ -1179,6 +1212,7 @@ static void set_pixel_format(VncState *vs, |
1179 | 1212 | vs->send_hextile_tile = send_hextile_tile_16; |
1180 | 1213 | } else |
1181 | 1214 | if (bits_per_pixel == 8 && |
1215 | + bits_per_pixel == vs->depth * 8 && | |
1182 | 1216 | red_max == 7 && green_max == 7 && blue_max == 3 && |
1183 | 1217 | red_shift == 5 && green_shift == 2 && blue_shift == 0) { |
1184 | 1218 | vs->depth = 1; |
... | ... | @@ -1191,28 +1225,116 @@ static void set_pixel_format(VncState *vs, |
1191 | 1225 | bits_per_pixel != 16 && |
1192 | 1226 | bits_per_pixel != 32) |
1193 | 1227 | goto fail; |
1194 | - vs->depth = 4; | |
1195 | - vs->red_shift = red_shift; | |
1196 | - vs->red_max = red_max; | |
1197 | - vs->red_shift1 = 24 - compute_nbits(red_max); | |
1198 | - vs->green_shift = green_shift; | |
1199 | - vs->green_max = green_max; | |
1200 | - vs->green_shift1 = 16 - compute_nbits(green_max); | |
1201 | - vs->blue_shift = blue_shift; | |
1202 | - vs->blue_max = blue_max; | |
1203 | - vs->blue_shift1 = 8 - compute_nbits(blue_max); | |
1204 | - vs->pix_bpp = bits_per_pixel / 8; | |
1228 | + if (vs->depth == 4) { | |
1229 | + vs->send_hextile_tile = send_hextile_tile_generic_32; | |
1230 | + } else if (vs->depth == 2) { | |
1231 | + vs->send_hextile_tile = send_hextile_tile_generic_16; | |
1232 | + } else { | |
1233 | + vs->send_hextile_tile = send_hextile_tile_generic_8; | |
1234 | + } | |
1235 | + | |
1205 | 1236 | vs->pix_big_endian = big_endian_flag; |
1206 | 1237 | vs->write_pixels = vnc_write_pixels_generic; |
1207 | - vs->send_hextile_tile = send_hextile_tile_generic; | |
1208 | 1238 | } |
1209 | 1239 | |
1210 | - vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height); | |
1240 | + vs->client_red_shift = red_shift; | |
1241 | + vs->client_red_max = red_max; | |
1242 | + vs->client_green_shift = green_shift; | |
1243 | + vs->client_green_max = green_max; | |
1244 | + vs->client_blue_shift = blue_shift; | |
1245 | + vs->client_blue_max = blue_max; | |
1246 | + vs->pix_bpp = bits_per_pixel / 8; | |
1211 | 1247 | |
1212 | 1248 | vga_hw_invalidate(); |
1213 | 1249 | vga_hw_update(); |
1214 | 1250 | } |
1215 | 1251 | |
1252 | +static void vnc_colordepth(DisplayState *ds, int depth) | |
1253 | +{ | |
1254 | + int host_big_endian_flag; | |
1255 | + struct VncState *vs = ds->opaque; | |
1256 | + | |
1257 | + switch (depth) { | |
1258 | + case 24: | |
1259 | + if (ds->depth == 32) return; | |
1260 | + depth = 32; | |
1261 | + break; | |
1262 | + case 15: | |
1263 | + case 8: | |
1264 | + case 0: | |
1265 | + return; | |
1266 | + default: | |
1267 | + break; | |
1268 | + } | |
1269 | + | |
1270 | +#ifdef WORDS_BIGENDIAN | |
1271 | + host_big_endian_flag = 1; | |
1272 | +#else | |
1273 | + host_big_endian_flag = 0; | |
1274 | +#endif | |
1275 | + | |
1276 | + switch (depth) { | |
1277 | + case 8: | |
1278 | + vs->depth = depth / 8; | |
1279 | + vs->server_red_max = 7; | |
1280 | + vs->server_green_max = 7; | |
1281 | + vs->server_blue_max = 3; | |
1282 | + vs->server_red_shift = 5; | |
1283 | + vs->server_green_shift = 2; | |
1284 | + vs->server_blue_shift = 0; | |
1285 | + break; | |
1286 | + case 16: | |
1287 | + vs->depth = depth / 8; | |
1288 | + vs->server_red_max = 31; | |
1289 | + vs->server_green_max = 63; | |
1290 | + vs->server_blue_max = 31; | |
1291 | + vs->server_red_shift = 11; | |
1292 | + vs->server_green_shift = 5; | |
1293 | + vs->server_blue_shift = 0; | |
1294 | + break; | |
1295 | + case 32: | |
1296 | + vs->depth = 4; | |
1297 | + vs->server_red_max = 255; | |
1298 | + vs->server_green_max = 255; | |
1299 | + vs->server_blue_max = 255; | |
1300 | + vs->server_red_shift = 16; | |
1301 | + vs->server_green_shift = 8; | |
1302 | + vs->server_blue_shift = 0; | |
1303 | + break; | |
1304 | + default: | |
1305 | + return; | |
1306 | + } | |
1307 | + | |
1308 | + if (vs->pix_bpp == 4 && vs->depth == 4 && | |
1309 | + host_big_endian_flag == vs->pix_big_endian && | |
1310 | + vs->client_red_max == 0xff && vs->client_green_max == 0xff && vs->client_blue_max == 0xff && | |
1311 | + vs->client_red_shift == 16 && vs->client_green_shift == 8 && vs->client_blue_shift == 0) { | |
1312 | + vs->write_pixels = vnc_write_pixels_copy; | |
1313 | + vs->send_hextile_tile = send_hextile_tile_32; | |
1314 | + } else if (vs->pix_bpp == 2 && vs->depth == 2 && | |
1315 | + host_big_endian_flag == vs->pix_big_endian && | |
1316 | + vs->client_red_max == 31 && vs->client_green_max == 63 && vs->client_blue_max == 31 && | |
1317 | + vs->client_red_shift == 11 && vs->client_green_shift == 5 && vs->client_blue_shift == 0) { | |
1318 | + vs->write_pixels = vnc_write_pixels_copy; | |
1319 | + vs->send_hextile_tile = send_hextile_tile_16; | |
1320 | + } else if (vs->pix_bpp == 1 && vs->depth == 1 && | |
1321 | + host_big_endian_flag == vs->pix_big_endian && | |
1322 | + vs->client_red_max == 7 && vs->client_green_max == 7 && vs->client_blue_max == 3 && | |
1323 | + vs->client_red_shift == 5 && vs->client_green_shift == 2 && vs->client_blue_shift == 0) { | |
1324 | + vs->write_pixels = vnc_write_pixels_copy; | |
1325 | + vs->send_hextile_tile = send_hextile_tile_8; | |
1326 | + } else { | |
1327 | + if (vs->depth == 4) { | |
1328 | + vs->send_hextile_tile = send_hextile_tile_generic_32; | |
1329 | + } else if (vs->depth == 2) { | |
1330 | + vs->send_hextile_tile = send_hextile_tile_generic_16; | |
1331 | + } else { | |
1332 | + vs->send_hextile_tile = send_hextile_tile_generic_8; | |
1333 | + } | |
1334 | + vs->write_pixels = vnc_write_pixels_generic; | |
1335 | + } | |
1336 | +} | |
1337 | + | |
1216 | 1338 | static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) |
1217 | 1339 | { |
1218 | 1340 | int i; |
... | ... | @@ -1316,7 +1438,9 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) |
1316 | 1438 | vnc_write_u16(vs, vs->ds->height); |
1317 | 1439 | |
1318 | 1440 | vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */ |
1319 | - vnc_write_u8(vs, vs->depth * 8); /* depth */ | |
1441 | + if (vs->depth == 4) vnc_write_u8(vs, 24); /* depth */ | |
1442 | + else vnc_write_u8(vs, vs->depth * 8); /* depth */ | |
1443 | + | |
1320 | 1444 | #ifdef WORDS_BIGENDIAN |
1321 | 1445 | vnc_write_u8(vs, 1); /* big-endian-flag */ |
1322 | 1446 | #else |
... | ... | @@ -2006,7 +2130,6 @@ void vnc_display_init(DisplayState *ds) |
2006 | 2130 | |
2007 | 2131 | vs->lsock = -1; |
2008 | 2132 | vs->csock = -1; |
2009 | - vs->depth = 4; | |
2010 | 2133 | vs->last_x = -1; |
2011 | 2134 | vs->last_y = -1; |
2012 | 2135 | |
... | ... | @@ -2027,6 +2150,7 @@ void vnc_display_init(DisplayState *ds) |
2027 | 2150 | vs->ds->dpy_resize = vnc_dpy_resize; |
2028 | 2151 | vs->ds->dpy_refresh = NULL; |
2029 | 2152 | |
2153 | + vnc_colordepth(vs->ds, 32); | |
2030 | 2154 | vnc_dpy_resize(vs->ds, 640, 400); |
2031 | 2155 | } |
2032 | 2156 | ... | ... |
vnchextile.h
... | ... | @@ -2,29 +2,29 @@ |
2 | 2 | #define CONCAT(a, b) CONCAT_I(a, b) |
3 | 3 | #define pixel_t CONCAT(uint, CONCAT(BPP, _t)) |
4 | 4 | #ifdef GENERIC |
5 | -#define NAME generic | |
5 | +#define NAME CONCAT(generic_, BPP) | |
6 | 6 | #else |
7 | 7 | #define NAME BPP |
8 | 8 | #endif |
9 | 9 | |
10 | 10 | static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, |
11 | 11 | int x, int y, int w, int h, |
12 | - uint32_t *last_bg32, | |
13 | - uint32_t *last_fg32, | |
12 | + void *last_bg_, | |
13 | + void *last_fg_, | |
14 | 14 | int *has_bg, int *has_fg) |
15 | 15 | { |
16 | 16 | uint8_t *row = (vs->ds->data + y * vs->ds->linesize + x * vs->depth); |
17 | 17 | pixel_t *irow = (pixel_t *)row; |
18 | 18 | int j, i; |
19 | - pixel_t *last_bg = (pixel_t *)last_bg32; | |
20 | - pixel_t *last_fg = (pixel_t *)last_fg32; | |
19 | + pixel_t *last_bg = (pixel_t *)last_bg_; | |
20 | + pixel_t *last_fg = (pixel_t *)last_fg_; | |
21 | 21 | pixel_t bg = 0; |
22 | 22 | pixel_t fg = 0; |
23 | 23 | int n_colors = 0; |
24 | 24 | int bg_count = 0; |
25 | 25 | int fg_count = 0; |
26 | 26 | int flags = 0; |
27 | - uint8_t data[(sizeof(pixel_t) + 2) * 16 * 16]; | |
27 | + uint8_t data[(vs->pix_bpp + 2) * 16 * 16]; | |
28 | 28 | int n_data = 0; |
29 | 29 | int n_subtiles = 0; |
30 | 30 | ... | ... |