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 | ... | ... |