summaryrefslogtreecommitdiffstats
path: root/client/glz_decoder.cpp
diff options
context:
space:
mode:
authorYaniv Kamay <ykamay@redhat.com>2009-09-19 21:25:46 +0300
committerYaniv Kamay <ykamay@redhat.com>2009-10-14 15:06:41 +0200
commitc1b79eb035fa158fb2ac3bc8e559809611070016 (patch)
tree3348dd749a700dedf87c9b16fe8be77c62928df8 /client/glz_decoder.cpp
downloadspice-c1b79eb035fa158fb2ac3bc8e559809611070016.tar.gz
spice-c1b79eb035fa158fb2ac3bc8e559809611070016.tar.xz
spice-c1b79eb035fa158fb2ac3bc8e559809611070016.zip
fresh start
Diffstat (limited to 'client/glz_decoder.cpp')
-rw-r--r--client/glz_decoder.cpp290
1 files changed, 290 insertions, 0 deletions
diff --git a/client/glz_decoder.cpp b/client/glz_decoder.cpp
new file mode 100644
index 00000000..d5f5970d
--- /dev/null
+++ b/client/glz_decoder.cpp
@@ -0,0 +1,290 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "common.h"
+#include "glz_decoder_config.h"
+#include "glz_decoder.h"
+
+GlzDecoder::GlzDecoder(GlzDecoderWindow &images_window,
+ GlzDecodeHandler &usr_handler, GlzDecoderDebug &debug_calls)
+ : _images_window (images_window)
+ , _usr_handler (usr_handler)
+ , _debug_calls (debug_calls)
+{
+}
+
+GlzDecoder::~GlzDecoder()
+{
+}
+
+void GlzDecoder::decode_header()
+{
+ int magic;
+ int version;
+ uint8_t tmp;
+ int stride;
+
+ magic = decode_32();
+ if (magic != LZ_MAGIC) {
+ _debug_calls.warn(std::string("bad magic\n"));
+ }
+
+ version = decode_32();
+ if (version != LZ_VERSION) {
+ _debug_calls.warn(std::string("bad version\n"));
+ }
+
+ tmp = *(_in_now++);
+
+ _image.type = (LzImageType)(tmp & LZ_IMAGE_TYPE_MASK);
+ _image.top_down = (tmp >> LZ_IMAGE_TYPE_LOG) ? true : false;
+ _image.width = decode_32();
+ _image.height = decode_32();
+ stride = decode_32();
+
+ if (IS_IMAGE_TYPE_PLT[_image.type]) {
+ _image.gross_pixels = stride * PLT_PIXELS_PER_BYTE[_image.type] * _image.height;
+ } else {
+ _image.gross_pixels = _image.width * _image.height;
+ }
+
+ _image.id = decode_64();
+ _image.win_head_dist = decode_32();
+}
+
+inline uint32_t GlzDecoder::decode_32()
+{
+ uint32_t word = 0;
+ word |= *(_in_now++);
+ word <<= 8;
+ word |= *(_in_now++);
+ word <<= 8;
+ word |= *(_in_now++);
+ word <<= 8;
+ word |= *(_in_now++);
+ return word;
+}
+
+inline uint64_t GlzDecoder::decode_64()
+{
+ uint64_t long_word = decode_32();
+ long_word <<= 32;
+ long_word |= decode_32();
+ return long_word;
+}
+
+// TODO: the code is historically c based. Consider transforming to c++ and use templates
+// - but be sure it won't make it slower!
+
+/*
+ * Give hints to the compiler for branch prediction optimization.
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2)
+#define LZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
+#define LZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
+#else
+#define LZ_EXPECT_CONDITIONAL(c) (c)
+#define LZ_UNEXPECT_CONDITIONAL(c) (c)
+#endif
+
+
+#ifdef __GNUC__
+#define ATTR_PACKED __attribute__ ((__packed__))
+#else
+#define ATTR_PACKED
+#pragma pack(push)
+#pragma pack(1)
+#endif
+
+
+/* the palette images will be treated as one byte pixels. Their width should be transformed
+ accordingly.
+*/
+typedef struct ATTR_PACKED one_byte_pixel_t {
+ uint8_t a;
+} one_byte_pixel_t;
+
+typedef struct ATTR_PACKED rgb32_pixel_t {
+ uint8_t b;
+ uint8_t g;
+ uint8_t r;
+ uint8_t pad;
+} rgb32_pixel_t;
+
+typedef struct ATTR_PACKED rgb24_pixel_t {
+ uint8_t b;
+ uint8_t g;
+ uint8_t r;
+} rgb24_pixel_t;
+
+typedef uint16_t rgb16_pixel_t;
+
+#ifndef __GNUC__
+#pragma pack(pop)
+#endif
+
+#undef ATTR_PACKED
+
+#define LZ_PLT
+#include "glz_decode_tmpl.c"
+
+#define LZ_PLT
+#define PLT8
+#define TO_RGB32
+#include "glz_decode_tmpl.c"
+
+#define LZ_PLT
+#define PLT4_BE
+#define TO_RGB32
+#include "glz_decode_tmpl.c"
+
+#define LZ_PLT
+#define PLT4_LE
+#define TO_RGB32
+#include "glz_decode_tmpl.c"
+
+#define LZ_PLT
+#define PLT1_BE
+#define TO_RGB32
+#include "glz_decode_tmpl.c"
+
+#define LZ_PLT
+#define PLT1_LE
+#define TO_RGB32
+#include "glz_decode_tmpl.c"
+
+
+#define LZ_RGB16
+#include "glz_decode_tmpl.c"
+#define LZ_RGB16
+#define TO_RGB32
+#include "glz_decode_tmpl.c"
+
+#define LZ_RGB24
+#include "glz_decode_tmpl.c"
+
+#define LZ_RGB32
+#include "glz_decode_tmpl.c"
+
+#define LZ_RGB_ALPHA
+#include "glz_decode_tmpl.c"
+
+#undef LZ_UNEXPECT_CONDITIONAL
+#undef LZ_EXPECT_CONDITIONAL
+
+typedef size_t (*decode_function)(GlzDecoderWindow &window, uint8_t* in_buf,
+ uint8_t *out_buf, int size,
+ DecodedImageWinId image_win_id, Palette *plt,
+ GlzDecoderDebug &debug_calls);
+
+// ordered according to LZ_IMAGE_TYPE
+const decode_function DECODE_TO_RGB32[] = {
+ NULL,
+ glz_plt1_le_to_rgb32_decode,
+ glz_plt1_be_to_rgb32_decode,
+ glz_plt4_le_to_rgb32_decode,
+ glz_plt4_be_to_rgb32_decode,
+ glz_plt8_to_rgb32_decode,
+ glz_rgb16_to_rgb32_decode,
+ glz_rgb32_decode,
+ glz_rgb32_decode,
+ glz_rgb32_decode
+};
+
+const decode_function DECODE_TO_SAME[] = {
+ NULL,
+ glz_plt_decode,
+ glz_plt_decode,
+ glz_plt_decode,
+ glz_plt_decode,
+ glz_plt_decode,
+ glz_rgb16_decode,
+ glz_rgb24_decode,
+ glz_rgb32_decode,
+ glz_rgb32_decode
+};
+
+void GlzDecoder::decode(uint8_t *data, Palette *palette, void *opaque_usr_info)
+{
+ int out_size;
+ DecodedImageWinId image_window_id;
+ GlzDecodedImage *decoded_image;
+ size_t n_in_bytes_decoded;
+ int bytes_per_pixel;
+ LzImageType decoded_type;
+
+ _in_start = data;
+ _in_now = data;
+
+ decode_header();
+
+#ifdef GLZ_DECODE_TO_RGB32
+ out_size = _image.gross_pixels << 2;
+ bytes_per_pixel = 4;
+
+ if (_image.type == LZ_IMAGE_TYPE_RGBA) {
+ decoded_type = LZ_IMAGE_TYPE_RGBA;
+ } else {
+ decoded_type = LZ_IMAGE_TYPE_RGB32;
+ }
+
+#else
+ if (IS_IMAGE_TYPE_PLT[_image.type]) {
+ GLZ_ASSERT(_debug_calls, !(_image.gross_pixels % PLT_PIXELS_PER_BYTE[_image.type]));
+ out_size = _image.gross_pixels / PLT_PIXELS_PER_BYTE[_image.type];
+ } else {
+ out_size = _image.gross_pixels * RGB_BYTES_PER_PIXEL[_image.type];
+ }
+ bytes_per_pixel = RGB_BYTES_PER_PIXEL[_image.type];
+ decoded_type = _image.type;
+#endif
+
+
+ image_window_id = _images_window.pre_decode(_image.id, _image.id - _image.win_head_dist);
+
+ decoded_image = _usr_handler.alloc_image(opaque_usr_info, _image.id,
+ _image.id - _image.win_head_dist,
+ decoded_type, _image.width, _image.height,
+ _image.gross_pixels, bytes_per_pixel,
+ _image.top_down);
+
+ _image.data = decoded_image->get_data();
+
+ // decode_by_type
+#ifdef GLZ_DECODE_TO_RGB32
+ n_in_bytes_decoded = DECODE_TO_RGB32[_image.type](_images_window, _in_now, _image.data,
+ _image.gross_pixels, image_window_id,
+ palette, _debug_calls);
+#else
+ n_in_bytes_decoded = DECODE_TO_SAME[_image.type](_images_window, _in_now, _image.data,
+ IS_IMAGE_TYPE_PLT[_image.type] ?
+ _image.gross_pixels /
+ PLT_PIXELS_PER_BYTE[_image.type] :
+ _image.gross_pixels,
+ image_window_id, palette, _debug_calls);
+#endif
+
+ _in_now += n_in_bytes_decoded;
+
+ if (_image.type == LZ_IMAGE_TYPE_RGBA) {
+ glz_rgb_alpha_decode(_images_window, _in_now, _image.data,
+ _image.gross_pixels, image_window_id, palette, _debug_calls);
+ }
+
+ _images_window.post_decode(decoded_image);
+}
+