[Spice-devel,2/3] Add support for A8 images to the LZ routines

Submitted by Soeren Sandmann on Aug. 19, 2012, 8:55 p.m.

Details

Message ID 1345409750-28813-3-git-send-email-sandmann@cs.au.dk
State New
Headers show

Not browsing as part of any series.

Commit Message

Soeren Sandmann Aug. 19, 2012, 8:55 p.m.
From: Søren Sandmann Pedersen <ssp@redhat.com>

This format is needed to add Render support to the X driver, so we
need the ability to compress and decompress it.
---
 common/canvas_base.c        |  4 ++++
 common/lz.c                 | 24 +++++++++++++++++++++++-
 common/lz_common.h          |  5 +++--
 common/lz_compress_tmpl.c   | 28 +++++++++++++++++++++++-----
 common/lz_decompress_tmpl.c | 19 ++++++++++++++++++-
 common/pixman_utils.c       | 15 +++++++++++++++
 spice-protocol              |  2 +-
 spice.proto                 |  3 ++-
 8 files changed, 89 insertions(+), 11 deletions(-)

Patch hide | download patch | download mbox

diff --git a/common/canvas_base.c b/common/canvas_base.c
index 4f40306..c60c5cf 100644
--- a/common/canvas_base.c
+++ b/common/canvas_base.c
@@ -776,6 +776,10 @@  static pixman_image_t *canvas_get_lz(CanvasBase *canvas, SpiceImage *image, int
         as_type = LZ_IMAGE_TYPE_RGB32;
         pixman_format = PIXMAN_x8r8g8b8;
         break;
+    case LZ_IMAGE_TYPE_A8:
+        as_type = LZ_IMAGE_TYPE_A8;
+        pixman_format = PIXMAN_a8;
+        break;
     case LZ_IMAGE_TYPE_RGB16:
         if (!want_original &&
             (canvas->format == SPICE_SURFACE_FMT_32_xRGB ||
diff --git a/common/lz.c b/common/lz.c
index 568aae7..3d77aed 100644
--- a/common/lz.c
+++ b/common/lz.c
@@ -465,6 +465,13 @@  typedef uint16_t rgb16_pixel_t;
 #define TO_RGB32
 #include "lz_decompress_tmpl.c"
 
+#define LZ_A8
+#include "lz_compress_tmpl.c"
+#define LZ_A8
+#include "lz_decompress_tmpl.c"
+#define LZ_A8
+#define TO_RGB32
+#include "lz_decompress_tmpl.c"
 
 #define LZ_RGB16
 #include "lz_compress_tmpl.c"
@@ -514,7 +521,8 @@  int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_do
         }
     } else {
         if (encoder->stride != width * RGB_BYTES_PER_PIXEL[encoder->type]) {
-            encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb)\n");
+            encoder->usr->error(encoder->usr, "stride != width*bytes_per_pixel (rgb) %d %d %d\n",
+                                encoder->stride, width, RGB_BYTES_PER_PIXEL[encoder->type]);
         }
     }
 
@@ -560,6 +568,9 @@  int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_do
     case LZ_IMAGE_TYPE_XXXA:
         lz_rgb_alpha_compress(encoder);
         break;
+    case LZ_IMAGE_TYPE_A8:
+        lz_a8_compress(encoder);
+        break;
     case LZ_IMAGE_TYPE_INVALID:
     default:
         encoder->usr->error(encoder->usr, "bad image type\n");
@@ -709,6 +720,17 @@  void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf)
                 encoder->usr->error(encoder->usr, "unsupported output format\n");
             }
             break;
+        case LZ_IMAGE_TYPE_A8:
+            if (encoder->type == to_type) {
+                alpha_size = lz_a8_decompress(encoder, (one_byte_pixel_t *)buf, size);
+                out_size = alpha_size;
+            } else if (to_type == LZ_IMAGE_TYPE_RGB32) {
+                alpha_size = lz_a8_to_rgb32_decompress(encoder, (rgb32_pixel_t *)buf, size);
+                out_size = alpha_size;
+            } else {
+                encoder->usr->error(encoder->usr, "unsupported output format\n");
+            }
+            break;
         case LZ_IMAGE_TYPE_PLT1_LE:
         case LZ_IMAGE_TYPE_PLT1_BE:
         case LZ_IMAGE_TYPE_PLT4_LE:
