From: Marc-André Lureau <marcandre.lureau@xxxxxxxxx> Signed-off-by: Marc-André Lureau <marcandre.lureau@xxxxxxxxx> Signed-off-by: Frediano Ziglio <fziglio@xxxxxxxxxx> --- server/Makefile.am | 8 +- server/cache-item.tmpl.c | 143 ++++++++++ server/cache_item.tmpl.c | 143 ---------- server/cursor-channel.c | 2 +- server/dcc.c | 2 +- server/glz-encode-match.tmpl.c | 154 +++++++++++ server/glz-encode.tmpl.c | 574 +++++++++++++++++++++++++++++++++++++++ server/glz_encode_match_tmpl.c | 154 ----------- server/glz_encode_tmpl.c | 574 --------------------------------------- server/glz_encoder.c | 14 +- server/red_bitmap_utils_tmpl.c | 160 ----------- server/spice-bitmap-utils.c | 6 +- server/spice-bitmap-utils.tmpl.c | 160 +++++++++++ 13 files changed, 1047 insertions(+), 1047 deletions(-) create mode 100644 server/cache-item.tmpl.c delete mode 100644 server/cache_item.tmpl.c create mode 100644 server/glz-encode-match.tmpl.c create mode 100644 server/glz-encode.tmpl.c delete mode 100644 server/glz_encode_match_tmpl.c delete mode 100644 server/glz_encode_tmpl.c delete mode 100644 server/red_bitmap_utils_tmpl.c create mode 100644 server/spice-bitmap-utils.tmpl.c diff --git a/server/Makefile.am b/server/Makefile.am index 4e4fc6f..6b45a42 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -154,10 +154,10 @@ libspice_server_la_SOURCES += \ endif EXTRA_DIST = \ - red_bitmap_utils_tmpl.c \ - cache_item.tmpl.c \ - glz_encode_match_tmpl.c \ - glz_encode_tmpl.c \ + spice-bitmap-utils.tmpl.c \ + cache-item.tmpl.c \ + glz-encode-match.tmpl.c \ + glz-encode.tmpl.c \ spice-server.syms \ $(NULL) diff --git a/server/cache-item.tmpl.c b/server/cache-item.tmpl.c new file mode 100644 index 0000000..09add79 --- /dev/null +++ b/server/cache-item.tmpl.c @@ -0,0 +1,143 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if defined(CLIENT_CURSOR_CACHE) + +#define CACHE_NAME cursor_cache +#define CACHE_HASH_KEY CURSOR_CACHE_HASH_KEY +#define CACHE_HASH_SIZE CURSOR_CACHE_HASH_SIZE +#define CACHE_INVAL_TYPE SPICE_MSG_CURSOR_INVAL_ONE +#define FUNC_NAME(name) red_cursor_cache_##name +#define VAR_NAME(name) cursor_cache_##name +#define CHANNEL CursorChannel +#define CHANNELCLIENT CursorChannelClient + +#elif defined(CLIENT_PALETTE_CACHE) + +#define CACHE_NAME palette_cache +#define CACHE_HASH_KEY PALETTE_CACHE_HASH_KEY +#define CACHE_HASH_SIZE PALETTE_CACHE_HASH_SIZE +#define CACHE_INVAL_TYPE SPICE_MSG_DISPLAY_INVAL_PALETTE +#define FUNC_NAME(name) red_palette_cache_##name +#define VAR_NAME(name) palette_cache_##name +#define CHANNEL DisplayChannel +#define CHANNELCLIENT DisplayChannelClient +#else + +#error "no cache type." + +#endif + +#define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF((rcc)->channel, CHANNEL, common.base); + +static CacheItem *FUNC_NAME(find)(CHANNELCLIENT *channel_client, uint64_t id) +{ + CacheItem *item = channel_client->CACHE_NAME[CACHE_HASH_KEY(id)]; + + while (item) { + if (item->id == id) { + ring_remove(&item->u.cache_data.lru_link); + ring_add(&channel_client->VAR_NAME(lru), &item->u.cache_data.lru_link); + break; + } + item = item->u.cache_data.next; + } + return item; +} + +static void FUNC_NAME(remove)(CHANNELCLIENT *channel_client, CacheItem *item) +{ + CacheItem **now; + CHANNEL *channel = CHANNEL_FROM_RCC(&channel_client->common.base); + spice_assert(item); + + now = &channel_client->CACHE_NAME[CACHE_HASH_KEY(item->id)]; + for (;;) { + spice_assert(*now); + if (*now == item) { + *now = item->u.cache_data.next; + break; + } + now = &(*now)->u.cache_data.next; + } + ring_remove(&item->u.cache_data.lru_link); + channel_client->VAR_NAME(items)--; + channel_client->VAR_NAME(available) += item->size; + + red_channel_pipe_item_init(&channel->common.base, &item->u.pipe_data, PIPE_ITEM_TYPE_INVAL_ONE); + red_channel_client_pipe_add_tail(&channel_client->common.base, &item->u.pipe_data); // for now +} + +static int FUNC_NAME(add)(CHANNELCLIENT *channel_client, uint64_t id, size_t size) +{ + CacheItem *item; + int key; + + item = spice_new(CacheItem, 1); + + channel_client->VAR_NAME(available) -= size; + while (channel_client->VAR_NAME(available) < 0) { + CacheItem *tail = (CacheItem *)ring_get_tail(&channel_client->VAR_NAME(lru)); + if (!tail) { + channel_client->VAR_NAME(available) += size; + free(item); + return FALSE; + } + FUNC_NAME(remove)(channel_client, tail); + } + ++channel_client->VAR_NAME(items); + item->u.cache_data.next = channel_client->CACHE_NAME[(key = CACHE_HASH_KEY(id))]; + channel_client->CACHE_NAME[key] = item; + ring_item_init(&item->u.cache_data.lru_link); + ring_add(&channel_client->VAR_NAME(lru), &item->u.cache_data.lru_link); + item->id = id; + item->size = size; + item->inval_type = CACHE_INVAL_TYPE; + return TRUE; +} + +static void FUNC_NAME(reset)(CHANNELCLIENT *channel_client, long size) +{ + int i; + + for (i = 0; i < CACHE_HASH_SIZE; i++) { + while (channel_client->CACHE_NAME[i]) { + CacheItem *item = channel_client->CACHE_NAME[i]; + channel_client->CACHE_NAME[i] = item->u.cache_data.next; + free(item); + } + } + ring_init(&channel_client->VAR_NAME(lru)); + channel_client->VAR_NAME(available) = size; + channel_client->VAR_NAME(items) = 0; +} + + +#undef CACHE_NAME +#undef CACHE_HASH_KEY +#undef CACHE_HASH_SIZE +#undef CACHE_INVAL_TYPE +#undef CACHE_MAX_CLIENT_SIZE +#undef FUNC_NAME +#undef VAR_NAME +#undef CHANNEL +#undef CHANNELCLIENT +#undef CHANNEL_FROM_RCC diff --git a/server/cache_item.tmpl.c b/server/cache_item.tmpl.c deleted file mode 100644 index 09add79..0000000 --- a/server/cache_item.tmpl.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(CLIENT_CURSOR_CACHE) - -#define CACHE_NAME cursor_cache -#define CACHE_HASH_KEY CURSOR_CACHE_HASH_KEY -#define CACHE_HASH_SIZE CURSOR_CACHE_HASH_SIZE -#define CACHE_INVAL_TYPE SPICE_MSG_CURSOR_INVAL_ONE -#define FUNC_NAME(name) red_cursor_cache_##name -#define VAR_NAME(name) cursor_cache_##name -#define CHANNEL CursorChannel -#define CHANNELCLIENT CursorChannelClient - -#elif defined(CLIENT_PALETTE_CACHE) - -#define CACHE_NAME palette_cache -#define CACHE_HASH_KEY PALETTE_CACHE_HASH_KEY -#define CACHE_HASH_SIZE PALETTE_CACHE_HASH_SIZE -#define CACHE_INVAL_TYPE SPICE_MSG_DISPLAY_INVAL_PALETTE -#define FUNC_NAME(name) red_palette_cache_##name -#define VAR_NAME(name) palette_cache_##name -#define CHANNEL DisplayChannel -#define CHANNELCLIENT DisplayChannelClient -#else - -#error "no cache type." - -#endif - -#define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF((rcc)->channel, CHANNEL, common.base); - -static CacheItem *FUNC_NAME(find)(CHANNELCLIENT *channel_client, uint64_t id) -{ - CacheItem *item = channel_client->CACHE_NAME[CACHE_HASH_KEY(id)]; - - while (item) { - if (item->id == id) { - ring_remove(&item->u.cache_data.lru_link); - ring_add(&channel_client->VAR_NAME(lru), &item->u.cache_data.lru_link); - break; - } - item = item->u.cache_data.next; - } - return item; -} - -static void FUNC_NAME(remove)(CHANNELCLIENT *channel_client, CacheItem *item) -{ - CacheItem **now; - CHANNEL *channel = CHANNEL_FROM_RCC(&channel_client->common.base); - spice_assert(item); - - now = &channel_client->CACHE_NAME[CACHE_HASH_KEY(item->id)]; - for (;;) { - spice_assert(*now); - if (*now == item) { - *now = item->u.cache_data.next; - break; - } - now = &(*now)->u.cache_data.next; - } - ring_remove(&item->u.cache_data.lru_link); - channel_client->VAR_NAME(items)--; - channel_client->VAR_NAME(available) += item->size; - - red_channel_pipe_item_init(&channel->common.base, &item->u.pipe_data, PIPE_ITEM_TYPE_INVAL_ONE); - red_channel_client_pipe_add_tail(&channel_client->common.base, &item->u.pipe_data); // for now -} - -static int FUNC_NAME(add)(CHANNELCLIENT *channel_client, uint64_t id, size_t size) -{ - CacheItem *item; - int key; - - item = spice_new(CacheItem, 1); - - channel_client->VAR_NAME(available) -= size; - while (channel_client->VAR_NAME(available) < 0) { - CacheItem *tail = (CacheItem *)ring_get_tail(&channel_client->VAR_NAME(lru)); - if (!tail) { - channel_client->VAR_NAME(available) += size; - free(item); - return FALSE; - } - FUNC_NAME(remove)(channel_client, tail); - } - ++channel_client->VAR_NAME(items); - item->u.cache_data.next = channel_client->CACHE_NAME[(key = CACHE_HASH_KEY(id))]; - channel_client->CACHE_NAME[key] = item; - ring_item_init(&item->u.cache_data.lru_link); - ring_add(&channel_client->VAR_NAME(lru), &item->u.cache_data.lru_link); - item->id = id; - item->size = size; - item->inval_type = CACHE_INVAL_TYPE; - return TRUE; -} - -static void FUNC_NAME(reset)(CHANNELCLIENT *channel_client, long size) -{ - int i; - - for (i = 0; i < CACHE_HASH_SIZE; i++) { - while (channel_client->CACHE_NAME[i]) { - CacheItem *item = channel_client->CACHE_NAME[i]; - channel_client->CACHE_NAME[i] = item->u.cache_data.next; - free(item); - } - } - ring_init(&channel_client->VAR_NAME(lru)); - channel_client->VAR_NAME(available) = size; - channel_client->VAR_NAME(items) = 0; -} - - -#undef CACHE_NAME -#undef CACHE_HASH_KEY -#undef CACHE_HASH_SIZE -#undef CACHE_INVAL_TYPE -#undef CACHE_MAX_CLIENT_SIZE -#undef FUNC_NAME -#undef VAR_NAME -#undef CHANNEL -#undef CHANNELCLIENT -#undef CHANNEL_FROM_RCC diff --git a/server/cursor-channel.c b/server/cursor-channel.c index aafc807..9d72299 100644 --- a/server/cursor-channel.c +++ b/server/cursor-channel.c @@ -86,7 +86,7 @@ struct CursorChannelClient { #define RCC_TO_CCC(rcc) SPICE_CONTAINEROF((rcc), CursorChannelClient, common.base) #define CLIENT_CURSOR_CACHE -#include "cache_item.tmpl.c" +#include "cache-item.tmpl.c" #undef CLIENT_CURSOR_CACHE static CursorItem *cursor_item_new(QXLInstance *qxl, RedCursorCmd *cmd, uint32_t group_id) diff --git a/server/dcc.c b/server/dcc.c index ffe5b34..6e8c876 100644 --- a/server/dcc.c +++ b/server/dcc.c @@ -1184,7 +1184,7 @@ int dcc_compress_image(DisplayChannelClient *dcc, } #define CLIENT_PALETTE_CACHE -#include "cache_item.tmpl.c" +#include "cache-item.tmpl.c" #undef CLIENT_PALETTE_CACHE void dcc_palette_cache_palette(DisplayChannelClient *dcc, SpicePalette *palette, diff --git a/server/glz-encode-match.tmpl.c b/server/glz-encode-match.tmpl.c new file mode 100644 index 0000000..1fd251e --- /dev/null +++ b/server/glz-encode-match.tmpl.c @@ -0,0 +1,154 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define SHORT_PIX_IMAGE_DIST_LEVEL_1 64 //(1 << 6) +#define SHORT_PIX_IMAGE_DIST_LEVEL_2 16384 // (1 << 14) +#define SHORT_PIX_IMAGE_DIST_LEVEL_3 4194304 // (1 << 22) +#define FAR_PIX_IMAGE_DIST_LEVEL_1 256 // (1 << 8) +#define FAR_PIX_IMAGE_DIST_LEVEL_2 65536 // (1 << 16) +#define FAR_PIX_IMAGE_DIST_LEVEL_3 16777216 // (1 << 24) + +/* if image_distance = 0, pixel_distance is the distance between the matching pixels. + Otherwise, it is the offset from the beginning of the referred image */ +#if defined(GLZ_ENCODE_MATCH) /* actually performing the encoding */ +static inline void encode_match(Encoder *encoder, uint32_t image_distance, + size_t pixel_distance, size_t len) +#elif defined(GLZ_ENCODE_SIZE) /* compute the size of the encoding except for the match length*/ +static inline int get_encode_ref_size(uint32_t image_distance, size_t pixel_distance) +#endif +{ +#if defined(GLZ_ENCODE_SIZE) + int encode_size; +#endif + +#if defined(GLZ_ENCODE_MATCH) + /* encoding the match length + Long/Short dist bit + 12 LSB pixels of pixel_distance*/ + if (len < 7) { + if (pixel_distance < MAX_PIXEL_SHORT_DISTANCE) { + encode(encoder, (uint8_t)((len << 5) + (pixel_distance & 0x0f))); + } else { + encode(encoder, (uint8_t)((len << 5) + 16 + (pixel_distance & 0x0f))); + } + encode(encoder, (uint8_t)((pixel_distance >> 4) & 255)); + } else { + if (pixel_distance < MAX_PIXEL_SHORT_DISTANCE) { + encode(encoder, (uint8_t)((7 << 5) + (pixel_distance & 0x0f))); + } else { + encode(encoder, (uint8_t)((7 << 5) + 16 + (pixel_distance & 0x0f))); + } + for (len -= 7; len >= 255; len -= 255) { + encode(encoder, 255); + } + encode(encoder, (uint8_t)len); + encode(encoder, (uint8_t)((pixel_distance >> 4) & 255)); + } +#endif + + + /* encoding the rest of the pixel distance and the image_dist and its 2 control bits */ + + /* The first 2 MSB bits indicate how many more bytes should be read for image dist */ + if (pixel_distance < MAX_PIXEL_SHORT_DISTANCE) { + if (image_distance < SHORT_PIX_IMAGE_DIST_LEVEL_1) { +#if defined(GLZ_ENCODE_MATCH) + encode(encoder, (uint8_t)(image_distance & 0x3f)); +#elif defined(GLZ_ENCODE_SIZE) + encode_size = 3; +#endif + } else if (image_distance < SHORT_PIX_IMAGE_DIST_LEVEL_2) { +#if defined(GLZ_ENCODE_MATCH) + encode(encoder, (uint8_t)((1 << 6) + (image_distance & 0x3f))); + encode(encoder, (uint8_t)((image_distance >> 6) & 255)); +#elif defined(GLZ_ENCODE_SIZE) + encode_size = 4; +#endif + } else if (image_distance < SHORT_PIX_IMAGE_DIST_LEVEL_3) { +#if defined(GLZ_ENCODE_MATCH) + encode(encoder, (uint8_t)((1 << 7) + (image_distance & 0x3f))); + encode(encoder, (uint8_t)((image_distance >> 6) & 255)); + encode(encoder, (uint8_t)((image_distance >> 14) & 255)); +#elif defined(GLZ_ENCODE_SIZE) + encode_size = 5; +#endif + } else { +#if defined(GLZ_ENCODE_MATCH) + encode(encoder, (uint8_t)((1 << 7) + (1 << 6) + (image_distance & 0x3f))); + encode(encoder, (uint8_t)((image_distance >> 6) & 255)); + encode(encoder, (uint8_t)((image_distance >> 14) & 255)); + encode(encoder, (uint8_t)((image_distance >> 22) & 255)); +#elif defined(GLZ_ENCODE_SIZE) + encode_size = 6; +#endif + } + } else { + /* the third MSB bit indicates if the pixel_distance is medium/long*/ + uint8_t long_dist_control = (pixel_distance < MAX_PIXEL_MEDIUM_DISTANCE) ? 0 : 32; + if (image_distance == 0) { +#if defined(GLZ_ENCODE_MATCH) + encode(encoder, (uint8_t)(long_dist_control + ((pixel_distance >> 12) & 31))); +#elif defined(GLZ_ENCODE_SIZE) + encode_size = 3; +#endif + } else if (image_distance < FAR_PIX_IMAGE_DIST_LEVEL_1) { +#if defined(GLZ_ENCODE_MATCH) + encode(encoder, + (uint8_t)(long_dist_control + (1 << 6) + ((pixel_distance >> 12) & 31))); + encode(encoder, (uint8_t)(image_distance & 255)); +#elif defined(GLZ_ENCODE_SIZE) + encode_size = 4; +#endif + } else if (image_distance < FAR_PIX_IMAGE_DIST_LEVEL_2) { +#if defined(GLZ_ENCODE_MATCH) + encode(encoder, + (uint8_t)(long_dist_control + (1 << 7) + ((pixel_distance >> 12) & 31))); + encode(encoder, (uint8_t)(image_distance & 255)); + encode(encoder, (uint8_t)((image_distance >> 8) & 255)); +#elif defined(GLZ_ENCODE_SIZE) + encode_size = 5; +#endif + } else { +#if defined(GLZ_ENCODE_MATCH) + encode(encoder, + (uint8_t)(long_dist_control + (1 << 7) + (1 << 6) + + ((pixel_distance >> 12) & 31))); + encode(encoder, (uint8_t)(image_distance & 255)); + encode(encoder, (uint8_t)((image_distance >> 8) & 255)); + encode(encoder, (uint8_t)((image_distance >> 16) & 255)); +#elif defined(GLZ_ENCODE_SIZE) + encode_size = 6; +#endif + } + + if (long_dist_control) { +#if defined(GLZ_ENCODE_MATCH) + encode(encoder, (uint8_t)((pixel_distance >> 17) & 255)); +#elif defined(GLZ_ENCODE_SIZE) + encode_size++; +#endif + } + } + +#if defined(GLZ_ENCODE_SIZE) + return encode_size; +#endif +} + +#undef GLZ_ENCODE_SIZE +#undef GLZ_ENCODE_MATCH diff --git a/server/glz-encode.tmpl.c b/server/glz-encode.tmpl.c new file mode 100644 index 0000000..46dd1d4 --- /dev/null +++ b/server/glz-encode.tmpl.c @@ -0,0 +1,574 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define DJB2_START 5381 +#define DJB2_HASH(hash, c) (hash = ((hash << 5) + hash) ^ (c)) //|{hash = ((hash << 5) + hash) + c;} + +/* + For each pixel type the following macros are defined: + PIXEL : input type + FNAME(name) + ENCODE_PIXEL(encoder, pixel) : writing a pixel to the compressed buffer (byte by byte) + SAME_PIXEL(pix1, pix2) : comparing two pixels + HASH_FUNC(value, pix_ptr) : hash func of 3 consecutive pixels +*/ + +#ifdef LZ_PLT +#define PIXEL one_byte_pixel_t +#define FNAME(name) glz_plt_##name +#define ENCODE_PIXEL(e, pix) encode(e, (pix).a) // gets the pixel and write only the needed bytes + // from the pixel +#define SAME_PIXEL(pix1, pix2) ((pix1).a == (pix2).a) +#define MIN_REF_ENCODE_SIZE 4 +#define MAX_REF_ENCODE_SIZE 7 +#define HASH_FUNC(v, p) { \ + v = DJB2_START; \ + DJB2_HASH(v, p[0].a); \ + DJB2_HASH(v, p[1].a); \ + DJB2_HASH(v, p[2].a); \ + v &= HASH_MASK; \ + } +#endif + +#ifdef LZ_RGB_ALPHA +//#undef LZ_RGB_ALPHA +#define PIXEL rgb32_pixel_t +#define FNAME(name) glz_rgb_alpha_##name +#define ENCODE_PIXEL(e, pix) {encode(e, (pix).pad);} +#define SAME_PIXEL(pix1, pix2) ((pix1).pad == (pix2).pad) +#define MIN_REF_ENCODE_SIZE 4 +#define MAX_REF_ENCODE_SIZE 7 +#define HASH_FUNC(v, p) { \ + v = DJB2_START; \ + DJB2_HASH(v, p[0].pad); \ + DJB2_HASH(v, p[1].pad); \ + DJB2_HASH(v, p[2].pad); \ + v &= HASH_MASK; \ + } +#endif + + +#ifdef LZ_RGB16 +#define PIXEL rgb16_pixel_t +#define FNAME(name) glz_rgb16_##name +#define GET_r(pix) (((pix) >> 10) & 0x1f) +#define GET_g(pix) (((pix) >> 5) & 0x1f) +#define GET_b(pix) ((pix) & 0x1f) +#define ENCODE_PIXEL(e, pix) {encode(e, (pix) >> 8); encode(e, (pix) & 0xff);} +#define MIN_REF_ENCODE_SIZE 2 +#define MAX_REF_ENCODE_SIZE 3 +#define HASH_FUNC(v, p) { \ + v = DJB2_START; \ + DJB2_HASH(v, p[0] & (0x00ff)); \ + DJB2_HASH(v, (p[0] >> 8) & (0x007f)); \ + DJB2_HASH(v, p[1] & (0x00ff)); \ + DJB2_HASH(v, (p[1] >> 8) & (0x007f)); \ + DJB2_HASH(v, p[2] & (0x00ff)); \ + DJB2_HASH(v, (p[2] >> 8) & (0x007f)); \ + v &= HASH_MASK; \ +} +#endif + +#ifdef LZ_RGB24 +#define PIXEL rgb24_pixel_t +#define FNAME(name) glz_rgb24_##name +#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);} +#define MIN_REF_ENCODE_SIZE 2 +#define MAX_REF_ENCODE_SIZE 2 +#endif + +#ifdef LZ_RGB32 +#define PIXEL rgb32_pixel_t +#define FNAME(name) glz_rgb32_##name +#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);} +#define MIN_REF_ENCODE_SIZE 2 +#define MAX_REF_ENCODE_SIZE 2 +#endif + + +#if defined(LZ_RGB24) || defined(LZ_RGB32) +#define GET_r(pix) ((pix).r) +#define GET_g(pix) ((pix).g) +#define GET_b(pix) ((pix).b) +#define HASH_FUNC(v, p) { \ + v = DJB2_START; \ + DJB2_HASH(v, p[0].r); \ + DJB2_HASH(v, p[0].g); \ + DJB2_HASH(v, p[0].b); \ + DJB2_HASH(v, p[1].r); \ + DJB2_HASH(v, p[1].g); \ + DJB2_HASH(v, p[1].b); \ + DJB2_HASH(v, p[2].r); \ + DJB2_HASH(v, p[2].g); \ + DJB2_HASH(v, p[2].b); \ + v &= HASH_MASK; \ + } +#endif + +#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32) +#define SAME_PIXEL(p1, p2) (GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) && \ + GET_b(p1) == GET_b(p2)) + +#endif + +#ifndef LZ_PLT +#define PIXEL_ID(pix_ptr, seg_ptr) \ + ((pix_ptr) - ((PIXEL *)(seg_ptr)->lines) + (seg_ptr)->pixels_so_far) +#define PIXEL_DIST(src_pix_ptr, src_seg_ptr, ref_pix_ptr, ref_seg_ptr) \ + (PIXEL_ID(src_pix_ptr,src_seg_ptr) - PIXEL_ID(ref_pix_ptr, ref_seg_ptr)) +#else +#define PIXEL_ID(pix_ptr, seg_ptr, pix_per_byte) \ + (((pix_ptr) - ((PIXEL *)(seg_ptr)->lines)) * pix_per_byte + (seg_ptr)->pixels_so_far) +#define PIXEL_DIST(src_pix_ptr, src_seg_ptr, ref_pix_ptr, ref_seg_ptr, pix_per_byte) \ + ((PIXEL_ID(src_pix_ptr,src_seg_ptr, pix_per_byte) - \ + PIXEL_ID(ref_pix_ptr, ref_seg_ptr, pix_per_byte)) / pix_per_byte) +#endif + +/* returns the length of the match. 0 if no match. + if image_distance = 0, pixel_distance is the distance between the matching pixels. + Otherwise, it is the offset from the beginning of the referred image */ +static inline size_t FNAME(do_match)(SharedDictionary *dict, + WindowImageSegment *ref_seg, const PIXEL *ref, + const PIXEL *ref_limit, + WindowImageSegment *ip_seg, const PIXEL *ip, + const PIXEL *ip_limit, +#ifdef LZ_PLT + int pix_per_byte, +#endif + size_t *o_image_dist, size_t *o_pix_distance) +{ + int encode_size; + const PIXEL *tmp_ip = ip; + const PIXEL *tmp_ref = ref; + + if (ref > (ref_limit - MIN_REF_ENCODE_SIZE)) { + return 0; // in case the hash entry is not relevant + } + + + /* min match length == MIN_REF_ENCODE_SIZE (depends on pixel type) */ + + if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) { + return 0; + } else { + tmp_ref++; + tmp_ip++; + } + + + if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) { + return 0; + } else { + tmp_ref++; + tmp_ip++; + } + +#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) + if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) { + return 0; + } else { + tmp_ref++; + tmp_ip++; + } + + + if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) { + return 0; + } else { + tmp_ref++; + tmp_ip++; + } + +#endif + + + *o_image_dist = ip_seg->image->id - ref_seg->image->id; + + if (!(*o_image_dist)) { // the ref is inside the same image - encode distance +#ifndef LZ_PLT + *o_pix_distance = PIXEL_DIST(ip, ip_seg, ref, ref_seg); +#else + // in bytes + *o_pix_distance = PIXEL_DIST(ip, ip_seg, ref, ref_seg, pix_per_byte); +#endif + } else { // the ref is at different image - encode offset from the image start +#ifndef LZ_PLT + *o_pix_distance = PIXEL_DIST(ref, ref_seg, + (PIXEL *)(dict->window.segs[ref_seg->image->first_seg].lines), + &dict->window.segs[ref_seg->image->first_seg] + ); +#else + // in bytes + *o_pix_distance = PIXEL_DIST(ref, ref_seg, + (PIXEL *)(dict->window.segs[ref_seg->image->first_seg].lines), + &dict->window.segs[ref_seg->image->first_seg], + pix_per_byte); +#endif + } + + if ((*o_pix_distance == 0) || (*o_pix_distance >= MAX_PIXEL_LONG_DISTANCE) || + (*o_image_dist > MAX_IMAGE_DIST)) { + return 0; + } + + + /* continue the match*/ + while ((tmp_ip < ip_limit) && (tmp_ref < ref_limit)) { + if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) { + break; + } else { + tmp_ref++; + tmp_ip++; + } + } + + + if ((tmp_ip - ip) > MAX_REF_ENCODE_SIZE) { + return (tmp_ip - ip); + } + + encode_size = get_encode_ref_size(*o_image_dist, *o_pix_distance); + + // min number of identical pixels for a match +#if defined(LZ_RGB16) + encode_size /= 2; +#elif defined(LZ_RGB24) || defined(LZ_RGB32) + encode_size /= 3; +#endif + + encode_size++; // the minimum match + // match len is smaller than the encoding - not worth encoding + if ((tmp_ip - ip) < encode_size) { + return 0; + } + return (tmp_ip - ip); +} + +/* compresses one segment starting from 'from'. + In order to encode a match, we use pixels resolution when we encode RGB image, + and bytes count when we encode PLT. +*/ +static void FNAME(compress_seg)(Encoder *encoder, uint32_t seg_idx, PIXEL *from, int copied) +{ + WindowImageSegment *seg = &encoder->dict->window.segs[seg_idx]; + const PIXEL *ip = from; + const PIXEL *ip_bound = (PIXEL *)(seg->lines_end) - BOUND_OFFSET; + const PIXEL *ip_limit = (PIXEL *)(seg->lines_end) - LIMIT_OFFSET; + int hval; + int copy = copied; +#ifdef LZ_PLT + int pix_per_byte = PLT_PIXELS_PER_BYTE[encoder->cur_image.type]; +#endif + +#ifdef DEBUG_ENCODE + int n_encoded = 0; +#endif + + if (copy == 0) { + encode_copy_count(encoder, MAX_COPY - 1); + } + + + while (LZ_EXPECT_CONDITIONAL(ip < ip_limit)) { + const PIXEL *ref; + const PIXEL *ref_limit; + WindowImageSegment *ref_seg; + uint32_t ref_seg_idx; + size_t pix_dist; + size_t image_dist; + /* minimum match length */ + size_t len = 0; + + /* comparison starting-point */ + const PIXEL *anchor = ip; +#ifdef CHAINED_HASH + int hash_id = 0; + size_t best_len = 0; + size_t best_pix_dist = 0; + size_t best_image_dist = 0; +#endif + + /* check for a run */ + + if (LZ_EXPECT_CONDITIONAL(ip > (PIXEL *)(seg->lines))) { + if (SAME_PIXEL(ip[-1], ip[0]) && SAME_PIXEL(ip[0], ip[1]) && SAME_PIXEL(ip[1], ip[2])) { + PIXEL x; + pix_dist = 1; + image_dist = 0; + + ip += 3; + ref = anchor + 2; + ref_limit = (PIXEL *)(seg->lines_end); + len = 3; + + x = *ref; + + while (ip < ip_bound) { // TODO: maybe separate a run from the same seg or from + // different ones in order to spare ref < ref_limit + if (!SAME_PIXEL(*ip, x)) { + ip++; + break; + } else { + ip++; + len++; + } + } + + goto match; + } // END RLE MATCH + } + + /* find potential match */ + HASH_FUNC(hval, ip); + +#ifdef CHAINED_HASH + for (hash_id = 0; hash_id < HASH_CHAIN_SIZE; hash_id++) { + ref_seg_idx = encoder->dict->htab[hval][hash_id].image_seg_idx; +#else + ref_seg_idx = encoder->dict->htab[hval].image_seg_idx; +#endif + ref_seg = encoder->dict->window.segs + ref_seg_idx; + if (REF_SEG_IS_VALID(encoder->dict, encoder->id, + ref_seg, seg)) { +#ifdef CHAINED_HASH + ref = ((PIXEL *)ref_seg->lines) + encoder->dict->htab[hval][hash_id].ref_pix_idx; +#else + ref = ((PIXEL *)ref_seg->lines) + encoder->dict->htab[hval].ref_pix_idx; +#endif + ref_limit = (PIXEL *)ref_seg->lines_end; + + len = FNAME(do_match)(encoder->dict, ref_seg, ref, ref_limit, seg, ip, ip_bound, +#ifdef LZ_PLT + pix_per_byte, +#endif + &image_dist, &pix_dist); + +#ifdef CHAINED_HASH + // TODO. not compare len but rather len - encode_size + if (len > best_len) { + best_len = len; + best_pix_dist = pix_dist; + best_image_dist = image_dist; + } +#endif + } + +#ifdef CHAINED_HASH + } // end chain loop + len = best_len; + pix_dist = best_pix_dist; + image_dist = best_image_dist; +#endif + + /* update hash table */ + UPDATE_HASH(encoder->dict, hval, seg_idx, anchor - ((PIXEL *)seg->lines)); + + if (!len) { + goto literal; + } + +match: // RLE or dictionary (both are encoded by distance from ref (-1) and length) +#ifdef DEBUG_ENCODE + printf(", match(%d, %d, %d)", image_dist, pix_dist, len); + n_encoded += len; +#endif + + /* distance is biased */ + if (!image_dist) { + pix_dist--; + } + + /* if we have copied something, adjust the copy count */ + if (copy) { + /* copy is biased, '0' means 1 byte copy */ + update_copy_count(encoder, copy - 1); + } else { + /* back, to overwrite the copy count */ + compress_output_prev(encoder); + } + + /* reset literal counter */ + copy = 0; + + /* length is biased, '1' means a match of 3 pixels for PLT and alpha*/ + /* for RGB 16 1 means 2 */ + /* for RGB24/32 1 means 1...*/ + ip = anchor + len - 2; + +#if defined(LZ_RGB16) + len--; +#elif defined(LZ_PLT) || defined(LZ_RGB_ALPHA) + len -= 2; +#endif + GLZ_ASSERT(encoder->usr, len > 0); + encode_match(encoder, image_dist, pix_dist, len); + + /* update the hash at match boundary */ +#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32) + if (ip > anchor) { +#endif + HASH_FUNC(hval, ip); + UPDATE_HASH(encoder->dict, hval, seg_idx, ip - ((PIXEL *)seg->lines)); + ip++; +#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32) + } else {ip++; + } +#endif +#if defined(LZ_RGB24) || defined(LZ_RGB32) + if (ip > anchor) { +#endif + HASH_FUNC(hval, ip); + UPDATE_HASH(encoder->dict, hval, seg_idx, ip - ((PIXEL *)seg->lines)); + ip++; +#if defined(LZ_RGB24) || defined(LZ_RGB32) + } else { + ip++; + } +#endif + /* assuming literal copy */ + encode_copy_count(encoder, MAX_COPY - 1); + continue; + +literal: +#ifdef DEBUG_ENCODE + printf(", copy"); + n_encoded++; +#endif + ENCODE_PIXEL(encoder, *anchor); + anchor++; + ip = anchor; + copy++; + + if (LZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) { + copy = 0; + encode_copy_count(encoder, MAX_COPY - 1); + } + } // END LOOP (ip < ip_limit) + + + /* left-over as literal copy */ + ip_bound++; + while (ip <= ip_bound) { +#ifdef DEBUG_ENCODE + printf(", copy"); + n_encoded++; +#endif + ENCODE_PIXEL(encoder, *ip); + ip++; + copy++; + if (copy == MAX_COPY) { + copy = 0; + encode_copy_count(encoder, MAX_COPY - 1); + } + } + + /* if we have copied something, adjust the copy length */ + if (copy) { + update_copy_count(encoder, copy - 1); + } else { + compress_output_prev(encoder); + } +#ifdef DEBUG_ENCODE + printf("\ntotal encoded=%d\n", n_encoded); +#endif +} + + +/* If the file is very small, copies it. + copies the first two pixels of the first segment, and sends the segments + one by one to compress_seg. + the number of bytes compressed are stored inside encoder. */ +static void FNAME(compress)(Encoder *encoder) +{ + uint32_t seg_id = encoder->cur_image.first_win_seg; + PIXEL *ip; + SharedDictionary *dict = encoder->dict; + int hval; + + // fetch the first image segment that is not too small + while ((seg_id != NULL_IMAGE_SEG_ID) && + (dict->window.segs[seg_id].image->id == encoder->cur_image.id) && + ((((PIXEL *)dict->window.segs[seg_id].lines_end) - + ((PIXEL *)dict->window.segs[seg_id].lines)) < 4)) { + // coping the segment + if (dict->window.segs[seg_id].lines != dict->window.segs[seg_id].lines_end) { + ip = (PIXEL *)dict->window.segs[seg_id].lines; + // Note: we assume MAX_COPY > 3 + encode_copy_count(encoder, (uint8_t)( + (((PIXEL *)dict->window.segs[seg_id].lines_end) - + ((PIXEL *)dict->window.segs[seg_id].lines)) - 1)); + while (ip < (PIXEL *)dict->window.segs[seg_id].lines_end) { + ENCODE_PIXEL(encoder, *ip); + ip++; + } + } + seg_id = dict->window.segs[seg_id].next; + } + + if ((seg_id == NULL_IMAGE_SEG_ID) || + (dict->window.segs[seg_id].image->id != encoder->cur_image.id)) { + return; + } + + ip = (PIXEL *)dict->window.segs[seg_id].lines; + + + encode_copy_count(encoder, MAX_COPY - 1); + + HASH_FUNC(hval, ip); + UPDATE_HASH(encoder->dict, hval, seg_id, 0); + + ENCODE_PIXEL(encoder, *ip); + ip++; + ENCODE_PIXEL(encoder, *ip); + ip++; +#ifdef DEBUG_ENCODE + printf("copy, copy"); +#endif + // compressing the first segment + FNAME(compress_seg)(encoder, seg_id, ip, 2); + + // compressing the next segments + for (seg_id = dict->window.segs[seg_id].next; + seg_id != NULL_IMAGE_SEG_ID && ( + dict->window.segs[seg_id].image->id == encoder->cur_image.id); + seg_id = dict->window.segs[seg_id].next) { + FNAME(compress_seg)(encoder, seg_id, (PIXEL *)dict->window.segs[seg_id].lines, 0); + } +} + +#undef FNAME +#undef PIXEL_ID +#undef PIXEL_DIST +#undef PIXEL +#undef ENCODE_PIXEL +#undef SAME_PIXEL +#undef HASH_FUNC +#undef GET_r +#undef GET_g +#undef GET_b +#undef GET_CODE +#undef LZ_PLT +#undef LZ_RGB_ALPHA +#undef LZ_RGB16 +#undef LZ_RGB24 +#undef LZ_RGB32 +#undef MIN_REF_ENCODE_SIZE +#undef MAX_REF_ENCODE_SIZE diff --git a/server/glz_encode_match_tmpl.c b/server/glz_encode_match_tmpl.c deleted file mode 100644 index 1fd251e..0000000 --- a/server/glz_encode_match_tmpl.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#define SHORT_PIX_IMAGE_DIST_LEVEL_1 64 //(1 << 6) -#define SHORT_PIX_IMAGE_DIST_LEVEL_2 16384 // (1 << 14) -#define SHORT_PIX_IMAGE_DIST_LEVEL_3 4194304 // (1 << 22) -#define FAR_PIX_IMAGE_DIST_LEVEL_1 256 // (1 << 8) -#define FAR_PIX_IMAGE_DIST_LEVEL_2 65536 // (1 << 16) -#define FAR_PIX_IMAGE_DIST_LEVEL_3 16777216 // (1 << 24) - -/* if image_distance = 0, pixel_distance is the distance between the matching pixels. - Otherwise, it is the offset from the beginning of the referred image */ -#if defined(GLZ_ENCODE_MATCH) /* actually performing the encoding */ -static inline void encode_match(Encoder *encoder, uint32_t image_distance, - size_t pixel_distance, size_t len) -#elif defined(GLZ_ENCODE_SIZE) /* compute the size of the encoding except for the match length*/ -static inline int get_encode_ref_size(uint32_t image_distance, size_t pixel_distance) -#endif -{ -#if defined(GLZ_ENCODE_SIZE) - int encode_size; -#endif - -#if defined(GLZ_ENCODE_MATCH) - /* encoding the match length + Long/Short dist bit + 12 LSB pixels of pixel_distance*/ - if (len < 7) { - if (pixel_distance < MAX_PIXEL_SHORT_DISTANCE) { - encode(encoder, (uint8_t)((len << 5) + (pixel_distance & 0x0f))); - } else { - encode(encoder, (uint8_t)((len << 5) + 16 + (pixel_distance & 0x0f))); - } - encode(encoder, (uint8_t)((pixel_distance >> 4) & 255)); - } else { - if (pixel_distance < MAX_PIXEL_SHORT_DISTANCE) { - encode(encoder, (uint8_t)((7 << 5) + (pixel_distance & 0x0f))); - } else { - encode(encoder, (uint8_t)((7 << 5) + 16 + (pixel_distance & 0x0f))); - } - for (len -= 7; len >= 255; len -= 255) { - encode(encoder, 255); - } - encode(encoder, (uint8_t)len); - encode(encoder, (uint8_t)((pixel_distance >> 4) & 255)); - } -#endif - - - /* encoding the rest of the pixel distance and the image_dist and its 2 control bits */ - - /* The first 2 MSB bits indicate how many more bytes should be read for image dist */ - if (pixel_distance < MAX_PIXEL_SHORT_DISTANCE) { - if (image_distance < SHORT_PIX_IMAGE_DIST_LEVEL_1) { -#if defined(GLZ_ENCODE_MATCH) - encode(encoder, (uint8_t)(image_distance & 0x3f)); -#elif defined(GLZ_ENCODE_SIZE) - encode_size = 3; -#endif - } else if (image_distance < SHORT_PIX_IMAGE_DIST_LEVEL_2) { -#if defined(GLZ_ENCODE_MATCH) - encode(encoder, (uint8_t)((1 << 6) + (image_distance & 0x3f))); - encode(encoder, (uint8_t)((image_distance >> 6) & 255)); -#elif defined(GLZ_ENCODE_SIZE) - encode_size = 4; -#endif - } else if (image_distance < SHORT_PIX_IMAGE_DIST_LEVEL_3) { -#if defined(GLZ_ENCODE_MATCH) - encode(encoder, (uint8_t)((1 << 7) + (image_distance & 0x3f))); - encode(encoder, (uint8_t)((image_distance >> 6) & 255)); - encode(encoder, (uint8_t)((image_distance >> 14) & 255)); -#elif defined(GLZ_ENCODE_SIZE) - encode_size = 5; -#endif - } else { -#if defined(GLZ_ENCODE_MATCH) - encode(encoder, (uint8_t)((1 << 7) + (1 << 6) + (image_distance & 0x3f))); - encode(encoder, (uint8_t)((image_distance >> 6) & 255)); - encode(encoder, (uint8_t)((image_distance >> 14) & 255)); - encode(encoder, (uint8_t)((image_distance >> 22) & 255)); -#elif defined(GLZ_ENCODE_SIZE) - encode_size = 6; -#endif - } - } else { - /* the third MSB bit indicates if the pixel_distance is medium/long*/ - uint8_t long_dist_control = (pixel_distance < MAX_PIXEL_MEDIUM_DISTANCE) ? 0 : 32; - if (image_distance == 0) { -#if defined(GLZ_ENCODE_MATCH) - encode(encoder, (uint8_t)(long_dist_control + ((pixel_distance >> 12) & 31))); -#elif defined(GLZ_ENCODE_SIZE) - encode_size = 3; -#endif - } else if (image_distance < FAR_PIX_IMAGE_DIST_LEVEL_1) { -#if defined(GLZ_ENCODE_MATCH) - encode(encoder, - (uint8_t)(long_dist_control + (1 << 6) + ((pixel_distance >> 12) & 31))); - encode(encoder, (uint8_t)(image_distance & 255)); -#elif defined(GLZ_ENCODE_SIZE) - encode_size = 4; -#endif - } else if (image_distance < FAR_PIX_IMAGE_DIST_LEVEL_2) { -#if defined(GLZ_ENCODE_MATCH) - encode(encoder, - (uint8_t)(long_dist_control + (1 << 7) + ((pixel_distance >> 12) & 31))); - encode(encoder, (uint8_t)(image_distance & 255)); - encode(encoder, (uint8_t)((image_distance >> 8) & 255)); -#elif defined(GLZ_ENCODE_SIZE) - encode_size = 5; -#endif - } else { -#if defined(GLZ_ENCODE_MATCH) - encode(encoder, - (uint8_t)(long_dist_control + (1 << 7) + (1 << 6) + - ((pixel_distance >> 12) & 31))); - encode(encoder, (uint8_t)(image_distance & 255)); - encode(encoder, (uint8_t)((image_distance >> 8) & 255)); - encode(encoder, (uint8_t)((image_distance >> 16) & 255)); -#elif defined(GLZ_ENCODE_SIZE) - encode_size = 6; -#endif - } - - if (long_dist_control) { -#if defined(GLZ_ENCODE_MATCH) - encode(encoder, (uint8_t)((pixel_distance >> 17) & 255)); -#elif defined(GLZ_ENCODE_SIZE) - encode_size++; -#endif - } - } - -#if defined(GLZ_ENCODE_SIZE) - return encode_size; -#endif -} - -#undef GLZ_ENCODE_SIZE -#undef GLZ_ENCODE_MATCH diff --git a/server/glz_encode_tmpl.c b/server/glz_encode_tmpl.c deleted file mode 100644 index 46dd1d4..0000000 --- a/server/glz_encode_tmpl.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#define DJB2_START 5381 -#define DJB2_HASH(hash, c) (hash = ((hash << 5) + hash) ^ (c)) //|{hash = ((hash << 5) + hash) + c;} - -/* - For each pixel type the following macros are defined: - PIXEL : input type - FNAME(name) - ENCODE_PIXEL(encoder, pixel) : writing a pixel to the compressed buffer (byte by byte) - SAME_PIXEL(pix1, pix2) : comparing two pixels - HASH_FUNC(value, pix_ptr) : hash func of 3 consecutive pixels -*/ - -#ifdef LZ_PLT -#define PIXEL one_byte_pixel_t -#define FNAME(name) glz_plt_##name -#define ENCODE_PIXEL(e, pix) encode(e, (pix).a) // gets the pixel and write only the needed bytes - // from the pixel -#define SAME_PIXEL(pix1, pix2) ((pix1).a == (pix2).a) -#define MIN_REF_ENCODE_SIZE 4 -#define MAX_REF_ENCODE_SIZE 7 -#define HASH_FUNC(v, p) { \ - v = DJB2_START; \ - DJB2_HASH(v, p[0].a); \ - DJB2_HASH(v, p[1].a); \ - DJB2_HASH(v, p[2].a); \ - v &= HASH_MASK; \ - } -#endif - -#ifdef LZ_RGB_ALPHA -//#undef LZ_RGB_ALPHA -#define PIXEL rgb32_pixel_t -#define FNAME(name) glz_rgb_alpha_##name -#define ENCODE_PIXEL(e, pix) {encode(e, (pix).pad);} -#define SAME_PIXEL(pix1, pix2) ((pix1).pad == (pix2).pad) -#define MIN_REF_ENCODE_SIZE 4 -#define MAX_REF_ENCODE_SIZE 7 -#define HASH_FUNC(v, p) { \ - v = DJB2_START; \ - DJB2_HASH(v, p[0].pad); \ - DJB2_HASH(v, p[1].pad); \ - DJB2_HASH(v, p[2].pad); \ - v &= HASH_MASK; \ - } -#endif - - -#ifdef LZ_RGB16 -#define PIXEL rgb16_pixel_t -#define FNAME(name) glz_rgb16_##name -#define GET_r(pix) (((pix) >> 10) & 0x1f) -#define GET_g(pix) (((pix) >> 5) & 0x1f) -#define GET_b(pix) ((pix) & 0x1f) -#define ENCODE_PIXEL(e, pix) {encode(e, (pix) >> 8); encode(e, (pix) & 0xff);} -#define MIN_REF_ENCODE_SIZE 2 -#define MAX_REF_ENCODE_SIZE 3 -#define HASH_FUNC(v, p) { \ - v = DJB2_START; \ - DJB2_HASH(v, p[0] & (0x00ff)); \ - DJB2_HASH(v, (p[0] >> 8) & (0x007f)); \ - DJB2_HASH(v, p[1] & (0x00ff)); \ - DJB2_HASH(v, (p[1] >> 8) & (0x007f)); \ - DJB2_HASH(v, p[2] & (0x00ff)); \ - DJB2_HASH(v, (p[2] >> 8) & (0x007f)); \ - v &= HASH_MASK; \ -} -#endif - -#ifdef LZ_RGB24 -#define PIXEL rgb24_pixel_t -#define FNAME(name) glz_rgb24_##name -#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);} -#define MIN_REF_ENCODE_SIZE 2 -#define MAX_REF_ENCODE_SIZE 2 -#endif - -#ifdef LZ_RGB32 -#define PIXEL rgb32_pixel_t -#define FNAME(name) glz_rgb32_##name -#define ENCODE_PIXEL(e, pix) {encode(e, (pix).b); encode(e, (pix).g); encode(e, (pix).r);} -#define MIN_REF_ENCODE_SIZE 2 -#define MAX_REF_ENCODE_SIZE 2 -#endif - - -#if defined(LZ_RGB24) || defined(LZ_RGB32) -#define GET_r(pix) ((pix).r) -#define GET_g(pix) ((pix).g) -#define GET_b(pix) ((pix).b) -#define HASH_FUNC(v, p) { \ - v = DJB2_START; \ - DJB2_HASH(v, p[0].r); \ - DJB2_HASH(v, p[0].g); \ - DJB2_HASH(v, p[0].b); \ - DJB2_HASH(v, p[1].r); \ - DJB2_HASH(v, p[1].g); \ - DJB2_HASH(v, p[1].b); \ - DJB2_HASH(v, p[2].r); \ - DJB2_HASH(v, p[2].g); \ - DJB2_HASH(v, p[2].b); \ - v &= HASH_MASK; \ - } -#endif - -#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32) -#define SAME_PIXEL(p1, p2) (GET_r(p1) == GET_r(p2) && GET_g(p1) == GET_g(p2) && \ - GET_b(p1) == GET_b(p2)) - -#endif - -#ifndef LZ_PLT -#define PIXEL_ID(pix_ptr, seg_ptr) \ - ((pix_ptr) - ((PIXEL *)(seg_ptr)->lines) + (seg_ptr)->pixels_so_far) -#define PIXEL_DIST(src_pix_ptr, src_seg_ptr, ref_pix_ptr, ref_seg_ptr) \ - (PIXEL_ID(src_pix_ptr,src_seg_ptr) - PIXEL_ID(ref_pix_ptr, ref_seg_ptr)) -#else -#define PIXEL_ID(pix_ptr, seg_ptr, pix_per_byte) \ - (((pix_ptr) - ((PIXEL *)(seg_ptr)->lines)) * pix_per_byte + (seg_ptr)->pixels_so_far) -#define PIXEL_DIST(src_pix_ptr, src_seg_ptr, ref_pix_ptr, ref_seg_ptr, pix_per_byte) \ - ((PIXEL_ID(src_pix_ptr,src_seg_ptr, pix_per_byte) - \ - PIXEL_ID(ref_pix_ptr, ref_seg_ptr, pix_per_byte)) / pix_per_byte) -#endif - -/* returns the length of the match. 0 if no match. - if image_distance = 0, pixel_distance is the distance between the matching pixels. - Otherwise, it is the offset from the beginning of the referred image */ -static inline size_t FNAME(do_match)(SharedDictionary *dict, - WindowImageSegment *ref_seg, const PIXEL *ref, - const PIXEL *ref_limit, - WindowImageSegment *ip_seg, const PIXEL *ip, - const PIXEL *ip_limit, -#ifdef LZ_PLT - int pix_per_byte, -#endif - size_t *o_image_dist, size_t *o_pix_distance) -{ - int encode_size; - const PIXEL *tmp_ip = ip; - const PIXEL *tmp_ref = ref; - - if (ref > (ref_limit - MIN_REF_ENCODE_SIZE)) { - return 0; // in case the hash entry is not relevant - } - - - /* min match length == MIN_REF_ENCODE_SIZE (depends on pixel type) */ - - if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) { - return 0; - } else { - tmp_ref++; - tmp_ip++; - } - - - if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) { - return 0; - } else { - tmp_ref++; - tmp_ip++; - } - -#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) - if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) { - return 0; - } else { - tmp_ref++; - tmp_ip++; - } - - - if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) { - return 0; - } else { - tmp_ref++; - tmp_ip++; - } - -#endif - - - *o_image_dist = ip_seg->image->id - ref_seg->image->id; - - if (!(*o_image_dist)) { // the ref is inside the same image - encode distance -#ifndef LZ_PLT - *o_pix_distance = PIXEL_DIST(ip, ip_seg, ref, ref_seg); -#else - // in bytes - *o_pix_distance = PIXEL_DIST(ip, ip_seg, ref, ref_seg, pix_per_byte); -#endif - } else { // the ref is at different image - encode offset from the image start -#ifndef LZ_PLT - *o_pix_distance = PIXEL_DIST(ref, ref_seg, - (PIXEL *)(dict->window.segs[ref_seg->image->first_seg].lines), - &dict->window.segs[ref_seg->image->first_seg] - ); -#else - // in bytes - *o_pix_distance = PIXEL_DIST(ref, ref_seg, - (PIXEL *)(dict->window.segs[ref_seg->image->first_seg].lines), - &dict->window.segs[ref_seg->image->first_seg], - pix_per_byte); -#endif - } - - if ((*o_pix_distance == 0) || (*o_pix_distance >= MAX_PIXEL_LONG_DISTANCE) || - (*o_image_dist > MAX_IMAGE_DIST)) { - return 0; - } - - - /* continue the match*/ - while ((tmp_ip < ip_limit) && (tmp_ref < ref_limit)) { - if (!SAME_PIXEL(*tmp_ref, *tmp_ip)) { - break; - } else { - tmp_ref++; - tmp_ip++; - } - } - - - if ((tmp_ip - ip) > MAX_REF_ENCODE_SIZE) { - return (tmp_ip - ip); - } - - encode_size = get_encode_ref_size(*o_image_dist, *o_pix_distance); - - // min number of identical pixels for a match -#if defined(LZ_RGB16) - encode_size /= 2; -#elif defined(LZ_RGB24) || defined(LZ_RGB32) - encode_size /= 3; -#endif - - encode_size++; // the minimum match - // match len is smaller than the encoding - not worth encoding - if ((tmp_ip - ip) < encode_size) { - return 0; - } - return (tmp_ip - ip); -} - -/* compresses one segment starting from 'from'. - In order to encode a match, we use pixels resolution when we encode RGB image, - and bytes count when we encode PLT. -*/ -static void FNAME(compress_seg)(Encoder *encoder, uint32_t seg_idx, PIXEL *from, int copied) -{ - WindowImageSegment *seg = &encoder->dict->window.segs[seg_idx]; - const PIXEL *ip = from; - const PIXEL *ip_bound = (PIXEL *)(seg->lines_end) - BOUND_OFFSET; - const PIXEL *ip_limit = (PIXEL *)(seg->lines_end) - LIMIT_OFFSET; - int hval; - int copy = copied; -#ifdef LZ_PLT - int pix_per_byte = PLT_PIXELS_PER_BYTE[encoder->cur_image.type]; -#endif - -#ifdef DEBUG_ENCODE - int n_encoded = 0; -#endif - - if (copy == 0) { - encode_copy_count(encoder, MAX_COPY - 1); - } - - - while (LZ_EXPECT_CONDITIONAL(ip < ip_limit)) { - const PIXEL *ref; - const PIXEL *ref_limit; - WindowImageSegment *ref_seg; - uint32_t ref_seg_idx; - size_t pix_dist; - size_t image_dist; - /* minimum match length */ - size_t len = 0; - - /* comparison starting-point */ - const PIXEL *anchor = ip; -#ifdef CHAINED_HASH - int hash_id = 0; - size_t best_len = 0; - size_t best_pix_dist = 0; - size_t best_image_dist = 0; -#endif - - /* check for a run */ - - if (LZ_EXPECT_CONDITIONAL(ip > (PIXEL *)(seg->lines))) { - if (SAME_PIXEL(ip[-1], ip[0]) && SAME_PIXEL(ip[0], ip[1]) && SAME_PIXEL(ip[1], ip[2])) { - PIXEL x; - pix_dist = 1; - image_dist = 0; - - ip += 3; - ref = anchor + 2; - ref_limit = (PIXEL *)(seg->lines_end); - len = 3; - - x = *ref; - - while (ip < ip_bound) { // TODO: maybe separate a run from the same seg or from - // different ones in order to spare ref < ref_limit - if (!SAME_PIXEL(*ip, x)) { - ip++; - break; - } else { - ip++; - len++; - } - } - - goto match; - } // END RLE MATCH - } - - /* find potential match */ - HASH_FUNC(hval, ip); - -#ifdef CHAINED_HASH - for (hash_id = 0; hash_id < HASH_CHAIN_SIZE; hash_id++) { - ref_seg_idx = encoder->dict->htab[hval][hash_id].image_seg_idx; -#else - ref_seg_idx = encoder->dict->htab[hval].image_seg_idx; -#endif - ref_seg = encoder->dict->window.segs + ref_seg_idx; - if (REF_SEG_IS_VALID(encoder->dict, encoder->id, - ref_seg, seg)) { -#ifdef CHAINED_HASH - ref = ((PIXEL *)ref_seg->lines) + encoder->dict->htab[hval][hash_id].ref_pix_idx; -#else - ref = ((PIXEL *)ref_seg->lines) + encoder->dict->htab[hval].ref_pix_idx; -#endif - ref_limit = (PIXEL *)ref_seg->lines_end; - - len = FNAME(do_match)(encoder->dict, ref_seg, ref, ref_limit, seg, ip, ip_bound, -#ifdef LZ_PLT - pix_per_byte, -#endif - &image_dist, &pix_dist); - -#ifdef CHAINED_HASH - // TODO. not compare len but rather len - encode_size - if (len > best_len) { - best_len = len; - best_pix_dist = pix_dist; - best_image_dist = image_dist; - } -#endif - } - -#ifdef CHAINED_HASH - } // end chain loop - len = best_len; - pix_dist = best_pix_dist; - image_dist = best_image_dist; -#endif - - /* update hash table */ - UPDATE_HASH(encoder->dict, hval, seg_idx, anchor - ((PIXEL *)seg->lines)); - - if (!len) { - goto literal; - } - -match: // RLE or dictionary (both are encoded by distance from ref (-1) and length) -#ifdef DEBUG_ENCODE - printf(", match(%d, %d, %d)", image_dist, pix_dist, len); - n_encoded += len; -#endif - - /* distance is biased */ - if (!image_dist) { - pix_dist--; - } - - /* if we have copied something, adjust the copy count */ - if (copy) { - /* copy is biased, '0' means 1 byte copy */ - update_copy_count(encoder, copy - 1); - } else { - /* back, to overwrite the copy count */ - compress_output_prev(encoder); - } - - /* reset literal counter */ - copy = 0; - - /* length is biased, '1' means a match of 3 pixels for PLT and alpha*/ - /* for RGB 16 1 means 2 */ - /* for RGB24/32 1 means 1...*/ - ip = anchor + len - 2; - -#if defined(LZ_RGB16) - len--; -#elif defined(LZ_PLT) || defined(LZ_RGB_ALPHA) - len -= 2; -#endif - GLZ_ASSERT(encoder->usr, len > 0); - encode_match(encoder, image_dist, pix_dist, len); - - /* update the hash at match boundary */ -#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32) - if (ip > anchor) { -#endif - HASH_FUNC(hval, ip); - UPDATE_HASH(encoder->dict, hval, seg_idx, ip - ((PIXEL *)seg->lines)); - ip++; -#if defined(LZ_RGB16) || defined(LZ_RGB24) || defined(LZ_RGB32) - } else {ip++; - } -#endif -#if defined(LZ_RGB24) || defined(LZ_RGB32) - if (ip > anchor) { -#endif - HASH_FUNC(hval, ip); - UPDATE_HASH(encoder->dict, hval, seg_idx, ip - ((PIXEL *)seg->lines)); - ip++; -#if defined(LZ_RGB24) || defined(LZ_RGB32) - } else { - ip++; - } -#endif - /* assuming literal copy */ - encode_copy_count(encoder, MAX_COPY - 1); - continue; - -literal: -#ifdef DEBUG_ENCODE - printf(", copy"); - n_encoded++; -#endif - ENCODE_PIXEL(encoder, *anchor); - anchor++; - ip = anchor; - copy++; - - if (LZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) { - copy = 0; - encode_copy_count(encoder, MAX_COPY - 1); - } - } // END LOOP (ip < ip_limit) - - - /* left-over as literal copy */ - ip_bound++; - while (ip <= ip_bound) { -#ifdef DEBUG_ENCODE - printf(", copy"); - n_encoded++; -#endif - ENCODE_PIXEL(encoder, *ip); - ip++; - copy++; - if (copy == MAX_COPY) { - copy = 0; - encode_copy_count(encoder, MAX_COPY - 1); - } - } - - /* if we have copied something, adjust the copy length */ - if (copy) { - update_copy_count(encoder, copy - 1); - } else { - compress_output_prev(encoder); - } -#ifdef DEBUG_ENCODE - printf("\ntotal encoded=%d\n", n_encoded); -#endif -} - - -/* If the file is very small, copies it. - copies the first two pixels of the first segment, and sends the segments - one by one to compress_seg. - the number of bytes compressed are stored inside encoder. */ -static void FNAME(compress)(Encoder *encoder) -{ - uint32_t seg_id = encoder->cur_image.first_win_seg; - PIXEL *ip; - SharedDictionary *dict = encoder->dict; - int hval; - - // fetch the first image segment that is not too small - while ((seg_id != NULL_IMAGE_SEG_ID) && - (dict->window.segs[seg_id].image->id == encoder->cur_image.id) && - ((((PIXEL *)dict->window.segs[seg_id].lines_end) - - ((PIXEL *)dict->window.segs[seg_id].lines)) < 4)) { - // coping the segment - if (dict->window.segs[seg_id].lines != dict->window.segs[seg_id].lines_end) { - ip = (PIXEL *)dict->window.segs[seg_id].lines; - // Note: we assume MAX_COPY > 3 - encode_copy_count(encoder, (uint8_t)( - (((PIXEL *)dict->window.segs[seg_id].lines_end) - - ((PIXEL *)dict->window.segs[seg_id].lines)) - 1)); - while (ip < (PIXEL *)dict->window.segs[seg_id].lines_end) { - ENCODE_PIXEL(encoder, *ip); - ip++; - } - } - seg_id = dict->window.segs[seg_id].next; - } - - if ((seg_id == NULL_IMAGE_SEG_ID) || - (dict->window.segs[seg_id].image->id != encoder->cur_image.id)) { - return; - } - - ip = (PIXEL *)dict->window.segs[seg_id].lines; - - - encode_copy_count(encoder, MAX_COPY - 1); - - HASH_FUNC(hval, ip); - UPDATE_HASH(encoder->dict, hval, seg_id, 0); - - ENCODE_PIXEL(encoder, *ip); - ip++; - ENCODE_PIXEL(encoder, *ip); - ip++; -#ifdef DEBUG_ENCODE - printf("copy, copy"); -#endif - // compressing the first segment - FNAME(compress_seg)(encoder, seg_id, ip, 2); - - // compressing the next segments - for (seg_id = dict->window.segs[seg_id].next; - seg_id != NULL_IMAGE_SEG_ID && ( - dict->window.segs[seg_id].image->id == encoder->cur_image.id); - seg_id = dict->window.segs[seg_id].next) { - FNAME(compress_seg)(encoder, seg_id, (PIXEL *)dict->window.segs[seg_id].lines, 0); - } -} - -#undef FNAME -#undef PIXEL_ID -#undef PIXEL_DIST -#undef PIXEL -#undef ENCODE_PIXEL -#undef SAME_PIXEL -#undef HASH_FUNC -#undef GET_r -#undef GET_g -#undef GET_b -#undef GET_CODE -#undef LZ_PLT -#undef LZ_RGB_ALPHA -#undef LZ_RGB16 -#undef LZ_RGB24 -#undef LZ_RGB32 -#undef MIN_REF_ENCODE_SIZE -#undef MAX_REF_ENCODE_SIZE diff --git a/server/glz_encoder.c b/server/glz_encoder.c index d9d6be1..65f4478 100644 --- a/server/glz_encoder.c +++ b/server/glz_encoder.c @@ -203,24 +203,24 @@ typedef uint16_t rgb16_pixel_t; #define GLZ_ENCODE_SIZE -#include "glz_encode_match_tmpl.c" +#include "glz-encode-match.tmpl.c" #define GLZ_ENCODE_MATCH -#include "glz_encode_match_tmpl.c" +#include "glz-encode-match.tmpl.c" #define LZ_PLT -#include "glz_encode_tmpl.c" +#include "glz-encode.tmpl.c" #define LZ_RGB16 -#include "glz_encode_tmpl.c" +#include "glz-encode.tmpl.c" #define LZ_RGB24 -#include "glz_encode_tmpl.c" +#include "glz-encode.tmpl.c" #define LZ_RGB32 -#include "glz_encode_tmpl.c" +#include "glz-encode.tmpl.c" #define LZ_RGB_ALPHA -#include "glz_encode_tmpl.c" +#include "glz-encode.tmpl.c" int glz_encode(GlzEncoderContext *opaque_encoder, diff --git a/server/red_bitmap_utils_tmpl.c b/server/red_bitmap_utils_tmpl.c deleted file mode 100644 index 35f8227..0000000 --- a/server/red_bitmap_utils_tmpl.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef RED_BITMAP_UTILS_RGB16 -#define PIXEL rgb16_pixel_t -#define FNAME(name) name##_rgb16 -#define GET_r(pix) (((pix) >> 10) & 0x1f) -#define GET_g(pix) (((pix) >> 5) & 0x1f) -#define GET_b(pix) ((pix) & 0x1f) -#endif - -#if defined(RED_BITMAP_UTILS_RGB24) || defined(RED_BITMAP_UTILS_RGB32) -#define GET_r(pix) ((pix).r) -#define GET_g(pix) ((pix).g) -#define GET_b(pix) ((pix).b) -#endif - -#ifdef RED_BITMAP_UTILS_RGB24 -#define PIXEL rgb24_pixel_t -#define FNAME(name) name##_rgb24 -#endif - -#ifdef RED_BITMAP_UTILS_RGB32 -#define PIXEL rgb32_pixel_t -#define FNAME(name) name##_rgb32 -#endif - - -#define SAME_PIXEL_WEIGHT 0.5 -#define NOT_CONTRAST_PIXELS_WEIGHT -0.25 -#define CONTRAST_PIXELS_WEIGHT 1.0 - -#ifndef RED_BITMAP_UTILS_RGB16 -#define CONTRAST_TH 60 -#else -#define CONTRAST_TH 8 -#endif -#define CONTRASTING(n) ((n) <= -CONTRAST_TH || (n) >= CONTRAST_TH) - - -#define SAMPLE_JUMP 15 - -static const double FNAME(PIX_PAIR_SCORE)[] = { - SAME_PIXEL_WEIGHT, - CONTRAST_PIXELS_WEIGHT, - NOT_CONTRAST_PIXELS_WEIGHT, -}; - -// return 0 - equal, 1 - for contrast, 2 for no contrast (PIX_PAIR_SCORE is defined accordingly) -static inline int FNAME(pixelcmp)(PIXEL p1, PIXEL p2) -{ - int diff, any_different; - - diff = GET_r(p1) - GET_r(p2); - any_different = diff; - if (CONTRASTING(diff)) { - return 1; - } - - diff = GET_g(p1) - GET_g(p2); - any_different |= diff; - if (CONTRASTING(diff)) { - return 1; - } - - diff = GET_b(p1) - GET_b(p2); - any_different |= diff; - if (CONTRASTING(diff)) { - return 1; - } - - if (!any_different) { - return 0; - } else { - return 2; - } -} - -static inline double FNAME(pixels_square_score)(PIXEL *line1, PIXEL *line2) -{ - double ret; - int any_different = 0; - int cmp_res; - cmp_res = FNAME(pixelcmp)(*line1, line1[1]); - any_different |= cmp_res; - ret = FNAME(PIX_PAIR_SCORE)[cmp_res]; - cmp_res = FNAME(pixelcmp)(*line1, *line2); - any_different |= cmp_res; - ret += FNAME(PIX_PAIR_SCORE)[cmp_res]; - cmp_res = FNAME(pixelcmp)(*line1, line2[1]); - any_different |= cmp_res; - ret += FNAME(PIX_PAIR_SCORE)[cmp_res]; - - // ignore squares where all pixels are identical - if (!any_different) { - ret = 0; - } - - return ret; -} - -static void FNAME(compute_lines_gradual_score)(PIXEL *lines, int width, int num_lines, - double *o_samples_sum_score, int *o_num_samples) -{ - int jump = (SAMPLE_JUMP % width) ? SAMPLE_JUMP : SAMPLE_JUMP - 1; - PIXEL *cur_pix = lines + width / 2; - PIXEL *bottom_pix; - PIXEL *last_line = lines + (num_lines - 1) * width; - - if ((width <= 1) || (num_lines <= 1)) { - *o_num_samples = 1; - *o_samples_sum_score = 1.0; - return; - } - - *o_samples_sum_score = 0; - *o_num_samples = 0; - - while (cur_pix < last_line) { - if ((cur_pix + 1 - lines) % width == 0) { // last pixel in the row - cur_pix--; // jump is bigger than 1 so we will not enter endless loop - } - bottom_pix = cur_pix + width; - (*o_samples_sum_score) += FNAME(pixels_square_score)(cur_pix, bottom_pix); - (*o_num_samples)++; - cur_pix += jump; - } - - (*o_num_samples) *= 3; -} - -#undef PIXEL -#undef FNAME -#undef GET_r -#undef GET_g -#undef GET_b -#undef RED_BITMAP_UTILS_RGB16 -#undef RED_BITMAP_UTILS_RGB24 -#undef RED_BITMAP_UTILS_RGB32 -#undef SAMPLE_JUMP -#undef CONTRAST_TH -#undef SAME_PIXEL_WEIGHT -#undef NOT_CONTRAST_PIXELS_WEIGHT diff --git a/server/spice-bitmap-utils.c b/server/spice-bitmap-utils.c index c4ec625..03d7694 100644 --- a/server/spice-bitmap-utils.c +++ b/server/spice-bitmap-utils.c @@ -21,11 +21,11 @@ #include "spice-bitmap-utils.h" #define RED_BITMAP_UTILS_RGB16 -#include "red_bitmap_utils_tmpl.c" +#include "spice-bitmap-utils.tmpl.c" #define RED_BITMAP_UTILS_RGB24 -#include "red_bitmap_utils_tmpl.c" +#include "spice-bitmap-utils.tmpl.c" #define RED_BITMAP_UTILS_RGB32 -#include "red_bitmap_utils_tmpl.c" +#include "spice-bitmap-utils.tmpl.c" #define GRADUAL_HIGH_RGB24_TH -0.03 #define GRADUAL_HIGH_RGB16_TH 0 diff --git a/server/spice-bitmap-utils.tmpl.c b/server/spice-bitmap-utils.tmpl.c new file mode 100644 index 0000000..35f8227 --- /dev/null +++ b/server/spice-bitmap-utils.tmpl.c @@ -0,0 +1,160 @@ +/* + Copyright (C) 2009 Red Hat, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef RED_BITMAP_UTILS_RGB16 +#define PIXEL rgb16_pixel_t +#define FNAME(name) name##_rgb16 +#define GET_r(pix) (((pix) >> 10) & 0x1f) +#define GET_g(pix) (((pix) >> 5) & 0x1f) +#define GET_b(pix) ((pix) & 0x1f) +#endif + +#if defined(RED_BITMAP_UTILS_RGB24) || defined(RED_BITMAP_UTILS_RGB32) +#define GET_r(pix) ((pix).r) +#define GET_g(pix) ((pix).g) +#define GET_b(pix) ((pix).b) +#endif + +#ifdef RED_BITMAP_UTILS_RGB24 +#define PIXEL rgb24_pixel_t +#define FNAME(name) name##_rgb24 +#endif + +#ifdef RED_BITMAP_UTILS_RGB32 +#define PIXEL rgb32_pixel_t +#define FNAME(name) name##_rgb32 +#endif + + +#define SAME_PIXEL_WEIGHT 0.5 +#define NOT_CONTRAST_PIXELS_WEIGHT -0.25 +#define CONTRAST_PIXELS_WEIGHT 1.0 + +#ifndef RED_BITMAP_UTILS_RGB16 +#define CONTRAST_TH 60 +#else +#define CONTRAST_TH 8 +#endif +#define CONTRASTING(n) ((n) <= -CONTRAST_TH || (n) >= CONTRAST_TH) + + +#define SAMPLE_JUMP 15 + +static const double FNAME(PIX_PAIR_SCORE)[] = { + SAME_PIXEL_WEIGHT, + CONTRAST_PIXELS_WEIGHT, + NOT_CONTRAST_PIXELS_WEIGHT, +}; + +// return 0 - equal, 1 - for contrast, 2 for no contrast (PIX_PAIR_SCORE is defined accordingly) +static inline int FNAME(pixelcmp)(PIXEL p1, PIXEL p2) +{ + int diff, any_different; + + diff = GET_r(p1) - GET_r(p2); + any_different = diff; + if (CONTRASTING(diff)) { + return 1; + } + + diff = GET_g(p1) - GET_g(p2); + any_different |= diff; + if (CONTRASTING(diff)) { + return 1; + } + + diff = GET_b(p1) - GET_b(p2); + any_different |= diff; + if (CONTRASTING(diff)) { + return 1; + } + + if (!any_different) { + return 0; + } else { + return 2; + } +} + +static inline double FNAME(pixels_square_score)(PIXEL *line1, PIXEL *line2) +{ + double ret; + int any_different = 0; + int cmp_res; + cmp_res = FNAME(pixelcmp)(*line1, line1[1]); + any_different |= cmp_res; + ret = FNAME(PIX_PAIR_SCORE)[cmp_res]; + cmp_res = FNAME(pixelcmp)(*line1, *line2); + any_different |= cmp_res; + ret += FNAME(PIX_PAIR_SCORE)[cmp_res]; + cmp_res = FNAME(pixelcmp)(*line1, line2[1]); + any_different |= cmp_res; + ret += FNAME(PIX_PAIR_SCORE)[cmp_res]; + + // ignore squares where all pixels are identical + if (!any_different) { + ret = 0; + } + + return ret; +} + +static void FNAME(compute_lines_gradual_score)(PIXEL *lines, int width, int num_lines, + double *o_samples_sum_score, int *o_num_samples) +{ + int jump = (SAMPLE_JUMP % width) ? SAMPLE_JUMP : SAMPLE_JUMP - 1; + PIXEL *cur_pix = lines + width / 2; + PIXEL *bottom_pix; + PIXEL *last_line = lines + (num_lines - 1) * width; + + if ((width <= 1) || (num_lines <= 1)) { + *o_num_samples = 1; + *o_samples_sum_score = 1.0; + return; + } + + *o_samples_sum_score = 0; + *o_num_samples = 0; + + while (cur_pix < last_line) { + if ((cur_pix + 1 - lines) % width == 0) { // last pixel in the row + cur_pix--; // jump is bigger than 1 so we will not enter endless loop + } + bottom_pix = cur_pix + width; + (*o_samples_sum_score) += FNAME(pixels_square_score)(cur_pix, bottom_pix); + (*o_num_samples)++; + cur_pix += jump; + } + + (*o_num_samples) *= 3; +} + +#undef PIXEL +#undef FNAME +#undef GET_r +#undef GET_g +#undef GET_b +#undef RED_BITMAP_UTILS_RGB16 +#undef RED_BITMAP_UTILS_RGB24 +#undef RED_BITMAP_UTILS_RGB32 +#undef SAMPLE_JUMP +#undef CONTRAST_TH +#undef SAME_PIXEL_WEIGHT +#undef NOT_CONTRAST_PIXELS_WEIGHT -- 2.4.3 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel