|  | /* | 
|  | * QEMU VNC display driver: Zlib Run-length Encoding (ZRLE) | 
|  | * | 
|  | * From libvncserver/libvncserver/zrleencodetemplate.c | 
|  | * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved. | 
|  | * Copyright (C) 2003 Sun Microsystems, Inc. | 
|  | * | 
|  | * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com> | 
|  | * | 
|  | * This work is licensed under the terms of the GNU GPL, version 2 or later. | 
|  | * See the COPYING file in the top-level directory. | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * Before including this file, you must define a number of CPP macros. | 
|  | * | 
|  | * ZRLE_BPP should be 8, 16 or 32 depending on the bits per pixel. | 
|  | * | 
|  | * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel | 
|  | * bigger than the largest tile of pixel data, since the ZRLE encoding | 
|  | * algorithm writes to the position one past the end of the pixel data. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include "qemu/osdep.h" | 
|  |  | 
|  | #undef ZRLE_ENDIAN_SUFFIX | 
|  |  | 
|  | #if ZYWRLE_ENDIAN == ENDIAN_LITTLE | 
|  | #define ZRLE_ENDIAN_SUFFIX le | 
|  | #elif ZYWRLE_ENDIAN == ENDIAN_BIG | 
|  | #define ZRLE_ENDIAN_SUFFIX be | 
|  | #else | 
|  | #define ZRLE_ENDIAN_SUFFIX ne | 
|  | #endif | 
|  |  | 
|  | #ifndef ZRLE_CONCAT | 
|  | #define ZRLE_CONCAT_I(a, b)    a##b | 
|  | #define ZRLE_CONCAT2(a, b)     ZRLE_CONCAT_I(a, b) | 
|  | #define ZRLE_CONCAT3(a, b, c)  ZRLE_CONCAT2(a, ZRLE_CONCAT2(b, c)) | 
|  | #endif | 
|  |  | 
|  | #ifdef ZRLE_COMPACT_PIXEL | 
|  | #define ZRLE_ENCODE_SUFFIX   ZRLE_CONCAT2(ZRLE_COMPACT_PIXEL,ZRLE_ENDIAN_SUFFIX) | 
|  | #define ZRLE_WRITE_SUFFIX    ZRLE_COMPACT_PIXEL | 
|  | #define ZRLE_PIXEL           ZRLE_CONCAT3(uint,ZRLE_BPP,_t) | 
|  | #define ZRLE_BPP_OUT         24 | 
|  | #elif ZRLE_BPP == 15 | 
|  | #define ZRLE_ENCODE_SUFFIX   ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX) | 
|  | #define ZRLE_WRITE_SUFFIX    16 | 
|  | #define ZRLE_PIXEL           uint16_t | 
|  | #define ZRLE_BPP_OUT         16 | 
|  | #else | 
|  | #define ZRLE_ENCODE_SUFFIX   ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX) | 
|  | #define ZRLE_WRITE_SUFFIX    ZRLE_BPP | 
|  | #define ZRLE_BPP_OUT         ZRLE_BPP | 
|  | #define ZRLE_PIXEL           ZRLE_CONCAT3(uint,ZRLE_BPP,_t) | 
|  | #endif | 
|  |  | 
|  | #define ZRLE_WRITE_PIXEL     ZRLE_CONCAT2(zrle_write_u,       ZRLE_WRITE_SUFFIX) | 
|  | #define ZRLE_ENCODE          ZRLE_CONCAT2(zrle_encode_,      ZRLE_ENCODE_SUFFIX) | 
|  | #define ZRLE_ENCODE_TILE     ZRLE_CONCAT2(zrle_encode_tile,  ZRLE_ENCODE_SUFFIX) | 
|  | #define ZRLE_WRITE_PALETTE   ZRLE_CONCAT2(zrle_write_palette,ZRLE_ENCODE_SUFFIX) | 
|  |  | 
|  | static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, | 
|  | int zywrle_level); | 
|  |  | 
|  | #if ZRLE_BPP != 8 | 
|  | #include "vnc-enc-zywrle-template.c" | 
|  | #endif | 
|  |  | 
|  |  | 
|  | static void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h, | 
|  | int zywrle_level) | 
|  | { | 
|  | int ty; | 
|  |  | 
|  | for (ty = y; ty < y + h; ty += VNC_ZRLE_TILE_HEIGHT) { | 
|  |  | 
|  | int tx, th; | 
|  |  | 
|  | th = MIN(VNC_ZRLE_TILE_HEIGHT, y + h - ty); | 
|  |  | 
|  | for (tx = x; tx < x + w; tx += VNC_ZRLE_TILE_WIDTH) { | 
|  | int tw; | 
|  | ZRLE_PIXEL *buf; | 
|  |  | 
|  | tw = MIN(VNC_ZRLE_TILE_WIDTH, x + w - tx); | 
|  |  | 
|  | buf = zrle_convert_fb(vs, tx, ty, tw, th, ZRLE_BPP); | 
|  | ZRLE_ENCODE_TILE(vs, buf, tw, th, zywrle_level); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, | 
|  | int zywrle_level) | 
|  | { | 
|  | VncPalette *palette = &vs->zrle->palette; | 
|  |  | 
|  | int runs = 0; | 
|  | int single_pixels = 0; | 
|  |  | 
|  | bool use_rle; | 
|  | bool use_palette; | 
|  |  | 
|  | int i; | 
|  |  | 
|  | ZRLE_PIXEL *ptr = data; | 
|  | ZRLE_PIXEL *end = ptr + h * w; | 
|  | *end = ~*(end-1); /* one past the end is different so the while loop ends */ | 
|  |  | 
|  | /* Real limit is 127 but we want a way to know if there is more than 127 */ | 
|  | palette_init(palette, 256, ZRLE_BPP); | 
|  |  | 
|  | while (ptr < end) { | 
|  | ZRLE_PIXEL pix = *ptr; | 
|  | if (*++ptr != pix) { /* FIXME */ | 
|  | single_pixels++; | 
|  | } else { | 
|  | while (*++ptr == pix) ; | 
|  | runs++; | 
|  | } | 
|  | palette_put(palette, pix); | 
|  | } | 
|  |  | 
|  | /* Solid tile is a special case */ | 
|  |  | 
|  | if (palette_size(palette) == 1) { | 
|  | bool found; | 
|  |  | 
|  | vnc_write_u8(vs, 1); | 
|  | ZRLE_WRITE_PIXEL(vs, palette_color(palette, 0, &found)); | 
|  | return; | 
|  | } | 
|  |  | 
|  | zrle_choose_palette_rle(vs, w, h, palette, ZRLE_BPP_OUT, | 
|  | runs, single_pixels, zywrle_level, | 
|  | &use_rle, &use_palette); | 
|  |  | 
|  | if (!use_palette) { | 
|  | vnc_write_u8(vs, (use_rle ? 128 : 0)); | 
|  | } else { | 
|  | uint32_t colors[VNC_PALETTE_MAX_SIZE]; | 
|  | size_t size = palette_size(palette); | 
|  |  | 
|  | vnc_write_u8(vs, (use_rle ? 128 : 0) | size); | 
|  | palette_fill(palette, colors); | 
|  |  | 
|  | for (i = 0; i < size; i++) { | 
|  | ZRLE_WRITE_PIXEL(vs, colors[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (use_rle) { | 
|  | ZRLE_PIXEL *run_start; | 
|  | ZRLE_PIXEL pix; | 
|  |  | 
|  | ptr = data; | 
|  | end = ptr + w * h; | 
|  |  | 
|  | while (ptr < end) { | 
|  | int len; | 
|  | int index = 0; | 
|  |  | 
|  | run_start = ptr; | 
|  | pix = *ptr++; | 
|  |  | 
|  | while (*ptr == pix && ptr < end) { | 
|  | ptr++; | 
|  | } | 
|  |  | 
|  | len = ptr - run_start; | 
|  |  | 
|  | if (use_palette) | 
|  | index = palette_idx(palette, pix); | 
|  |  | 
|  | if (len <= 2 && use_palette) { | 
|  | if (len == 2) { | 
|  | vnc_write_u8(vs, index); | 
|  | } | 
|  | vnc_write_u8(vs, index); | 
|  | continue; | 
|  | } | 
|  | if (use_palette) { | 
|  | vnc_write_u8(vs, index | 128); | 
|  | } else { | 
|  | ZRLE_WRITE_PIXEL(vs, pix); | 
|  | } | 
|  |  | 
|  | len -= 1; | 
|  |  | 
|  | while (len >= 255) { | 
|  | vnc_write_u8(vs, 255); | 
|  | len -= 255; | 
|  | } | 
|  |  | 
|  | vnc_write_u8(vs, len); | 
|  | } | 
|  | } else if (use_palette) { /* no RLE */ | 
|  | int bppp; | 
|  | ptr = data; | 
|  |  | 
|  | /* packed pixels */ | 
|  |  | 
|  | assert (palette_size(palette) < 17); | 
|  |  | 
|  | bppp = bits_per_packed_pixel[palette_size(palette)-1]; | 
|  |  | 
|  | for (i = 0; i < h; i++) { | 
|  | uint8_t nbits = 0; | 
|  | uint8_t byte = 0; | 
|  |  | 
|  | ZRLE_PIXEL *eol = ptr + w; | 
|  |  | 
|  | while (ptr < eol) { | 
|  | ZRLE_PIXEL pix = *ptr++; | 
|  | uint8_t index = palette_idx(palette, pix); | 
|  |  | 
|  | byte = (byte << bppp) | index; | 
|  | nbits += bppp; | 
|  | if (nbits >= 8) { | 
|  | vnc_write_u8(vs, byte); | 
|  | nbits = 0; | 
|  | } | 
|  | } | 
|  | if (nbits > 0) { | 
|  | byte <<= 8 - nbits; | 
|  | vnc_write_u8(vs, byte); | 
|  | } | 
|  | } | 
|  | } else { | 
|  |  | 
|  | /* raw */ | 
|  |  | 
|  | #if ZRLE_BPP != 8 | 
|  | if (zywrle_level > 0 && !(zywrle_level & 0x80)) { | 
|  | ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, vs->zywrle.buf); | 
|  | ZRLE_ENCODE_TILE(vs, data, w, h, zywrle_level | 0x80); | 
|  | } | 
|  | else | 
|  | #endif | 
|  | { | 
|  | #ifdef ZRLE_COMPACT_PIXEL | 
|  | for (ptr = data; ptr < data + w * h; ptr++) { | 
|  | ZRLE_WRITE_PIXEL(vs, *ptr); | 
|  | } | 
|  | #else | 
|  | vnc_write(vs, data, w * h * (ZRLE_BPP / 8)); | 
|  | #endif | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #undef ZRLE_PIXEL | 
|  | #undef ZRLE_WRITE_PIXEL | 
|  | #undef ZRLE_ENCODE | 
|  | #undef ZRLE_ENCODE_TILE | 
|  | #undef ZYWRLE_ENCODE_TILE | 
|  | #undef ZRLE_BPP_OUT | 
|  | #undef ZRLE_WRITE_SUFFIX | 
|  | #undef ZRLE_ENCODE_SUFFIX |