diff --git a/common/lz_common.h b/common/lz_common.h
index 2ec374b..b5ce212 100644
--- a/common/lz_common.h
+++ b/common/lz_common.h
@@ -44,7 +44,8 @@  typedef enum {
     LZ_IMAGE_TYPE_RGB24,
     LZ_IMAGE_TYPE_RGB32,
     LZ_IMAGE_TYPE_RGBA,
-    LZ_IMAGE_TYPE_XXXA
+    LZ_IMAGE_TYPE_XXXA,
+    LZ_IMAGE_TYPE_A8
 } LzImageType;
 
 #define LZ_IMAGE_TYPE_MASK 0x0f
@@ -54,7 +55,7 @@  typedef enum {
 static const int IS_IMAGE_TYPE_PLT[] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
 static const int IS_IMAGE_TYPE_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
 static const int PLT_PIXELS_PER_BYTE[] = {0, 8, 8, 2, 2, 1};
-static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4};
+static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4, 1};
 
 
 #define LZ_MAGIC (*(uint32_t *)"LZ  ")
diff --git a/common/lz_compress_tmpl.c b/common/lz_compress_tmpl.c
index 6db5387..7e2ce42 100644
--- a/common/lz_compress_tmpl.c
+++ b/common/lz_compress_tmpl.c
@@ -71,6 +71,21 @@ 
     }
 #endif
 
+#ifdef LZ_A8
+#define PIXEL one_byte_pixel_t
+#define FNAME(name) lz_a8_##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 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
@@ -177,7 +192,7 @@  static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
         size_t distance;
 
         /* minimum match length */
-#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
+#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
         size_t len = 3;
 #elif defined(LZ_RGB16)
         size_t len = 2;
@@ -234,7 +249,7 @@  static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
         ip++;
 
         /* minimum match length for rgb16 is 2 and for plt and alpha is 3 */
