1139c1837SPaolo Bonzini/* 2139c1837SPaolo Bonzini * QEMU VNC display driver: Zlib Run-length Encoding (ZRLE) 3139c1837SPaolo Bonzini * 4139c1837SPaolo Bonzini * From libvncserver/libvncserver/zrleencodetemplate.c 5139c1837SPaolo Bonzini * Copyright (C) 2002 RealVNC Ltd. All Rights Reserved. 6139c1837SPaolo Bonzini * Copyright (C) 2003 Sun Microsystems, Inc. 7139c1837SPaolo Bonzini * 8139c1837SPaolo Bonzini * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com> 9139c1837SPaolo Bonzini * 10139c1837SPaolo Bonzini * This work is licensed under the terms of the GNU GPL, version 2 or later. 11139c1837SPaolo Bonzini * See the COPYING file in the top-level directory. 12139c1837SPaolo Bonzini */ 13139c1837SPaolo Bonzini 14139c1837SPaolo Bonzini/* 15139c1837SPaolo Bonzini * Before including this file, you must define a number of CPP macros. 16139c1837SPaolo Bonzini * 17139c1837SPaolo Bonzini * ZRLE_BPP should be 8, 16 or 32 depending on the bits per pixel. 18139c1837SPaolo Bonzini * 19139c1837SPaolo Bonzini * Note that the buf argument to ZRLE_ENCODE needs to be at least one pixel 20139c1837SPaolo Bonzini * bigger than the largest tile of pixel data, since the ZRLE encoding 21139c1837SPaolo Bonzini * algorithm writes to the position one past the end of the pixel data. 22139c1837SPaolo Bonzini */ 23139c1837SPaolo Bonzini 24139c1837SPaolo Bonzini 25139c1837SPaolo Bonzini#include "qemu/osdep.h" 26139c1837SPaolo Bonzini 27139c1837SPaolo Bonzini#undef ZRLE_ENDIAN_SUFFIX 28139c1837SPaolo Bonzini 29139c1837SPaolo Bonzini#if ZYWRLE_ENDIAN == ENDIAN_LITTLE 30139c1837SPaolo Bonzini#define ZRLE_ENDIAN_SUFFIX le 31139c1837SPaolo Bonzini#elif ZYWRLE_ENDIAN == ENDIAN_BIG 32139c1837SPaolo Bonzini#define ZRLE_ENDIAN_SUFFIX be 33139c1837SPaolo Bonzini#else 34139c1837SPaolo Bonzini#define ZRLE_ENDIAN_SUFFIX ne 35139c1837SPaolo Bonzini#endif 36139c1837SPaolo Bonzini 37139c1837SPaolo Bonzini#ifndef ZRLE_CONCAT 38139c1837SPaolo Bonzini#define ZRLE_CONCAT_I(a, b) a##b 39139c1837SPaolo Bonzini#define ZRLE_CONCAT2(a, b) ZRLE_CONCAT_I(a, b) 40139c1837SPaolo Bonzini#define ZRLE_CONCAT3(a, b, c) ZRLE_CONCAT2(a, ZRLE_CONCAT2(b, c)) 41139c1837SPaolo Bonzini#endif 42139c1837SPaolo Bonzini 43139c1837SPaolo Bonzini#ifdef ZRLE_COMPACT_PIXEL 44139c1837SPaolo Bonzini#define ZRLE_ENCODE_SUFFIX ZRLE_CONCAT2(ZRLE_COMPACT_PIXEL,ZRLE_ENDIAN_SUFFIX) 45139c1837SPaolo Bonzini#define ZRLE_WRITE_SUFFIX ZRLE_COMPACT_PIXEL 46139c1837SPaolo Bonzini#define ZRLE_PIXEL ZRLE_CONCAT3(uint,ZRLE_BPP,_t) 47139c1837SPaolo Bonzini#define ZRLE_BPP_OUT 24 48139c1837SPaolo Bonzini#elif ZRLE_BPP == 15 49139c1837SPaolo Bonzini#define ZRLE_ENCODE_SUFFIX ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX) 50139c1837SPaolo Bonzini#define ZRLE_WRITE_SUFFIX 16 51139c1837SPaolo Bonzini#define ZRLE_PIXEL uint16_t 52139c1837SPaolo Bonzini#define ZRLE_BPP_OUT 16 53139c1837SPaolo Bonzini#else 54139c1837SPaolo Bonzini#define ZRLE_ENCODE_SUFFIX ZRLE_CONCAT2(ZRLE_BPP,ZRLE_ENDIAN_SUFFIX) 55139c1837SPaolo Bonzini#define ZRLE_WRITE_SUFFIX ZRLE_BPP 56139c1837SPaolo Bonzini#define ZRLE_BPP_OUT ZRLE_BPP 57139c1837SPaolo Bonzini#define ZRLE_PIXEL ZRLE_CONCAT3(uint,ZRLE_BPP,_t) 58139c1837SPaolo Bonzini#endif 59139c1837SPaolo Bonzini 60139c1837SPaolo Bonzini#define ZRLE_WRITE_PIXEL ZRLE_CONCAT2(zrle_write_u, ZRLE_WRITE_SUFFIX) 61139c1837SPaolo Bonzini#define ZRLE_ENCODE ZRLE_CONCAT2(zrle_encode_, ZRLE_ENCODE_SUFFIX) 62139c1837SPaolo Bonzini#define ZRLE_ENCODE_TILE ZRLE_CONCAT2(zrle_encode_tile, ZRLE_ENCODE_SUFFIX) 63139c1837SPaolo Bonzini#define ZRLE_WRITE_PALETTE ZRLE_CONCAT2(zrle_write_palette,ZRLE_ENCODE_SUFFIX) 64139c1837SPaolo Bonzini 65139c1837SPaolo Bonzinistatic void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, 66139c1837SPaolo Bonzini int zywrle_level); 67139c1837SPaolo Bonzini 68139c1837SPaolo Bonzini#if ZRLE_BPP != 8 69139c1837SPaolo Bonzini#include "vnc-enc-zywrle-template.c" 70139c1837SPaolo Bonzini#endif 71139c1837SPaolo Bonzini 72139c1837SPaolo Bonzini 73139c1837SPaolo Bonzinistatic void ZRLE_ENCODE(VncState *vs, int x, int y, int w, int h, 74139c1837SPaolo Bonzini int zywrle_level) 75139c1837SPaolo Bonzini{ 76139c1837SPaolo Bonzini int ty; 77139c1837SPaolo Bonzini 78139c1837SPaolo Bonzini for (ty = y; ty < y + h; ty += VNC_ZRLE_TILE_HEIGHT) { 79139c1837SPaolo Bonzini 80139c1837SPaolo Bonzini int tx, th; 81139c1837SPaolo Bonzini 82139c1837SPaolo Bonzini th = MIN(VNC_ZRLE_TILE_HEIGHT, y + h - ty); 83139c1837SPaolo Bonzini 84139c1837SPaolo Bonzini for (tx = x; tx < x + w; tx += VNC_ZRLE_TILE_WIDTH) { 85139c1837SPaolo Bonzini int tw; 86139c1837SPaolo Bonzini ZRLE_PIXEL *buf; 87139c1837SPaolo Bonzini 88139c1837SPaolo Bonzini tw = MIN(VNC_ZRLE_TILE_WIDTH, x + w - tx); 89139c1837SPaolo Bonzini 90139c1837SPaolo Bonzini buf = zrle_convert_fb(vs, tx, ty, tw, th, ZRLE_BPP); 91139c1837SPaolo Bonzini ZRLE_ENCODE_TILE(vs, buf, tw, th, zywrle_level); 92139c1837SPaolo Bonzini } 93139c1837SPaolo Bonzini } 94139c1837SPaolo Bonzini} 95139c1837SPaolo Bonzini 96139c1837SPaolo Bonzinistatic void ZRLE_ENCODE_TILE(VncState *vs, ZRLE_PIXEL *data, int w, int h, 97139c1837SPaolo Bonzini int zywrle_level) 98139c1837SPaolo Bonzini{ 99139c1837SPaolo Bonzini VncPalette *palette = &vs->zrle->palette; 100139c1837SPaolo Bonzini 101139c1837SPaolo Bonzini int runs = 0; 102139c1837SPaolo Bonzini int single_pixels = 0; 103139c1837SPaolo Bonzini 104139c1837SPaolo Bonzini bool use_rle; 105139c1837SPaolo Bonzini bool use_palette; 106139c1837SPaolo Bonzini 107139c1837SPaolo Bonzini int i; 108139c1837SPaolo Bonzini 109139c1837SPaolo Bonzini ZRLE_PIXEL *ptr = data; 110139c1837SPaolo Bonzini ZRLE_PIXEL *end = ptr + h * w; 111139c1837SPaolo Bonzini *end = ~*(end-1); /* one past the end is different so the while loop ends */ 112139c1837SPaolo Bonzini 113d4761b65SMichael Tokarev /* Real limit is 127 but we want a way to know if there is more than 127 */ 114139c1837SPaolo Bonzini palette_init(palette, 256, ZRLE_BPP); 115139c1837SPaolo Bonzini 116139c1837SPaolo Bonzini while (ptr < end) { 117139c1837SPaolo Bonzini ZRLE_PIXEL pix = *ptr; 118139c1837SPaolo Bonzini if (*++ptr != pix) { /* FIXME */ 119139c1837SPaolo Bonzini single_pixels++; 120139c1837SPaolo Bonzini } else { 121139c1837SPaolo Bonzini while (*++ptr == pix) ; 122139c1837SPaolo Bonzini runs++; 123139c1837SPaolo Bonzini } 124139c1837SPaolo Bonzini palette_put(palette, pix); 125139c1837SPaolo Bonzini } 126139c1837SPaolo Bonzini 127139c1837SPaolo Bonzini /* Solid tile is a special case */ 128139c1837SPaolo Bonzini 129139c1837SPaolo Bonzini if (palette_size(palette) == 1) { 130139c1837SPaolo Bonzini bool found; 131139c1837SPaolo Bonzini 132139c1837SPaolo Bonzini vnc_write_u8(vs, 1); 133139c1837SPaolo Bonzini ZRLE_WRITE_PIXEL(vs, palette_color(palette, 0, &found)); 134139c1837SPaolo Bonzini return; 135139c1837SPaolo Bonzini } 136139c1837SPaolo Bonzini 137139c1837SPaolo Bonzini zrle_choose_palette_rle(vs, w, h, palette, ZRLE_BPP_OUT, 138139c1837SPaolo Bonzini runs, single_pixels, zywrle_level, 139139c1837SPaolo Bonzini &use_rle, &use_palette); 140139c1837SPaolo Bonzini 141139c1837SPaolo Bonzini if (!use_palette) { 142139c1837SPaolo Bonzini vnc_write_u8(vs, (use_rle ? 128 : 0)); 143139c1837SPaolo Bonzini } else { 144139c1837SPaolo Bonzini uint32_t colors[VNC_PALETTE_MAX_SIZE]; 145139c1837SPaolo Bonzini size_t size = palette_size(palette); 146139c1837SPaolo Bonzini 147139c1837SPaolo Bonzini vnc_write_u8(vs, (use_rle ? 128 : 0) | size); 148139c1837SPaolo Bonzini palette_fill(palette, colors); 149139c1837SPaolo Bonzini 150139c1837SPaolo Bonzini for (i = 0; i < size; i++) { 151139c1837SPaolo Bonzini ZRLE_WRITE_PIXEL(vs, colors[i]); 152139c1837SPaolo Bonzini } 153139c1837SPaolo Bonzini } 154139c1837SPaolo Bonzini 155139c1837SPaolo Bonzini if (use_rle) { 156139c1837SPaolo Bonzini ZRLE_PIXEL *run_start; 157139c1837SPaolo Bonzini ZRLE_PIXEL pix; 158139c1837SPaolo Bonzini 159*e33e66b1SMarkus Armbruster ptr = data; 160*e33e66b1SMarkus Armbruster end = ptr + w * h; 161*e33e66b1SMarkus Armbruster 162139c1837SPaolo Bonzini while (ptr < end) { 163139c1837SPaolo Bonzini int len; 164139c1837SPaolo Bonzini int index = 0; 165139c1837SPaolo Bonzini 166139c1837SPaolo Bonzini run_start = ptr; 167139c1837SPaolo Bonzini pix = *ptr++; 168139c1837SPaolo Bonzini 169139c1837SPaolo Bonzini while (*ptr == pix && ptr < end) { 170139c1837SPaolo Bonzini ptr++; 171139c1837SPaolo Bonzini } 172139c1837SPaolo Bonzini 173139c1837SPaolo Bonzini len = ptr - run_start; 174139c1837SPaolo Bonzini 175139c1837SPaolo Bonzini if (use_palette) 176139c1837SPaolo Bonzini index = palette_idx(palette, pix); 177139c1837SPaolo Bonzini 178139c1837SPaolo Bonzini if (len <= 2 && use_palette) { 179139c1837SPaolo Bonzini if (len == 2) { 180139c1837SPaolo Bonzini vnc_write_u8(vs, index); 181139c1837SPaolo Bonzini } 182139c1837SPaolo Bonzini vnc_write_u8(vs, index); 183139c1837SPaolo Bonzini continue; 184139c1837SPaolo Bonzini } 185139c1837SPaolo Bonzini if (use_palette) { 186139c1837SPaolo Bonzini vnc_write_u8(vs, index | 128); 187139c1837SPaolo Bonzini } else { 188139c1837SPaolo Bonzini ZRLE_WRITE_PIXEL(vs, pix); 189139c1837SPaolo Bonzini } 190139c1837SPaolo Bonzini 191139c1837SPaolo Bonzini len -= 1; 192139c1837SPaolo Bonzini 193139c1837SPaolo Bonzini while (len >= 255) { 194139c1837SPaolo Bonzini vnc_write_u8(vs, 255); 195139c1837SPaolo Bonzini len -= 255; 196139c1837SPaolo Bonzini } 197139c1837SPaolo Bonzini 198139c1837SPaolo Bonzini vnc_write_u8(vs, len); 199139c1837SPaolo Bonzini } 200139c1837SPaolo Bonzini } else if (use_palette) { /* no RLE */ 201139c1837SPaolo Bonzini int bppp; 202*e33e66b1SMarkus Armbruster ptr = data; 203139c1837SPaolo Bonzini 204139c1837SPaolo Bonzini /* packed pixels */ 205139c1837SPaolo Bonzini 206139c1837SPaolo Bonzini assert (palette_size(palette) < 17); 207139c1837SPaolo Bonzini 208139c1837SPaolo Bonzini bppp = bits_per_packed_pixel[palette_size(palette)-1]; 209139c1837SPaolo Bonzini 210139c1837SPaolo Bonzini for (i = 0; i < h; i++) { 211139c1837SPaolo Bonzini uint8_t nbits = 0; 212139c1837SPaolo Bonzini uint8_t byte = 0; 213139c1837SPaolo Bonzini 214139c1837SPaolo Bonzini ZRLE_PIXEL *eol = ptr + w; 215139c1837SPaolo Bonzini 216139c1837SPaolo Bonzini while (ptr < eol) { 217139c1837SPaolo Bonzini ZRLE_PIXEL pix = *ptr++; 218139c1837SPaolo Bonzini uint8_t index = palette_idx(palette, pix); 219139c1837SPaolo Bonzini 220139c1837SPaolo Bonzini byte = (byte << bppp) | index; 221139c1837SPaolo Bonzini nbits += bppp; 222139c1837SPaolo Bonzini if (nbits >= 8) { 223139c1837SPaolo Bonzini vnc_write_u8(vs, byte); 224139c1837SPaolo Bonzini nbits = 0; 225139c1837SPaolo Bonzini } 226139c1837SPaolo Bonzini } 227139c1837SPaolo Bonzini if (nbits > 0) { 228139c1837SPaolo Bonzini byte <<= 8 - nbits; 229139c1837SPaolo Bonzini vnc_write_u8(vs, byte); 230139c1837SPaolo Bonzini } 231139c1837SPaolo Bonzini } 232139c1837SPaolo Bonzini } else { 233139c1837SPaolo Bonzini 234139c1837SPaolo Bonzini /* raw */ 235139c1837SPaolo Bonzini 236139c1837SPaolo Bonzini#if ZRLE_BPP != 8 237139c1837SPaolo Bonzini if (zywrle_level > 0 && !(zywrle_level & 0x80)) { 238139c1837SPaolo Bonzini ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, vs->zywrle.buf); 239139c1837SPaolo Bonzini ZRLE_ENCODE_TILE(vs, data, w, h, zywrle_level | 0x80); 240139c1837SPaolo Bonzini } 241139c1837SPaolo Bonzini else 242139c1837SPaolo Bonzini#endif 243139c1837SPaolo Bonzini { 244139c1837SPaolo Bonzini#ifdef ZRLE_COMPACT_PIXEL 245139c1837SPaolo Bonzini for (ptr = data; ptr < data + w * h; ptr++) { 246139c1837SPaolo Bonzini ZRLE_WRITE_PIXEL(vs, *ptr); 247139c1837SPaolo Bonzini } 248139c1837SPaolo Bonzini#else 249139c1837SPaolo Bonzini vnc_write(vs, data, w * h * (ZRLE_BPP / 8)); 250139c1837SPaolo Bonzini#endif 251139c1837SPaolo Bonzini } 252139c1837SPaolo Bonzini } 253139c1837SPaolo Bonzini} 254139c1837SPaolo Bonzini 255139c1837SPaolo Bonzini#undef ZRLE_PIXEL 256139c1837SPaolo Bonzini#undef ZRLE_WRITE_PIXEL 257139c1837SPaolo Bonzini#undef ZRLE_ENCODE 258139c1837SPaolo Bonzini#undef ZRLE_ENCODE_TILE 259139c1837SPaolo Bonzini#undef ZYWRLE_ENCODE_TILE 260139c1837SPaolo Bonzini#undef ZRLE_BPP_OUT 261139c1837SPaolo Bonzini#undef ZRLE_WRITE_SUFFIX 262139c1837SPaolo Bonzini#undef ZRLE_ENCODE_SUFFIX 263