1 /* 2 * QEMU VNC display driver: tight encoding 3 * 4 * From libvncserver/libvncserver/tight.c 5 * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. 6 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 7 * 8 * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com> 9 * 10 * Permission is hereby granted, free of charge, to any person obtaining a copy 11 * of this software and associated documentation files (the "Software"), to deal 12 * in the Software without restriction, including without limitation the rights 13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 * copies of the Software, and to permit persons to whom the Software is 15 * furnished to do so, subject to the following conditions: 16 * 17 * The above copyright notice and this permission notice shall be included in 18 * all copies or substantial portions of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 * THE SOFTWARE. 27 */ 28 29 #include "config-host.h" 30 31 #ifdef CONFIG_VNC_PNG 32 #include <png.h> 33 #endif 34 #ifdef CONFIG_VNC_JPEG 35 #include <stdio.h> 36 #include <jpeglib.h> 37 #endif 38 39 #include "qemu-common.h" 40 41 #include "bswap.h" 42 #include "qint.h" 43 #include "vnc.h" 44 #include "vnc-enc-tight.h" 45 #include "vnc-palette.h" 46 47 /* Compression level stuff. The following array contains various 48 encoder parameters for each of 10 compression levels (0..9). 49 Last three parameters correspond to JPEG quality levels (0..9). */ 50 51 static const struct { 52 int max_rect_size, max_rect_width; 53 int mono_min_rect_size, gradient_min_rect_size; 54 int idx_zlib_level, mono_zlib_level, raw_zlib_level, gradient_zlib_level; 55 int gradient_threshold, gradient_threshold24; 56 int idx_max_colors_divisor; 57 int jpeg_quality, jpeg_threshold, jpeg_threshold24; 58 } tight_conf[] = { 59 { 512, 32, 6, 65536, 0, 0, 0, 0, 0, 0, 4, 5, 10000, 23000 }, 60 { 2048, 128, 6, 65536, 1, 1, 1, 0, 0, 0, 8, 10, 8000, 18000 }, 61 { 6144, 256, 8, 65536, 3, 3, 2, 0, 0, 0, 24, 15, 6500, 15000 }, 62 { 10240, 1024, 12, 65536, 5, 5, 3, 0, 0, 0, 32, 25, 5000, 12000 }, 63 { 16384, 2048, 12, 65536, 6, 6, 4, 0, 0, 0, 32, 37, 4000, 10000 }, 64 { 32768, 2048, 12, 4096, 7, 7, 5, 4, 150, 380, 32, 50, 3000, 8000 }, 65 { 65536, 2048, 16, 4096, 7, 7, 6, 4, 170, 420, 48, 60, 2000, 5000 }, 66 { 65536, 2048, 16, 4096, 8, 8, 7, 5, 180, 450, 64, 70, 1000, 2500 }, 67 { 65536, 2048, 32, 8192, 9, 9, 8, 6, 190, 475, 64, 75, 500, 1200 }, 68 { 65536, 2048, 32, 8192, 9, 9, 9, 6, 200, 500, 96, 80, 200, 500 } 69 }; 70 71 72 static int tight_send_framebuffer_update(VncState *vs, int x, int y, 73 int w, int h); 74 75 #ifdef CONFIG_VNC_JPEG 76 static const struct { 77 double jpeg_freq_min; /* Don't send JPEG if the freq is bellow */ 78 double jpeg_freq_threshold; /* Always send JPEG if the freq is above */ 79 int jpeg_idx; /* Allow indexed JPEG */ 80 int jpeg_full; /* Allow full color JPEG */ 81 } tight_jpeg_conf[] = { 82 { 0, 8, 1, 1 }, 83 { 0, 8, 1, 1 }, 84 { 0, 8, 1, 1 }, 85 { 0, 8, 1, 1 }, 86 { 0, 10, 1, 1 }, 87 { 0.1, 10, 1, 1 }, 88 { 0.2, 10, 1, 1 }, 89 { 0.3, 12, 0, 0 }, 90 { 0.4, 14, 0, 0 }, 91 { 0.5, 16, 0, 0 }, 92 }; 93 #endif 94 95 #ifdef CONFIG_VNC_PNG 96 static const struct { 97 int png_zlib_level, png_filters; 98 } tight_png_conf[] = { 99 { 0, PNG_NO_FILTERS }, 100 { 1, PNG_NO_FILTERS }, 101 { 2, PNG_NO_FILTERS }, 102 { 3, PNG_NO_FILTERS }, 103 { 4, PNG_NO_FILTERS }, 104 { 5, PNG_ALL_FILTERS }, 105 { 6, PNG_ALL_FILTERS }, 106 { 7, PNG_ALL_FILTERS }, 107 { 8, PNG_ALL_FILTERS }, 108 { 9, PNG_ALL_FILTERS }, 109 }; 110 111 static int send_png_rect(VncState *vs, int x, int y, int w, int h, 112 VncPalette *palette); 113 114 static bool tight_can_send_png_rect(VncState *vs, int w, int h) 115 { 116 if (vs->tight.type != VNC_ENCODING_TIGHT_PNG) { 117 return false; 118 } 119 120 if (ds_get_bytes_per_pixel(vs->ds) == 1 || 121 vs->clientds.pf.bytes_per_pixel == 1) { 122 return false; 123 } 124 125 return true; 126 } 127 #endif 128 129 /* 130 * Code to guess if given rectangle is suitable for smooth image 131 * compression (by applying "gradient" filter or JPEG coder). 132 */ 133 134 static unsigned int 135 tight_detect_smooth_image24(VncState *vs, int w, int h) 136 { 137 int off; 138 int x, y, d, dx; 139 unsigned int c; 140 unsigned int stats[256]; 141 int pixels = 0; 142 int pix, left[3]; 143 unsigned int errors; 144 unsigned char *buf = vs->tight.tight.buffer; 145 146 /* 147 * If client is big-endian, color samples begin from the second 148 * byte (offset 1) of a 32-bit pixel value. 149 */ 150 off = !!(vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG); 151 152 memset(stats, 0, sizeof (stats)); 153 154 for (y = 0, x = 0; y < h && x < w;) { 155 for (d = 0; d < h - y && d < w - x - VNC_TIGHT_DETECT_SUBROW_WIDTH; 156 d++) { 157 for (c = 0; c < 3; c++) { 158 left[c] = buf[((y+d)*w+x+d)*4+off+c] & 0xFF; 159 } 160 for (dx = 1; dx <= VNC_TIGHT_DETECT_SUBROW_WIDTH; dx++) { 161 for (c = 0; c < 3; c++) { 162 pix = buf[((y+d)*w+x+d+dx)*4+off+c] & 0xFF; 163 stats[abs(pix - left[c])]++; 164 left[c] = pix; 165 } 166 pixels++; 167 } 168 } 169 if (w > h) { 170 x += h; 171 y = 0; 172 } else { 173 x = 0; 174 y += w; 175 } 176 } 177 178 /* 95% smooth or more ... */ 179 if (stats[0] * 33 / pixels >= 95) { 180 return 0; 181 } 182 183 errors = 0; 184 for (c = 1; c < 8; c++) { 185 errors += stats[c] * (c * c); 186 if (stats[c] == 0 || stats[c] > stats[c-1] * 2) { 187 return 0; 188 } 189 } 190 for (; c < 256; c++) { 191 errors += stats[c] * (c * c); 192 } 193 errors /= (pixels * 3 - stats[0]); 194 195 return errors; 196 } 197 198 #define DEFINE_DETECT_FUNCTION(bpp) \ 199 \ 200 static unsigned int \ 201 tight_detect_smooth_image##bpp(VncState *vs, int w, int h) { \ 202 bool endian; \ 203 uint##bpp##_t pix; \ 204 int max[3], shift[3]; \ 205 int x, y, d, dx; \ 206 unsigned int c; \ 207 unsigned int stats[256]; \ 208 int pixels = 0; \ 209 int sample, sum, left[3]; \ 210 unsigned int errors; \ 211 unsigned char *buf = vs->tight.tight.buffer; \ 212 \ 213 endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) != \ 214 (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)); \ 215 \ 216 \ 217 max[0] = vs->clientds.pf.rmax; \ 218 max[1] = vs->clientds.pf.gmax; \ 219 max[2] = vs->clientds.pf.bmax; \ 220 shift[0] = vs->clientds.pf.rshift; \ 221 shift[1] = vs->clientds.pf.gshift; \ 222 shift[2] = vs->clientds.pf.bshift; \ 223 \ 224 memset(stats, 0, sizeof(stats)); \ 225 \ 226 y = 0, x = 0; \ 227 while (y < h && x < w) { \ 228 for (d = 0; d < h - y && \ 229 d < w - x - VNC_TIGHT_DETECT_SUBROW_WIDTH; d++) { \ 230 pix = ((uint##bpp##_t *)buf)[(y+d)*w+x+d]; \ 231 if (endian) { \ 232 pix = bswap##bpp(pix); \ 233 } \ 234 for (c = 0; c < 3; c++) { \ 235 left[c] = (int)(pix >> shift[c] & max[c]); \ 236 } \ 237 for (dx = 1; dx <= VNC_TIGHT_DETECT_SUBROW_WIDTH; \ 238 dx++) { \ 239 pix = ((uint##bpp##_t *)buf)[(y+d)*w+x+d+dx]; \ 240 if (endian) { \ 241 pix = bswap##bpp(pix); \ 242 } \ 243 sum = 0; \ 244 for (c = 0; c < 3; c++) { \ 245 sample = (int)(pix >> shift[c] & max[c]); \ 246 sum += abs(sample - left[c]); \ 247 left[c] = sample; \ 248 } \ 249 if (sum > 255) { \ 250 sum = 255; \ 251 } \ 252 stats[sum]++; \ 253 pixels++; \ 254 } \ 255 } \ 256 if (w > h) { \ 257 x += h; \ 258 y = 0; \ 259 } else { \ 260 x = 0; \ 261 y += w; \ 262 } \ 263 } \ 264 \ 265 if ((stats[0] + stats[1]) * 100 / pixels >= 90) { \ 266 return 0; \ 267 } \ 268 \ 269 errors = 0; \ 270 for (c = 1; c < 8; c++) { \ 271 errors += stats[c] * (c * c); \ 272 if (stats[c] == 0 || stats[c] > stats[c-1] * 2) { \ 273 return 0; \ 274 } \ 275 } \ 276 for (; c < 256; c++) { \ 277 errors += stats[c] * (c * c); \ 278 } \ 279 errors /= (pixels - stats[0]); \ 280 \ 281 return errors; \ 282 } 283 284 DEFINE_DETECT_FUNCTION(16) 285 DEFINE_DETECT_FUNCTION(32) 286 287 static int 288 tight_detect_smooth_image(VncState *vs, int w, int h) 289 { 290 unsigned int errors; 291 int compression = vs->tight.compression; 292 int quality = vs->tight.quality; 293 294 if (!vs->vd->lossy) { 295 return 0; 296 } 297 298 if (ds_get_bytes_per_pixel(vs->ds) == 1 || 299 vs->clientds.pf.bytes_per_pixel == 1 || 300 w < VNC_TIGHT_DETECT_MIN_WIDTH || h < VNC_TIGHT_DETECT_MIN_HEIGHT) { 301 return 0; 302 } 303 304 if (vs->tight.quality != (uint8_t)-1) { 305 if (w * h < VNC_TIGHT_JPEG_MIN_RECT_SIZE) { 306 return 0; 307 } 308 } else { 309 if (w * h < tight_conf[compression].gradient_min_rect_size) { 310 return 0; 311 } 312 } 313 314 if (vs->clientds.pf.bytes_per_pixel == 4) { 315 if (vs->tight.pixel24) { 316 errors = tight_detect_smooth_image24(vs, w, h); 317 if (vs->tight.quality != (uint8_t)-1) { 318 return (errors < tight_conf[quality].jpeg_threshold24); 319 } 320 return (errors < tight_conf[compression].gradient_threshold24); 321 } else { 322 errors = tight_detect_smooth_image32(vs, w, h); 323 } 324 } else { 325 errors = tight_detect_smooth_image16(vs, w, h); 326 } 327 if (quality != -1) { 328 return (errors < tight_conf[quality].jpeg_threshold); 329 } 330 return (errors < tight_conf[compression].gradient_threshold); 331 } 332 333 /* 334 * Code to determine how many different colors used in rectangle. 335 */ 336 #define DEFINE_FILL_PALETTE_FUNCTION(bpp) \ 337 \ 338 static int \ 339 tight_fill_palette##bpp(VncState *vs, int x, int y, \ 340 int max, size_t count, \ 341 uint32_t *bg, uint32_t *fg, \ 342 VncPalette **palette) { \ 343 uint##bpp##_t *data; \ 344 uint##bpp##_t c0, c1, ci; \ 345 int i, n0, n1; \ 346 \ 347 data = (uint##bpp##_t *)vs->tight.tight.buffer; \ 348 \ 349 c0 = data[0]; \ 350 i = 1; \ 351 while (i < count && data[i] == c0) \ 352 i++; \ 353 if (i >= count) { \ 354 *bg = *fg = c0; \ 355 return 1; \ 356 } \ 357 \ 358 if (max < 2) { \ 359 return 0; \ 360 } \ 361 \ 362 n0 = i; \ 363 c1 = data[i]; \ 364 n1 = 0; \ 365 for (i++; i < count; i++) { \ 366 ci = data[i]; \ 367 if (ci == c0) { \ 368 n0++; \ 369 } else if (ci == c1) { \ 370 n1++; \ 371 } else \ 372 break; \ 373 } \ 374 if (i >= count) { \ 375 if (n0 > n1) { \ 376 *bg = (uint32_t)c0; \ 377 *fg = (uint32_t)c1; \ 378 } else { \ 379 *bg = (uint32_t)c1; \ 380 *fg = (uint32_t)c0; \ 381 } \ 382 return 2; \ 383 } \ 384 \ 385 if (max == 2) { \ 386 return 0; \ 387 } \ 388 \ 389 *palette = palette_new(max, bpp); \ 390 palette_put(*palette, c0); \ 391 palette_put(*palette, c1); \ 392 palette_put(*palette, ci); \ 393 \ 394 for (i++; i < count; i++) { \ 395 if (data[i] == ci) { \ 396 continue; \ 397 } else { \ 398 ci = data[i]; \ 399 if (!palette_put(*palette, (uint32_t)ci)) { \ 400 return 0; \ 401 } \ 402 } \ 403 } \ 404 \ 405 return palette_size(*palette); \ 406 } 407 408 DEFINE_FILL_PALETTE_FUNCTION(8) 409 DEFINE_FILL_PALETTE_FUNCTION(16) 410 DEFINE_FILL_PALETTE_FUNCTION(32) 411 412 static int tight_fill_palette(VncState *vs, int x, int y, 413 size_t count, uint32_t *bg, uint32_t *fg, 414 VncPalette **palette) 415 { 416 int max; 417 418 max = count / tight_conf[vs->tight.compression].idx_max_colors_divisor; 419 if (max < 2 && 420 count >= tight_conf[vs->tight.compression].mono_min_rect_size) { 421 max = 2; 422 } 423 if (max >= 256) { 424 max = 256; 425 } 426 427 switch(vs->clientds.pf.bytes_per_pixel) { 428 case 4: 429 return tight_fill_palette32(vs, x, y, max, count, bg, fg, palette); 430 case 2: 431 return tight_fill_palette16(vs, x, y, max, count, bg, fg, palette); 432 default: 433 max = 2; 434 return tight_fill_palette8(vs, x, y, max, count, bg, fg, palette); 435 } 436 return 0; 437 } 438 439 /* 440 * Converting truecolor samples into palette indices. 441 */ 442 #define DEFINE_IDX_ENCODE_FUNCTION(bpp) \ 443 \ 444 static void \ 445 tight_encode_indexed_rect##bpp(uint8_t *buf, int count, \ 446 VncPalette *palette) { \ 447 uint##bpp##_t *src; \ 448 uint##bpp##_t rgb; \ 449 int i, rep; \ 450 uint8_t idx; \ 451 \ 452 src = (uint##bpp##_t *) buf; \ 453 \ 454 for (i = 0; i < count; i++) { \ 455 \ 456 rgb = *src++; \ 457 rep = 0; \ 458 while (i < count && *src == rgb) { \ 459 rep++, src++, i++; \ 460 } \ 461 idx = palette_idx(palette, rgb); \ 462 /* \ 463 * Should never happen, but don't break everything \ 464 * if it does, use the first color instead \ 465 */ \ 466 if (idx == (uint8_t)-1) { \ 467 idx = 0; \ 468 } \ 469 while (rep >= 0) { \ 470 *buf++ = idx; \ 471 rep--; \ 472 } \ 473 } \ 474 } 475 476 DEFINE_IDX_ENCODE_FUNCTION(16) 477 DEFINE_IDX_ENCODE_FUNCTION(32) 478 479 #define DEFINE_MONO_ENCODE_FUNCTION(bpp) \ 480 \ 481 static void \ 482 tight_encode_mono_rect##bpp(uint8_t *buf, int w, int h, \ 483 uint##bpp##_t bg, uint##bpp##_t fg) { \ 484 uint##bpp##_t *ptr; \ 485 unsigned int value, mask; \ 486 int aligned_width; \ 487 int x, y, bg_bits; \ 488 \ 489 ptr = (uint##bpp##_t *) buf; \ 490 aligned_width = w - w % 8; \ 491 \ 492 for (y = 0; y < h; y++) { \ 493 for (x = 0; x < aligned_width; x += 8) { \ 494 for (bg_bits = 0; bg_bits < 8; bg_bits++) { \ 495 if (*ptr++ != bg) { \ 496 break; \ 497 } \ 498 } \ 499 if (bg_bits == 8) { \ 500 *buf++ = 0; \ 501 continue; \ 502 } \ 503 mask = 0x80 >> bg_bits; \ 504 value = mask; \ 505 for (bg_bits++; bg_bits < 8; bg_bits++) { \ 506 mask >>= 1; \ 507 if (*ptr++ != bg) { \ 508 value |= mask; \ 509 } \ 510 } \ 511 *buf++ = (uint8_t)value; \ 512 } \ 513 \ 514 mask = 0x80; \ 515 value = 0; \ 516 if (x >= w) { \ 517 continue; \ 518 } \ 519 \ 520 for (; x < w; x++) { \ 521 if (*ptr++ != bg) { \ 522 value |= mask; \ 523 } \ 524 mask >>= 1; \ 525 } \ 526 *buf++ = (uint8_t)value; \ 527 } \ 528 } 529 530 DEFINE_MONO_ENCODE_FUNCTION(8) 531 DEFINE_MONO_ENCODE_FUNCTION(16) 532 DEFINE_MONO_ENCODE_FUNCTION(32) 533 534 /* 535 * ``Gradient'' filter for 24-bit color samples. 536 * Should be called only when redMax, greenMax and blueMax are 255. 537 * Color components assumed to be byte-aligned. 538 */ 539 540 static void 541 tight_filter_gradient24(VncState *vs, uint8_t *buf, int w, int h) 542 { 543 uint32_t *buf32; 544 uint32_t pix32; 545 int shift[3]; 546 int *prev; 547 int here[3], upper[3], left[3], upperleft[3]; 548 int prediction; 549 int x, y, c; 550 551 buf32 = (uint32_t *)buf; 552 memset(vs->tight.gradient.buffer, 0, w * 3 * sizeof(int)); 553 554 if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) == 555 (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) { 556 shift[0] = vs->clientds.pf.rshift; 557 shift[1] = vs->clientds.pf.gshift; 558 shift[2] = vs->clientds.pf.bshift; 559 } else { 560 shift[0] = 24 - vs->clientds.pf.rshift; 561 shift[1] = 24 - vs->clientds.pf.gshift; 562 shift[2] = 24 - vs->clientds.pf.bshift; 563 } 564 565 for (y = 0; y < h; y++) { 566 for (c = 0; c < 3; c++) { 567 upper[c] = 0; 568 here[c] = 0; 569 } 570 prev = (int *)vs->tight.gradient.buffer; 571 for (x = 0; x < w; x++) { 572 pix32 = *buf32++; 573 for (c = 0; c < 3; c++) { 574 upperleft[c] = upper[c]; 575 left[c] = here[c]; 576 upper[c] = *prev; 577 here[c] = (int)(pix32 >> shift[c] & 0xFF); 578 *prev++ = here[c]; 579 580 prediction = left[c] + upper[c] - upperleft[c]; 581 if (prediction < 0) { 582 prediction = 0; 583 } else if (prediction > 0xFF) { 584 prediction = 0xFF; 585 } 586 *buf++ = (char)(here[c] - prediction); 587 } 588 } 589 } 590 } 591 592 593 /* 594 * ``Gradient'' filter for other color depths. 595 */ 596 597 #define DEFINE_GRADIENT_FILTER_FUNCTION(bpp) \ 598 \ 599 static void \ 600 tight_filter_gradient##bpp(VncState *vs, uint##bpp##_t *buf, \ 601 int w, int h) { \ 602 uint##bpp##_t pix, diff; \ 603 bool endian; \ 604 int *prev; \ 605 int max[3], shift[3]; \ 606 int here[3], upper[3], left[3], upperleft[3]; \ 607 int prediction; \ 608 int x, y, c; \ 609 \ 610 memset (vs->tight.gradient.buffer, 0, w * 3 * sizeof(int)); \ 611 \ 612 endian = ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) != \ 613 (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)); \ 614 \ 615 max[0] = vs->clientds.pf.rmax; \ 616 max[1] = vs->clientds.pf.gmax; \ 617 max[2] = vs->clientds.pf.bmax; \ 618 shift[0] = vs->clientds.pf.rshift; \ 619 shift[1] = vs->clientds.pf.gshift; \ 620 shift[2] = vs->clientds.pf.bshift; \ 621 \ 622 for (y = 0; y < h; y++) { \ 623 for (c = 0; c < 3; c++) { \ 624 upper[c] = 0; \ 625 here[c] = 0; \ 626 } \ 627 prev = (int *)vs->tight.gradient.buffer; \ 628 for (x = 0; x < w; x++) { \ 629 pix = *buf; \ 630 if (endian) { \ 631 pix = bswap##bpp(pix); \ 632 } \ 633 diff = 0; \ 634 for (c = 0; c < 3; c++) { \ 635 upperleft[c] = upper[c]; \ 636 left[c] = here[c]; \ 637 upper[c] = *prev; \ 638 here[c] = (int)(pix >> shift[c] & max[c]); \ 639 *prev++ = here[c]; \ 640 \ 641 prediction = left[c] + upper[c] - upperleft[c]; \ 642 if (prediction < 0) { \ 643 prediction = 0; \ 644 } else if (prediction > max[c]) { \ 645 prediction = max[c]; \ 646 } \ 647 diff |= ((here[c] - prediction) & max[c]) \ 648 << shift[c]; \ 649 } \ 650 if (endian) { \ 651 diff = bswap##bpp(diff); \ 652 } \ 653 *buf++ = diff; \ 654 } \ 655 } \ 656 } 657 658 DEFINE_GRADIENT_FILTER_FUNCTION(16) 659 DEFINE_GRADIENT_FILTER_FUNCTION(32) 660 661 /* 662 * Check if a rectangle is all of the same color. If needSameColor is 663 * set to non-zero, then also check that its color equals to the 664 * *colorPtr value. The result is 1 if the test is successful, and in 665 * that case new color will be stored in *colorPtr. 666 */ 667 668 #define DEFINE_CHECK_SOLID_FUNCTION(bpp) \ 669 \ 670 static bool \ 671 check_solid_tile##bpp(VncState *vs, int x, int y, int w, int h, \ 672 uint32_t* color, bool samecolor) \ 673 { \ 674 VncDisplay *vd = vs->vd; \ 675 uint##bpp##_t *fbptr; \ 676 uint##bpp##_t c; \ 677 int dx, dy; \ 678 \ 679 fbptr = (uint##bpp##_t *) \ 680 (vd->server->data + y * ds_get_linesize(vs->ds) + \ 681 x * ds_get_bytes_per_pixel(vs->ds)); \ 682 \ 683 c = *fbptr; \ 684 if (samecolor && (uint32_t)c != *color) { \ 685 return false; \ 686 } \ 687 \ 688 for (dy = 0; dy < h; dy++) { \ 689 for (dx = 0; dx < w; dx++) { \ 690 if (c != fbptr[dx]) { \ 691 return false; \ 692 } \ 693 } \ 694 fbptr = (uint##bpp##_t *) \ 695 ((uint8_t *)fbptr + ds_get_linesize(vs->ds)); \ 696 } \ 697 \ 698 *color = (uint32_t)c; \ 699 return true; \ 700 } 701 702 DEFINE_CHECK_SOLID_FUNCTION(32) 703 DEFINE_CHECK_SOLID_FUNCTION(16) 704 DEFINE_CHECK_SOLID_FUNCTION(8) 705 706 static bool check_solid_tile(VncState *vs, int x, int y, int w, int h, 707 uint32_t* color, bool samecolor) 708 { 709 VncDisplay *vd = vs->vd; 710 711 switch(vd->server->pf.bytes_per_pixel) { 712 case 4: 713 return check_solid_tile32(vs, x, y, w, h, color, samecolor); 714 case 2: 715 return check_solid_tile16(vs, x, y, w, h, color, samecolor); 716 default: 717 return check_solid_tile8(vs, x, y, w, h, color, samecolor); 718 } 719 } 720 721 static void find_best_solid_area(VncState *vs, int x, int y, int w, int h, 722 uint32_t color, int *w_ptr, int *h_ptr) 723 { 724 int dx, dy, dw, dh; 725 int w_prev; 726 int w_best = 0, h_best = 0; 727 728 w_prev = w; 729 730 for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) { 731 732 dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, y + h - dy); 733 dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, w_prev); 734 735 if (!check_solid_tile(vs, x, dy, dw, dh, &color, true)) { 736 break; 737 } 738 739 for (dx = x + dw; dx < x + w_prev;) { 740 dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, x + w_prev - dx); 741 742 if (!check_solid_tile(vs, dx, dy, dw, dh, &color, true)) { 743 break; 744 } 745 dx += dw; 746 } 747 748 w_prev = dx - x; 749 if (w_prev * (dy + dh - y) > w_best * h_best) { 750 w_best = w_prev; 751 h_best = dy + dh - y; 752 } 753 } 754 755 *w_ptr = w_best; 756 *h_ptr = h_best; 757 } 758 759 static void extend_solid_area(VncState *vs, int x, int y, int w, int h, 760 uint32_t color, int *x_ptr, int *y_ptr, 761 int *w_ptr, int *h_ptr) 762 { 763 int cx, cy; 764 765 /* Try to extend the area upwards. */ 766 for ( cy = *y_ptr - 1; 767 cy >= y && check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true); 768 cy-- ); 769 *h_ptr += *y_ptr - (cy + 1); 770 *y_ptr = cy + 1; 771 772 /* ... downwards. */ 773 for ( cy = *y_ptr + *h_ptr; 774 cy < y + h && 775 check_solid_tile(vs, *x_ptr, cy, *w_ptr, 1, &color, true); 776 cy++ ); 777 *h_ptr += cy - (*y_ptr + *h_ptr); 778 779 /* ... to the left. */ 780 for ( cx = *x_ptr - 1; 781 cx >= x && check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true); 782 cx-- ); 783 *w_ptr += *x_ptr - (cx + 1); 784 *x_ptr = cx + 1; 785 786 /* ... to the right. */ 787 for ( cx = *x_ptr + *w_ptr; 788 cx < x + w && 789 check_solid_tile(vs, cx, *y_ptr, 1, *h_ptr, &color, true); 790 cx++ ); 791 *w_ptr += cx - (*x_ptr + *w_ptr); 792 } 793 794 static int tight_init_stream(VncState *vs, int stream_id, 795 int level, int strategy) 796 { 797 z_streamp zstream = &vs->tight.stream[stream_id]; 798 799 if (zstream->opaque == NULL) { 800 int err; 801 802 VNC_DEBUG("VNC: TIGHT: initializing zlib stream %d\n", stream_id); 803 VNC_DEBUG("VNC: TIGHT: opaque = %p | vs = %p\n", zstream->opaque, vs); 804 zstream->zalloc = vnc_zlib_zalloc; 805 zstream->zfree = vnc_zlib_zfree; 806 807 err = deflateInit2(zstream, level, Z_DEFLATED, MAX_WBITS, 808 MAX_MEM_LEVEL, strategy); 809 810 if (err != Z_OK) { 811 fprintf(stderr, "VNC: error initializing zlib\n"); 812 return -1; 813 } 814 815 vs->tight.levels[stream_id] = level; 816 zstream->opaque = vs; 817 } 818 819 if (vs->tight.levels[stream_id] != level) { 820 if (deflateParams(zstream, level, strategy) != Z_OK) { 821 return -1; 822 } 823 vs->tight.levels[stream_id] = level; 824 } 825 return 0; 826 } 827 828 static void tight_send_compact_size(VncState *vs, size_t len) 829 { 830 int lpc = 0; 831 int bytes = 0; 832 char buf[3] = {0, 0, 0}; 833 834 buf[bytes++] = len & 0x7F; 835 if (len > 0x7F) { 836 buf[bytes-1] |= 0x80; 837 buf[bytes++] = (len >> 7) & 0x7F; 838 if (len > 0x3FFF) { 839 buf[bytes-1] |= 0x80; 840 buf[bytes++] = (len >> 14) & 0xFF; 841 } 842 } 843 for (lpc = 0; lpc < bytes; lpc++) { 844 vnc_write_u8(vs, buf[lpc]); 845 } 846 } 847 848 static int tight_compress_data(VncState *vs, int stream_id, size_t bytes, 849 int level, int strategy) 850 { 851 z_streamp zstream = &vs->tight.stream[stream_id]; 852 int previous_out; 853 854 if (bytes < VNC_TIGHT_MIN_TO_COMPRESS) { 855 vnc_write(vs, vs->tight.tight.buffer, vs->tight.tight.offset); 856 return bytes; 857 } 858 859 if (tight_init_stream(vs, stream_id, level, strategy)) { 860 return -1; 861 } 862 863 /* reserve memory in output buffer */ 864 buffer_reserve(&vs->tight.zlib, bytes + 64); 865 866 /* set pointers */ 867 zstream->next_in = vs->tight.tight.buffer; 868 zstream->avail_in = vs->tight.tight.offset; 869 zstream->next_out = vs->tight.zlib.buffer + vs->tight.zlib.offset; 870 zstream->avail_out = vs->tight.zlib.capacity - vs->tight.zlib.offset; 871 previous_out = zstream->avail_out; 872 zstream->data_type = Z_BINARY; 873 874 /* start encoding */ 875 if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) { 876 fprintf(stderr, "VNC: error during tight compression\n"); 877 return -1; 878 } 879 880 vs->tight.zlib.offset = vs->tight.zlib.capacity - zstream->avail_out; 881 /* ...how much data has actually been produced by deflate() */ 882 bytes = previous_out - zstream->avail_out; 883 884 tight_send_compact_size(vs, bytes); 885 vnc_write(vs, vs->tight.zlib.buffer, bytes); 886 887 buffer_reset(&vs->tight.zlib); 888 889 return bytes; 890 } 891 892 /* 893 * Subencoding implementations. 894 */ 895 static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret) 896 { 897 uint32_t *buf32; 898 uint32_t pix; 899 int rshift, gshift, bshift; 900 901 buf32 = (uint32_t *)buf; 902 903 if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) == 904 (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG)) { 905 rshift = vs->clientds.pf.rshift; 906 gshift = vs->clientds.pf.gshift; 907 bshift = vs->clientds.pf.bshift; 908 } else { 909 rshift = 24 - vs->clientds.pf.rshift; 910 gshift = 24 - vs->clientds.pf.gshift; 911 bshift = 24 - vs->clientds.pf.bshift; 912 } 913 914 if (ret) { 915 *ret = count * 3; 916 } 917 918 while (count--) { 919 pix = *buf32++; 920 *buf++ = (char)(pix >> rshift); 921 *buf++ = (char)(pix >> gshift); 922 *buf++ = (char)(pix >> bshift); 923 } 924 } 925 926 static int send_full_color_rect(VncState *vs, int x, int y, int w, int h) 927 { 928 int stream = 0; 929 ssize_t bytes; 930 931 #ifdef CONFIG_VNC_PNG 932 if (tight_can_send_png_rect(vs, w, h)) { 933 return send_png_rect(vs, x, y, w, h, NULL); 934 } 935 #endif 936 937 vnc_write_u8(vs, stream << 4); /* no flushing, no filter */ 938 939 if (vs->tight.pixel24) { 940 tight_pack24(vs, vs->tight.tight.buffer, w * h, &vs->tight.tight.offset); 941 bytes = 3; 942 } else { 943 bytes = vs->clientds.pf.bytes_per_pixel; 944 } 945 946 bytes = tight_compress_data(vs, stream, w * h * bytes, 947 tight_conf[vs->tight.compression].raw_zlib_level, 948 Z_DEFAULT_STRATEGY); 949 950 return (bytes >= 0); 951 } 952 953 static int send_solid_rect(VncState *vs) 954 { 955 size_t bytes; 956 957 vnc_write_u8(vs, VNC_TIGHT_FILL << 4); /* no flushing, no filter */ 958 959 if (vs->tight.pixel24) { 960 tight_pack24(vs, vs->tight.tight.buffer, 1, &vs->tight.tight.offset); 961 bytes = 3; 962 } else { 963 bytes = vs->clientds.pf.bytes_per_pixel; 964 } 965 966 vnc_write(vs, vs->tight.tight.buffer, bytes); 967 return 1; 968 } 969 970 static int send_mono_rect(VncState *vs, int x, int y, 971 int w, int h, uint32_t bg, uint32_t fg) 972 { 973 ssize_t bytes; 974 int stream = 1; 975 int level = tight_conf[vs->tight.compression].mono_zlib_level; 976 977 #ifdef CONFIG_VNC_PNG 978 if (tight_can_send_png_rect(vs, w, h)) { 979 int ret; 980 int bpp = vs->clientds.pf.bytes_per_pixel * 8; 981 VncPalette *palette = palette_new(2, bpp); 982 983 palette_put(palette, bg); 984 palette_put(palette, fg); 985 ret = send_png_rect(vs, x, y, w, h, palette); 986 palette_destroy(palette); 987 return ret; 988 } 989 #endif 990 991 bytes = ((w + 7) / 8) * h; 992 993 vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4); 994 vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE); 995 vnc_write_u8(vs, 1); 996 997 switch(vs->clientds.pf.bytes_per_pixel) { 998 case 4: 999 { 1000 uint32_t buf[2] = {bg, fg}; 1001 size_t ret = sizeof (buf); 1002 1003 if (vs->tight.pixel24) { 1004 tight_pack24(vs, (unsigned char*)buf, 2, &ret); 1005 } 1006 vnc_write(vs, buf, ret); 1007 1008 tight_encode_mono_rect32(vs->tight.tight.buffer, w, h, bg, fg); 1009 break; 1010 } 1011 case 2: 1012 vnc_write(vs, &bg, 2); 1013 vnc_write(vs, &fg, 2); 1014 tight_encode_mono_rect16(vs->tight.tight.buffer, w, h, bg, fg); 1015 break; 1016 default: 1017 vnc_write_u8(vs, bg); 1018 vnc_write_u8(vs, fg); 1019 tight_encode_mono_rect8(vs->tight.tight.buffer, w, h, bg, fg); 1020 break; 1021 } 1022 vs->tight.tight.offset = bytes; 1023 1024 bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY); 1025 return (bytes >= 0); 1026 } 1027 1028 struct palette_cb_priv { 1029 VncState *vs; 1030 uint8_t *header; 1031 #ifdef CONFIG_VNC_PNG 1032 png_colorp png_palette; 1033 #endif 1034 }; 1035 1036 static void write_palette(int idx, uint32_t color, void *opaque) 1037 { 1038 struct palette_cb_priv *priv = opaque; 1039 VncState *vs = priv->vs; 1040 uint32_t bytes = vs->clientds.pf.bytes_per_pixel; 1041 1042 if (bytes == 4) { 1043 ((uint32_t*)priv->header)[idx] = color; 1044 } else { 1045 ((uint16_t*)priv->header)[idx] = color; 1046 } 1047 } 1048 1049 static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h) 1050 { 1051 int stream = 3; 1052 int level = tight_conf[vs->tight.compression].gradient_zlib_level; 1053 ssize_t bytes; 1054 1055 if (vs->clientds.pf.bytes_per_pixel == 1) 1056 return send_full_color_rect(vs, x, y, w, h); 1057 1058 vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4); 1059 vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT); 1060 1061 buffer_reserve(&vs->tight.gradient, w * 3 * sizeof (int)); 1062 1063 if (vs->tight.pixel24) { 1064 tight_filter_gradient24(vs, vs->tight.tight.buffer, w, h); 1065 bytes = 3; 1066 } else if (vs->clientds.pf.bytes_per_pixel == 4) { 1067 tight_filter_gradient32(vs, (uint32_t *)vs->tight.tight.buffer, w, h); 1068 bytes = 4; 1069 } else { 1070 tight_filter_gradient16(vs, (uint16_t *)vs->tight.tight.buffer, w, h); 1071 bytes = 2; 1072 } 1073 1074 buffer_reset(&vs->tight.gradient); 1075 1076 bytes = w * h * bytes; 1077 vs->tight.tight.offset = bytes; 1078 1079 bytes = tight_compress_data(vs, stream, bytes, 1080 level, Z_FILTERED); 1081 return (bytes >= 0); 1082 } 1083 1084 static int send_palette_rect(VncState *vs, int x, int y, 1085 int w, int h, VncPalette *palette) 1086 { 1087 int stream = 2; 1088 int level = tight_conf[vs->tight.compression].idx_zlib_level; 1089 int colors; 1090 ssize_t bytes; 1091 1092 #ifdef CONFIG_VNC_PNG 1093 if (tight_can_send_png_rect(vs, w, h)) { 1094 return send_png_rect(vs, x, y, w, h, palette); 1095 } 1096 #endif 1097 1098 colors = palette_size(palette); 1099 1100 vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4); 1101 vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE); 1102 vnc_write_u8(vs, colors - 1); 1103 1104 switch(vs->clientds.pf.bytes_per_pixel) { 1105 case 4: 1106 { 1107 size_t old_offset, offset; 1108 uint32_t header[palette_size(palette)]; 1109 struct palette_cb_priv priv = { vs, (uint8_t *)header }; 1110 1111 old_offset = vs->output.offset; 1112 palette_iter(palette, write_palette, &priv); 1113 vnc_write(vs, header, sizeof(header)); 1114 1115 if (vs->tight.pixel24) { 1116 tight_pack24(vs, vs->output.buffer + old_offset, colors, &offset); 1117 vs->output.offset = old_offset + offset; 1118 } 1119 1120 tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette); 1121 break; 1122 } 1123 case 2: 1124 { 1125 uint16_t header[palette_size(palette)]; 1126 struct palette_cb_priv priv = { vs, (uint8_t *)header }; 1127 1128 palette_iter(palette, write_palette, &priv); 1129 vnc_write(vs, header, sizeof(header)); 1130 tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette); 1131 break; 1132 } 1133 default: 1134 return -1; /* No palette for 8bits colors */ 1135 break; 1136 } 1137 bytes = w * h; 1138 vs->tight.tight.offset = bytes; 1139 1140 bytes = tight_compress_data(vs, stream, bytes, 1141 level, Z_DEFAULT_STRATEGY); 1142 return (bytes >= 0); 1143 } 1144 1145 #if defined(CONFIG_VNC_JPEG) || defined(CONFIG_VNC_PNG) 1146 static void rgb_prepare_row24(VncState *vs, uint8_t *dst, int x, int y, 1147 int count) 1148 { 1149 VncDisplay *vd = vs->vd; 1150 uint32_t *fbptr; 1151 uint32_t pix; 1152 1153 fbptr = (uint32_t *)(vd->server->data + y * ds_get_linesize(vs->ds) + 1154 x * ds_get_bytes_per_pixel(vs->ds)); 1155 1156 while (count--) { 1157 pix = *fbptr++; 1158 *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.rshift); 1159 *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.gshift); 1160 *dst++ = (uint8_t)(pix >> vs->ds->surface->pf.bshift); 1161 } 1162 } 1163 1164 #define DEFINE_RGB_GET_ROW_FUNCTION(bpp) \ 1165 \ 1166 static void \ 1167 rgb_prepare_row##bpp(VncState *vs, uint8_t *dst, \ 1168 int x, int y, int count) \ 1169 { \ 1170 VncDisplay *vd = vs->vd; \ 1171 uint##bpp##_t *fbptr; \ 1172 uint##bpp##_t pix; \ 1173 int r, g, b; \ 1174 \ 1175 fbptr = (uint##bpp##_t *) \ 1176 (vd->server->data + y * ds_get_linesize(vs->ds) + \ 1177 x * ds_get_bytes_per_pixel(vs->ds)); \ 1178 \ 1179 while (count--) { \ 1180 pix = *fbptr++; \ 1181 \ 1182 r = (int)((pix >> vs->ds->surface->pf.rshift) \ 1183 & vs->ds->surface->pf.rmax); \ 1184 g = (int)((pix >> vs->ds->surface->pf.gshift) \ 1185 & vs->ds->surface->pf.gmax); \ 1186 b = (int)((pix >> vs->ds->surface->pf.bshift) \ 1187 & vs->ds->surface->pf.bmax); \ 1188 \ 1189 *dst++ = (uint8_t)((r * 255 + vs->ds->surface->pf.rmax / 2) \ 1190 / vs->ds->surface->pf.rmax); \ 1191 *dst++ = (uint8_t)((g * 255 + vs->ds->surface->pf.gmax / 2) \ 1192 / vs->ds->surface->pf.gmax); \ 1193 *dst++ = (uint8_t)((b * 255 + vs->ds->surface->pf.bmax / 2) \ 1194 / vs->ds->surface->pf.bmax); \ 1195 } \ 1196 } 1197 1198 DEFINE_RGB_GET_ROW_FUNCTION(16) 1199 DEFINE_RGB_GET_ROW_FUNCTION(32) 1200 1201 static void rgb_prepare_row(VncState *vs, uint8_t *dst, int x, int y, 1202 int count) 1203 { 1204 if (ds_get_bytes_per_pixel(vs->ds) == 4) { 1205 if (vs->ds->surface->pf.rmax == 0xFF && 1206 vs->ds->surface->pf.gmax == 0xFF && 1207 vs->ds->surface->pf.bmax == 0xFF) { 1208 rgb_prepare_row24(vs, dst, x, y, count); 1209 } else { 1210 rgb_prepare_row32(vs, dst, x, y, count); 1211 } 1212 } else { 1213 rgb_prepare_row16(vs, dst, x, y, count); 1214 } 1215 } 1216 #endif /* CONFIG_VNC_JPEG or CONFIG_VNC_PNG */ 1217 1218 /* 1219 * JPEG compression stuff. 1220 */ 1221 #ifdef CONFIG_VNC_JPEG 1222 /* 1223 * Destination manager implementation for JPEG library. 1224 */ 1225 1226 /* This is called once per encoding */ 1227 static void jpeg_init_destination(j_compress_ptr cinfo) 1228 { 1229 VncState *vs = cinfo->client_data; 1230 Buffer *buffer = &vs->tight.jpeg; 1231 1232 cinfo->dest->next_output_byte = (JOCTET *)buffer->buffer + buffer->offset; 1233 cinfo->dest->free_in_buffer = (size_t)(buffer->capacity - buffer->offset); 1234 } 1235 1236 /* This is called when we ran out of buffer (shouldn't happen!) */ 1237 static boolean jpeg_empty_output_buffer(j_compress_ptr cinfo) 1238 { 1239 VncState *vs = cinfo->client_data; 1240 Buffer *buffer = &vs->tight.jpeg; 1241 1242 buffer->offset = buffer->capacity; 1243 buffer_reserve(buffer, 2048); 1244 jpeg_init_destination(cinfo); 1245 return TRUE; 1246 } 1247 1248 /* This is called when we are done processing data */ 1249 static void jpeg_term_destination(j_compress_ptr cinfo) 1250 { 1251 VncState *vs = cinfo->client_data; 1252 Buffer *buffer = &vs->tight.jpeg; 1253 1254 buffer->offset = buffer->capacity - cinfo->dest->free_in_buffer; 1255 } 1256 1257 static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality) 1258 { 1259 struct jpeg_compress_struct cinfo; 1260 struct jpeg_error_mgr jerr; 1261 struct jpeg_destination_mgr manager; 1262 JSAMPROW row[1]; 1263 uint8_t *buf; 1264 int dy; 1265 1266 if (ds_get_bytes_per_pixel(vs->ds) == 1) 1267 return send_full_color_rect(vs, x, y, w, h); 1268 1269 buffer_reserve(&vs->tight.jpeg, 2048); 1270 1271 cinfo.err = jpeg_std_error(&jerr); 1272 jpeg_create_compress(&cinfo); 1273 1274 cinfo.client_data = vs; 1275 cinfo.image_width = w; 1276 cinfo.image_height = h; 1277 cinfo.input_components = 3; 1278 cinfo.in_color_space = JCS_RGB; 1279 1280 jpeg_set_defaults(&cinfo); 1281 jpeg_set_quality(&cinfo, quality, true); 1282 1283 manager.init_destination = jpeg_init_destination; 1284 manager.empty_output_buffer = jpeg_empty_output_buffer; 1285 manager.term_destination = jpeg_term_destination; 1286 cinfo.dest = &manager; 1287 1288 jpeg_start_compress(&cinfo, true); 1289 1290 buf = qemu_malloc(w * 3); 1291 row[0] = buf; 1292 for (dy = 0; dy < h; dy++) { 1293 rgb_prepare_row(vs, buf, x, y + dy, w); 1294 jpeg_write_scanlines(&cinfo, row, 1); 1295 } 1296 qemu_free(buf); 1297 1298 jpeg_finish_compress(&cinfo); 1299 jpeg_destroy_compress(&cinfo); 1300 1301 vnc_write_u8(vs, VNC_TIGHT_JPEG << 4); 1302 1303 tight_send_compact_size(vs, vs->tight.jpeg.offset); 1304 vnc_write(vs, vs->tight.jpeg.buffer, vs->tight.jpeg.offset); 1305 buffer_reset(&vs->tight.jpeg); 1306 1307 return 1; 1308 } 1309 #endif /* CONFIG_VNC_JPEG */ 1310 1311 /* 1312 * PNG compression stuff. 1313 */ 1314 #ifdef CONFIG_VNC_PNG 1315 static void write_png_palette(int idx, uint32_t pix, void *opaque) 1316 { 1317 struct palette_cb_priv *priv = opaque; 1318 VncState *vs = priv->vs; 1319 png_colorp color = &priv->png_palette[idx]; 1320 1321 if (vs->tight.pixel24) 1322 { 1323 color->red = (pix >> vs->clientds.pf.rshift) & vs->clientds.pf.rmax; 1324 color->green = (pix >> vs->clientds.pf.gshift) & vs->clientds.pf.gmax; 1325 color->blue = (pix >> vs->clientds.pf.bshift) & vs->clientds.pf.bmax; 1326 } 1327 else 1328 { 1329 int red, green, blue; 1330 1331 red = (pix >> vs->clientds.pf.rshift) & vs->clientds.pf.rmax; 1332 green = (pix >> vs->clientds.pf.gshift) & vs->clientds.pf.gmax; 1333 blue = (pix >> vs->clientds.pf.bshift) & vs->clientds.pf.bmax; 1334 color->red = ((red * 255 + vs->clientds.pf.rmax / 2) / 1335 vs->clientds.pf.rmax); 1336 color->green = ((green * 255 + vs->clientds.pf.gmax / 2) / 1337 vs->clientds.pf.gmax); 1338 color->blue = ((blue * 255 + vs->clientds.pf.bmax / 2) / 1339 vs->clientds.pf.bmax); 1340 } 1341 } 1342 1343 static void png_write_data(png_structp png_ptr, png_bytep data, 1344 png_size_t length) 1345 { 1346 VncState *vs = png_get_io_ptr(png_ptr); 1347 1348 buffer_reserve(&vs->tight.png, vs->tight.png.offset + length); 1349 memcpy(vs->tight.png.buffer + vs->tight.png.offset, data, length); 1350 1351 vs->tight.png.offset += length; 1352 } 1353 1354 static void png_flush_data(png_structp png_ptr) 1355 { 1356 } 1357 1358 static void *vnc_png_malloc(png_structp png_ptr, png_size_t size) 1359 { 1360 return qemu_malloc(size); 1361 } 1362 1363 static void vnc_png_free(png_structp png_ptr, png_voidp ptr) 1364 { 1365 qemu_free(ptr); 1366 } 1367 1368 static int send_png_rect(VncState *vs, int x, int y, int w, int h, 1369 VncPalette *palette) 1370 { 1371 png_byte color_type; 1372 png_structp png_ptr; 1373 png_infop info_ptr; 1374 png_colorp png_palette = NULL; 1375 int level = tight_png_conf[vs->tight.compression].png_zlib_level; 1376 int filters = tight_png_conf[vs->tight.compression].png_filters; 1377 uint8_t *buf; 1378 int dy; 1379 1380 png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, 1381 NULL, vnc_png_malloc, vnc_png_free); 1382 1383 if (png_ptr == NULL) 1384 return -1; 1385 1386 info_ptr = png_create_info_struct(png_ptr); 1387 1388 if (info_ptr == NULL) { 1389 png_destroy_write_struct(&png_ptr, NULL); 1390 return -1; 1391 } 1392 1393 png_set_write_fn(png_ptr, (void *) vs, png_write_data, png_flush_data); 1394 png_set_compression_level(png_ptr, level); 1395 png_set_filter(png_ptr, PNG_FILTER_TYPE_DEFAULT, filters); 1396 1397 if (palette) { 1398 color_type = PNG_COLOR_TYPE_PALETTE; 1399 } else { 1400 color_type = PNG_COLOR_TYPE_RGB; 1401 } 1402 1403 png_set_IHDR(png_ptr, info_ptr, w, h, 1404 8, color_type, PNG_INTERLACE_NONE, 1405 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 1406 1407 if (color_type == PNG_COLOR_TYPE_PALETTE) { 1408 struct palette_cb_priv priv; 1409 1410 png_palette = png_malloc(png_ptr, sizeof(*png_palette) * 1411 palette_size(palette)); 1412 1413 priv.vs = vs; 1414 priv.png_palette = png_palette; 1415 palette_iter(palette, write_png_palette, &priv); 1416 1417 png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette)); 1418 1419 if (vs->clientds.pf.bytes_per_pixel == 4) { 1420 tight_encode_indexed_rect32(vs->tight.tight.buffer, w * h, palette); 1421 } else { 1422 tight_encode_indexed_rect16(vs->tight.tight.buffer, w * h, palette); 1423 } 1424 } 1425 1426 png_write_info(png_ptr, info_ptr); 1427 1428 buffer_reserve(&vs->tight.png, 2048); 1429 buf = qemu_malloc(w * 3); 1430 for (dy = 0; dy < h; dy++) 1431 { 1432 if (color_type == PNG_COLOR_TYPE_PALETTE) { 1433 memcpy(buf, vs->tight.tight.buffer + (dy * w), w); 1434 } else { 1435 rgb_prepare_row(vs, buf, x, y + dy, w); 1436 } 1437 png_write_row(png_ptr, buf); 1438 } 1439 qemu_free(buf); 1440 1441 png_write_end(png_ptr, NULL); 1442 1443 if (color_type == PNG_COLOR_TYPE_PALETTE) { 1444 png_free(png_ptr, png_palette); 1445 } 1446 1447 png_destroy_write_struct(&png_ptr, &info_ptr); 1448 1449 vnc_write_u8(vs, VNC_TIGHT_PNG << 4); 1450 1451 tight_send_compact_size(vs, vs->tight.png.offset); 1452 vnc_write(vs, vs->tight.png.buffer, vs->tight.png.offset); 1453 buffer_reset(&vs->tight.png); 1454 return 1; 1455 } 1456 #endif /* CONFIG_VNC_PNG */ 1457 1458 static void vnc_tight_start(VncState *vs) 1459 { 1460 buffer_reset(&vs->tight.tight); 1461 1462 // make the output buffer be the zlib buffer, so we can compress it later 1463 vs->tight.tmp = vs->output; 1464 vs->output = vs->tight.tight; 1465 } 1466 1467 static void vnc_tight_stop(VncState *vs) 1468 { 1469 // switch back to normal output/zlib buffers 1470 vs->tight.tight = vs->output; 1471 vs->output = vs->tight.tmp; 1472 } 1473 1474 static int send_sub_rect_nojpeg(VncState *vs, int x, int y, int w, int h, 1475 int bg, int fg, int colors, VncPalette *palette) 1476 { 1477 int ret; 1478 1479 if (colors == 0) { 1480 if (tight_detect_smooth_image(vs, w, h)) { 1481 ret = send_gradient_rect(vs, x, y, w, h); 1482 } else { 1483 ret = send_full_color_rect(vs, x, y, w, h); 1484 } 1485 } else if (colors == 1) { 1486 ret = send_solid_rect(vs); 1487 } else if (colors == 2) { 1488 ret = send_mono_rect(vs, x, y, w, h, bg, fg); 1489 } else if (colors <= 256) { 1490 ret = send_palette_rect(vs, x, y, w, h, palette); 1491 } else { 1492 ret = 0; 1493 } 1494 return ret; 1495 } 1496 1497 #ifdef CONFIG_VNC_JPEG 1498 static int send_sub_rect_jpeg(VncState *vs, int x, int y, int w, int h, 1499 int bg, int fg, int colors, 1500 VncPalette *palette, bool force) 1501 { 1502 int ret; 1503 1504 if (colors == 0) { 1505 if (force || (tight_jpeg_conf[vs->tight.quality].jpeg_full && 1506 tight_detect_smooth_image(vs, w, h))) { 1507 int quality = tight_conf[vs->tight.quality].jpeg_quality; 1508 1509 ret = send_jpeg_rect(vs, x, y, w, h, quality); 1510 } else { 1511 ret = send_full_color_rect(vs, x, y, w, h); 1512 } 1513 } else if (colors == 1) { 1514 ret = send_solid_rect(vs); 1515 } else if (colors == 2) { 1516 ret = send_mono_rect(vs, x, y, w, h, bg, fg); 1517 } else if (colors <= 256) { 1518 if (force || (colors > 96 && 1519 tight_jpeg_conf[vs->tight.quality].jpeg_idx && 1520 tight_detect_smooth_image(vs, w, h))) { 1521 int quality = tight_conf[vs->tight.quality].jpeg_quality; 1522 1523 ret = send_jpeg_rect(vs, x, y, w, h, quality); 1524 } else { 1525 ret = send_palette_rect(vs, x, y, w, h, palette); 1526 } 1527 } else { 1528 ret = 0; 1529 } 1530 return ret; 1531 } 1532 #endif 1533 1534 static int send_sub_rect(VncState *vs, int x, int y, int w, int h) 1535 { 1536 VncPalette *palette = NULL; 1537 uint32_t bg = 0, fg = 0; 1538 int colors; 1539 int ret = 0; 1540 #ifdef CONFIG_VNC_JPEG 1541 bool force_jpeg = false; 1542 bool allow_jpeg = true; 1543 #endif 1544 1545 vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type); 1546 1547 vnc_tight_start(vs); 1548 vnc_raw_send_framebuffer_update(vs, x, y, w, h); 1549 vnc_tight_stop(vs); 1550 1551 #ifdef CONFIG_VNC_JPEG 1552 if (!vs->vd->non_adaptive && vs->tight.quality != (uint8_t)-1) { 1553 double freq = vnc_update_freq(vs, x, y, w, h); 1554 1555 if (freq < tight_jpeg_conf[vs->tight.quality].jpeg_freq_min) { 1556 allow_jpeg = false; 1557 } 1558 if (freq >= tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) { 1559 force_jpeg = true; 1560 vnc_sent_lossy_rect(vs, x, y, w, h); 1561 } 1562 } 1563 #endif 1564 1565 colors = tight_fill_palette(vs, x, y, w * h, &fg, &bg, &palette); 1566 1567 #ifdef CONFIG_VNC_JPEG 1568 if (allow_jpeg && vs->tight.quality != (uint8_t)-1) { 1569 ret = send_sub_rect_jpeg(vs, x, y, w, h, bg, fg, colors, palette, 1570 force_jpeg); 1571 } else { 1572 ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette); 1573 } 1574 #else 1575 ret = send_sub_rect_nojpeg(vs, x, y, w, h, bg, fg, colors, palette); 1576 #endif 1577 1578 palette_destroy(palette); 1579 return ret; 1580 } 1581 1582 static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h) 1583 { 1584 vnc_framebuffer_update(vs, x, y, w, h, vs->tight.type); 1585 1586 vnc_tight_start(vs); 1587 vnc_raw_send_framebuffer_update(vs, x, y, w, h); 1588 vnc_tight_stop(vs); 1589 1590 return send_solid_rect(vs); 1591 } 1592 1593 static int send_rect_simple(VncState *vs, int x, int y, int w, int h, 1594 bool split) 1595 { 1596 int max_size, max_width; 1597 int max_sub_width, max_sub_height; 1598 int dx, dy; 1599 int rw, rh; 1600 int n = 0; 1601 1602 max_size = tight_conf[vs->tight.compression].max_rect_size; 1603 max_width = tight_conf[vs->tight.compression].max_rect_width; 1604 1605 if (split && (w > max_width || w * h > max_size)) { 1606 max_sub_width = (w > max_width) ? max_width : w; 1607 max_sub_height = max_size / max_sub_width; 1608 1609 for (dy = 0; dy < h; dy += max_sub_height) { 1610 for (dx = 0; dx < w; dx += max_width) { 1611 rw = MIN(max_sub_width, w - dx); 1612 rh = MIN(max_sub_height, h - dy); 1613 n += send_sub_rect(vs, x+dx, y+dy, rw, rh); 1614 } 1615 } 1616 } else { 1617 n += send_sub_rect(vs, x, y, w, h); 1618 } 1619 1620 return n; 1621 } 1622 1623 static int find_large_solid_color_rect(VncState *vs, int x, int y, 1624 int w, int h, int max_rows) 1625 { 1626 int dx, dy, dw, dh; 1627 int n = 0; 1628 1629 /* Try to find large solid-color areas and send them separately. */ 1630 1631 for (dy = y; dy < y + h; dy += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) { 1632 1633 /* If a rectangle becomes too large, send its upper part now. */ 1634 1635 if (dy - y >= max_rows) { 1636 n += send_rect_simple(vs, x, y, w, max_rows, true); 1637 y += max_rows; 1638 h -= max_rows; 1639 } 1640 1641 dh = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (y + h - dy)); 1642 1643 for (dx = x; dx < x + w; dx += VNC_TIGHT_MAX_SPLIT_TILE_SIZE) { 1644 uint32_t color_value; 1645 int x_best, y_best, w_best, h_best; 1646 1647 dw = MIN(VNC_TIGHT_MAX_SPLIT_TILE_SIZE, (x + w - dx)); 1648 1649 if (!check_solid_tile(vs, dx, dy, dw, dh, &color_value, false)) { 1650 continue ; 1651 } 1652 1653 /* Get dimensions of solid-color area. */ 1654 1655 find_best_solid_area(vs, dx, dy, w - (dx - x), h - (dy - y), 1656 color_value, &w_best, &h_best); 1657 1658 /* Make sure a solid rectangle is large enough 1659 (or the whole rectangle is of the same color). */ 1660 1661 if (w_best * h_best != w * h && 1662 w_best * h_best < VNC_TIGHT_MIN_SOLID_SUBRECT_SIZE) { 1663 continue; 1664 } 1665 1666 /* Try to extend solid rectangle to maximum size. */ 1667 1668 x_best = dx; y_best = dy; 1669 extend_solid_area(vs, x, y, w, h, color_value, 1670 &x_best, &y_best, &w_best, &h_best); 1671 1672 /* Send rectangles at top and left to solid-color area. */ 1673 1674 if (y_best != y) { 1675 n += send_rect_simple(vs, x, y, w, y_best-y, true); 1676 } 1677 if (x_best != x) { 1678 n += tight_send_framebuffer_update(vs, x, y_best, 1679 x_best-x, h_best); 1680 } 1681 1682 /* Send solid-color rectangle. */ 1683 n += send_sub_rect_solid(vs, x_best, y_best, w_best, h_best); 1684 1685 /* Send remaining rectangles (at right and bottom). */ 1686 1687 if (x_best + w_best != x + w) { 1688 n += tight_send_framebuffer_update(vs, x_best+w_best, 1689 y_best, 1690 w-(x_best-x)-w_best, 1691 h_best); 1692 } 1693 if (y_best + h_best != y + h) { 1694 n += tight_send_framebuffer_update(vs, x, y_best+h_best, 1695 w, h-(y_best-y)-h_best); 1696 } 1697 1698 /* Return after all recursive calls are done. */ 1699 return n; 1700 } 1701 } 1702 return n + send_rect_simple(vs, x, y, w, h, true); 1703 } 1704 1705 static int tight_send_framebuffer_update(VncState *vs, int x, int y, 1706 int w, int h) 1707 { 1708 int max_rows; 1709 1710 if (vs->clientds.pf.bytes_per_pixel == 4 && vs->clientds.pf.rmax == 0xFF && 1711 vs->clientds.pf.bmax == 0xFF && vs->clientds.pf.gmax == 0xFF) { 1712 vs->tight.pixel24 = true; 1713 } else { 1714 vs->tight.pixel24 = false; 1715 } 1716 1717 #ifdef CONFIG_VNC_JPEG 1718 if (vs->tight.quality != (uint8_t)-1) { 1719 double freq = vnc_update_freq(vs, x, y, w, h); 1720 1721 if (freq > tight_jpeg_conf[vs->tight.quality].jpeg_freq_threshold) { 1722 return send_rect_simple(vs, x, y, w, h, false); 1723 } 1724 } 1725 #endif 1726 1727 if (w * h < VNC_TIGHT_MIN_SPLIT_RECT_SIZE) { 1728 return send_rect_simple(vs, x, y, w, h, true); 1729 } 1730 1731 /* Calculate maximum number of rows in one non-solid rectangle. */ 1732 1733 max_rows = tight_conf[vs->tight.compression].max_rect_size; 1734 max_rows /= MIN(tight_conf[vs->tight.compression].max_rect_width, w); 1735 1736 return find_large_solid_color_rect(vs, x, y, w, h, max_rows); 1737 } 1738 1739 int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, 1740 int w, int h) 1741 { 1742 vs->tight.type = VNC_ENCODING_TIGHT; 1743 return tight_send_framebuffer_update(vs, x, y, w, h); 1744 } 1745 1746 int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y, 1747 int w, int h) 1748 { 1749 vs->tight.type = VNC_ENCODING_TIGHT_PNG; 1750 return tight_send_framebuffer_update(vs, x, y, w, h); 1751 } 1752 1753 void vnc_tight_clear(VncState *vs) 1754 { 1755 int i; 1756 for (i=0; i<ARRAY_SIZE(vs->tight.stream); i++) { 1757 if (vs->tight.stream[i].opaque) { 1758 deflateEnd(&vs->tight.stream[i]); 1759 } 1760 } 1761 1762 buffer_free(&vs->tight.tight); 1763 buffer_free(&vs->tight.zlib); 1764 buffer_free(&vs->tight.gradient); 1765 #ifdef CONFIG_VNC_JPEG 1766 buffer_free(&vs->tight.jpeg); 1767 #endif 1768 #ifdef CONFIG_VNC_PNG 1769 buffer_free(&vs->tight.png); 1770 #endif 1771 } 1772