-#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_RGB16)
+#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_RGB16) || defined(LZ_A8)
         if (!SAME_PIXEL(*ref, *ip)) {
             ref++;
             ip++;
@@ -244,7 +259,7 @@  static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
         ip++;
 #endif
 
-#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
+#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
         if (!SAME_PIXEL(*ref, *ip)) {
             ref++;
             ip++;
@@ -255,7 +270,7 @@  static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
 #endif
         /* far, needs at least 5-byte match */
         if (distance >= MAX_DISTANCE) {
-#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
+#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
             if (ref >= (ref_limit - 1)) {
                 goto literal;
             }
@@ -272,7 +287,7 @@  static void FNAME(compress_seg)(Encoder *encoder, LzImageSegment *seg, PIXEL *fr
             ref++;
             ip++;
             len++;
-#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
+#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
             if (!SAME_PIXEL(*ref, *ip)) {
                 ref++;
                 ip++;
@@ -464,9 +479,11 @@  static void FNAME(compress)(Encoder *encoder)
     LzImageSegment    *cur_seg = encoder->head_image_segs;
     HashEntry        *hslot;
     PIXEL            *ip;
+    PIXEL            *ip_start;
 
     // fetch the first image segment that is not too small
     while (cur_seg && ((((PIXEL *)cur_seg->lines_end) - ((PIXEL *)cur_seg->lines)) < 4)) {
+        ip_start = cur_seg->lines;
         // coping the segment
         if (cur_seg->lines != cur_seg->lines_end) {
             ip = (PIXEL *)cur_seg->lines;
@@ -526,4 +543,5 @@  static void FNAME(compress)(Encoder *encoder)
 #undef LZ_RGB16
 #undef LZ_RGB24
 #undef LZ_RGB32
+#undef LZ_A8
 #undef HASH_FUNC2
diff --git a/common/lz_decompress_tmpl.c b/common/lz_decompress_tmpl.c
index fb41e77..04a5121 100644
--- a/common/lz_decompress_tmpl.c
+++ b/common/lz_decompress_tmpl.c
@@ -153,6 +153,22 @@ 
 #endif // TO_RGB32
 #endif
 
+#ifdef LZ_A8
+#ifndef TO_RGB32
+#define OUT_PIXEL one_byte_pixel_t
+#define FNAME(name) lz_a8_##name
+#define COPY_COMP_PIXEL(encoder, out) {out->a = decode(encoder); out++;}
+#else // TO_RGB32
+#define OUT_PIXEL rgb32_pixel_t
+#define FNAME(name) lz_a8_to_rgb32_##name
+#define COPY_COMP_PIXEL(encoder, out) {                     \
+        (out)->b = (out)->g = (out)->r = 0;                 \
+        (out)->pad = decode(encoder);                       \
+        (out)++;                                            \
+    }
+#endif
+#endif
+
 #ifdef LZ_RGB16
 #ifndef TO_RGB32
 #define OUT_PIXEL rgb16_pixel_t
@@ -237,7 +253,7 @@  static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
                 }
             }
 
-#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA)
+#if defined(LZ_PLT) || defined(LZ_RGB_ALPHA) || defined(LZ_A8)
             len += 3; // length is biased by 2 + 1 (fixing bias)
 #elif defined(LZ_RGB16)
             len += 2; // length is biased by 1 + 1 (fixing bias)
@@ -315,6 +331,7 @@  static size_t FNAME(decompress)(Encoder *encoder, OUT_PIXEL *out_buf, int size)
 #undef LZ_RGB16
 #undef LZ_RGB24
 #undef LZ_RGB32
+#undef LZ_A8
 #undef LZ_RGB_ALPHA
 #undef TO_RGB32
 #undef OUT_PIXEL
diff --git a/common/pixman_utils.c b/common/pixman_utils.c
index d4020e6..311c22e 100644
--- a/common/pixman_utils.c
+++ b/common/pixman_utils.c
@@ -963,6 +963,9 @@  pixman_format_code_t spice_bitmap_format_to_pixman(int bitmap_format,
     case SPICE_BITMAP_FMT_RGBA:
         return PIXMAN_a8r8g8b8;
 
+    case SPICE_BITMAP_FMT_8BIT_A:
+        return PIXMAN_a8;
+
     case SPICE_BITMAP_FMT_INVALID:
     default:
         printf("Unknown bitmap format %d\n", bitmap_format);
@@ -1083,6 +1086,15 @@  static void bitmap_32_to_32(uint8_t* dest, int dest_stride,
 #endif
 }
 
+static void bitmap_8_to_8(uint8_t* dest, int dest_stride,
+                          uint8_t* src, int src_stride,
+                          int width, uint8_t* end)
+{
+    for (; src != end; src += src_stride, dest += dest_stride) {
+        memcpy(dest, src, width);
+    }
+}
+
 static void bitmap_24_to_32(uint8_t* dest, int dest_stride,
                             uint8_t* src, int src_stride,
                             int width, uint8_t* end)
@@ -1477,6 +1489,9 @@  pixman_image_t *spice_bitmap_to_pixman(pixman_image_t *dest_image,
     case SPICE_BITMAP_FMT_RGBA:
         bitmap_32_to_32(dest, dest_stride, src, src_stride, width, end);
         break;
+    case SPICE_BITMAP_FMT_8BIT_A:
+        bitmap_8_to_8(dest, dest_stride, src, src_stride, width, end);
+        break;
     case SPICE_BITMAP_FMT_24BIT:
         bitmap_24_to_32(dest, dest_stride, src, src_stride, width, end);
         break;
diff --git a/spice-protocol b/spice-protocol
index da908f8..6ef7050 160000
--- a/spice-protocol
+++ b/spice-protocol
@@ -1 +1 @@ 
-Subproject commit da908f89b581fd4725da997fdaea209f8e6548f6
+Subproject commit 6ef7050b0725dbe385eed290e73a2603af7d3fbc
diff --git a/spice.proto b/spice.proto
index 1fdead9..87894a0 100644
--- a/spice.proto
+++ b/spice.proto
@@ -321,7 +321,8 @@  enum8 bitmap_fmt {
     16BIT, /* 0555 mode */
     24BIT /* 3 byte, brg */,
     32BIT /* 4 byte, xrgb in little endian format */,
-    RGBA /* 4 byte, argb in little endian format */
+    RGBA /* 4 byte, argb in little endian format */,
+    A8 /* 1 byte, alpha */
 };
 
 flags8 bitmap_flags {