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