jpeg pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=c21968bcd76e07ff300c8e102c0062f74fcb704d

commit c21968bcd76e07ff300c8e102c0062f74fcb704d
Author: Jean-Philippe Andre <[email protected]>
Date:   Fri Jun 13 16:56:39 2014 +0900

    Eet: Add support for ETC2 encoding and decoding
    
    Since we now have full support for ETC2, add the colorspaces
    to Eet.
    
    @feature
---
 src/Makefile_Eet.am     |   2 +
 src/lib/eet/Eet.h       |   8 +-
 src/lib/eet/eet_image.c | 310 +++++++++++++++++++++++++++++++++++-------------
 3 files changed, 237 insertions(+), 83 deletions(-)

diff --git a/src/Makefile_Eet.am b/src/Makefile_Eet.am
index c5da421..d5a308b 100644
--- a/src/Makefile_Eet.am
+++ b/src/Makefile_Eet.am
@@ -22,6 +22,8 @@ static_libs/lz4/lz4.h \
 static_libs/lz4/lz4hc.c \
 static_libs/lz4/lz4hc.h \
 static_libs/rg_etc/rg_etc1.c \
+static_libs/rg_etc/rg_etc2.c \
+static_libs/rg_etc/etc2_encoder.c \
 static_libs/rg_etc/rg_etc1.h
 
 lib_eet_libeet_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
diff --git a/src/lib/eet/Eet.h b/src/lib/eet/Eet.h
index 50645a0..95be2e5 100644
--- a/src/lib/eet/Eet.h
+++ b/src/lib/eet/Eet.h
@@ -477,14 +477,18 @@ typedef enum _Eet_Image_Encoding
 {
    EET_IMAGE_LOSSLESS = 0,
    EET_IMAGE_JPEG = 1,
-   EET_IMAGE_ETC1 = 2
+   EET_IMAGE_ETC1 = 2,
+   EET_IMAGE_ETC2_RGB = 3,
+   EET_IMAGE_ETC2_RGBA = 4
 } Eet_Image_Encoding;
 
 typedef enum _Eet_Colorspace
 {
    EET_COLORSPACE_ARGB8888 = 0,
    /* The number between are reserved to preserve compatibility with evas */
-   EET_COLORSPACE_ETC1 = 8
+   EET_COLORSPACE_ETC1 = 9,
+   EET_COLORSPACE_RGB8_ETC2 = 10,
+   EET_COLORSPACE_RGBA8_ETC2_EAC = 11
 } Eet_Colorspace;
 
 /**
diff --git a/src/lib/eet/eet_image.c b/src/lib/eet/eet_image.c
index 4aacee1..f3db7ee 100644
--- a/src/lib/eet/eet_image.c
+++ b/src/lib/eet/eet_image.c
@@ -31,7 +31,7 @@
 #include "rg_etc1.h"
 
 #define OFFSET_BLOCK_SIZE 4
-#define OFFSET_ALGORITHN 5
+#define OFFSET_ALGORITHM 5
 #define OFFSET_OPTIONS 6
 #define OFFSET_WIDTH 8
 #define OFFSET_HEIGHT 12
@@ -700,91 +700,149 @@ _tgv_length_get(const char *m, unsigned int length, 
unsigned int *offset)
 }
 
 static int
-eet_data_image_etc1_decode(const void *data,
+roundup(int val, int rup)
+{
+   if (val >= 0 && rup > 0)
+     return (val + rup - 1) - ((val + rup - 1) % rup);
+   return 0;
+}
+
+static int
+eet_data_image_etc2_decode(const void *data,
                            unsigned int length,
                            unsigned int *p,
                            unsigned int dst_x,
                            unsigned int dst_y,
                            unsigned int dst_w,
                            unsigned int dst_h,
-                           unsigned int cspace)
+                           Eina_Bool alpha,
+                           Eet_Colorspace cspace,
+                           Eet_Image_Encoding lossy)
 {
-   Eina_Rectangle master;
-   Eina_Rectangle current;
-   const char *m = data;
+   const char *m = NULL;
+   unsigned int bwidth, bheight;
+   unsigned char *p_etc;
    char *buffer;
-   unsigned int block_width, block_height;
-   unsigned int compress;
-   unsigned int width, height;
-   unsigned int block_count;
-   unsigned int etc1_width = 0;
+   Eina_Rectangle master;
+   unsigned int block_length;
    unsigned int offset;
-   unsigned int x, y;
+   unsigned int x, y, w, h;
+   unsigned int block_count;
+   unsigned int etc_width = 0;
+   unsigned int etc_block_size;
+   Eet_Colorspace file_cspace;
+   Eina_Bool compress, blockless;
+   Eina_Bool r = EINA_FALSE;
 
-   block_width = 4 << (m[OFFSET_BLOCK_SIZE] & 0x0f);
-   block_height = 4 << ((m[OFFSET_BLOCK_SIZE] & 0xf0) >> 4);
+   m = data;
 
-   if (m[OFFSET_ALGORITHN] != 0) return 0;
+   if (strncmp(m, "TGV1", 4) != 0)
+     return 0;
 
    compress = m[OFFSET_OPTIONS] & 0x1;
+   blockless = (m[OFFSET_OPTIONS] & 0x2) != 0;
+   w = ntohl(*((unsigned int*) &(m[OFFSET_WIDTH])));
+   h = ntohl(*((unsigned int*) &(m[OFFSET_HEIGHT])));
 
-   width = ntohl(*((unsigned int*) &(m[OFFSET_WIDTH])));
-   height = ntohl(*((unsigned int*) &(m[OFFSET_HEIGHT])));
-
-   EINA_RECTANGLE_SET(&master, 0, 0, width, height);
-   EINA_RECTANGLE_SET(&current, dst_x, dst_y, dst_w, dst_h);
-
-   if (!eina_rectangle_intersection(&master, &current))
-     return 0;
+   switch (m[OFFSET_ALGORITHM] & 0xFF)
+     {
+      case 0:
+        if (lossy != EET_IMAGE_ETC1) return 0;
+        file_cspace = EET_COLORSPACE_ETC1;
+        if (alpha != EINA_FALSE) return 0;
+        etc_block_size = 8;
+        etc_width = ((w + 2) / 4 + ((w + 2) % 4 ? 1 : 0)) * 8;
+        break;
+      case 1:
+        if (lossy != EET_IMAGE_ETC2_RGB) return 0;
+        file_cspace = EET_COLORSPACE_RGB8_ETC2;
+        if (alpha != EINA_FALSE) return 0;
+        etc_block_size = 8;
+        etc_width = ((w + 2) / 4 + ((w + 2) % 4 ? 1 : 0)) * 8;
+        break;
+      case 2:
+        if (lossy != EET_IMAGE_ETC2_RGBA) return 0;
+        file_cspace = EET_COLORSPACE_RGBA8_ETC2_EAC;
+        if (alpha != EINA_TRUE) return 0;
+        etc_block_size = 16;
+        etc_width = ((w + 2) / 4 + ((w + 2) % 4 ? 1 : 0)) * 16;
+        break;
+      default:
+        return 0;
+     }
 
-   if (cspace == EET_COLORSPACE_ETC1)
+   if (cspace != EET_COLORSPACE_ARGB8888 && cspace != file_cspace)
      {
-        if (master.x % 4 ||
-            master.y % 4)
-          abort ();
+        if (!((cspace == EET_COLORSPACE_RGB8_ETC2) && (file_cspace == 
EET_COLORSPACE_ETC1)))
+          return 0;
+        // else: ETC2 is compatible with ETC1 and is preferred
+     }
 
-        etc1_width = ((dst_w + 2) / 4 + ((dst_w + 2) % 4 ? 1 : 0)) * 8;
+   if (blockless)
+     {
+        bwidth = roundup(w + 2, 4);
+        bheight = roundup(h + 2, 4);
      }
    else
      {
-        // Account for duplicated border pixels
+        bwidth = 4 << (m[OFFSET_BLOCK_SIZE] & 0x0f);
+        bheight = 4 << ((m[OFFSET_BLOCK_SIZE] & 0xf0) >> 4);
+     }
+
+   EINA_RECTANGLE_SET(&master, dst_x, dst_y, dst_w, dst_h);
+
+   switch (cspace)
+     {
+      case EET_COLORSPACE_ETC1:
+      case EET_COLORSPACE_RGB8_ETC2:
+      case EET_COLORSPACE_RGBA8_ETC2_EAC:
+        if (master.x % 4 || master.y % 4)
+          abort();
+        break;
+      case EET_COLORSPACE_ARGB8888:
+        // Offset to take duplicated pixels into account
         master.x += 1;
         master.y += 1;
+        break;
+      default: abort();
      }
 
-   // Allocate space for each ETC1 block (64bytes per 4 * 4 pixels group)
-   block_count = block_width * block_height / (4 * 4);
+   p_etc = (unsigned char*) p;
+   offset = OFFSET_BLOCKS;
+
+   // Allocate space for each ETC block (8 or 16 bytes per 4 * 4 pixels group)
+   block_count = bwidth * bheight / (4 * 4);
    if (compress)
-     buffer = alloca(8 * block_count);
+     buffer = alloca(etc_block_size * block_count);
    else
      buffer = NULL;
 
-   offset = OFFSET_BLOCKS;
-
-   for (y = 0; y < height + 2; y += block_height)
-     for (x = 0; x < width + 2; x += block_width)
+   for (y = 0; y < h + 2; y += bheight)
+     for (x = 0; x < w + 2; x += bwidth)
        {
+          Eina_Rectangle current;
           const char *data_start;
           const char *it;
-          unsigned int block_length;
           unsigned int expand_length;
           unsigned int i, j;
 
           block_length = _tgv_length_get(m + offset, length, &offset);
+
           if (block_length == 0) return 0;
 
           data_start = m + offset;
           offset += block_length;
 
           EINA_RECTANGLE_SET(&current, x, y,
-                             block_width, block_height);
+                             bwidth, bheight);
+
           if (!eina_rectangle_intersection(&current, &master))
             continue ;
 
           if (compress)
             {
-               expand_length = LZ4_uncompress(data_start,
-                                              buffer, block_count * 8);
+               expand_length = LZ4_uncompress(data_start, buffer,
+                                              block_count * etc_block_size);
                // That's an overhead for now, need to be fixed
                if (expand_length != block_length)
                  return 0;
@@ -792,13 +850,13 @@ eet_data_image_etc1_decode(const void *data,
           else
             {
                buffer = (void*) data_start;
-               if (block_count * 8 != block_length)
+               if (block_count * etc_block_size != block_length)
                  return 0;
             }
           it = buffer;
 
-          for (i = 0; i < block_height; i += 4)
-            for (j = 0; j < block_width; j += 4, it += 8)
+          for (i = 0; i < bheight; i += 4)
+            for (j = 0; j < bwidth; j += 4, it += etc_block_size)
               {
                  Eina_Rectangle current_etc;
                  unsigned int temporary[4 * 4] = { 0 };
@@ -808,19 +866,33 @@ eet_data_image_etc1_decode(const void *data,
                  EINA_RECTANGLE_SET(&current_etc, x + j, y + i, 4, 4);
 
                  if (!eina_rectangle_intersection(&current_etc, &current))
-                   continue ;
+                   continue;
 
                  switch (cspace)
                    {
                     case EET_COLORSPACE_ARGB8888:
-                       if (!rg_etc1_unpack_block(it, temporary, 0))
-                         {
-                            fprintf(stderr, "HOUSTON WE HAVE A PROBLEM ! Block 
starting at {%i, %i} is corrupted !\n", x + j, y + i);
-                            continue ;
-                         }
+                      switch (file_cspace)
+                        {
+                         case EET_COLORSPACE_ETC1:
+                           if (!rg_etc1_unpack_block(it, temporary, 0))
+                             {
+                                // TODO: Should we decode as RGB8_ETC2?
+                                fprintf(stderr, "ETC1: Block starting at {%i, 
%i} is corrupted!\n", x + j, y + i);
+                                continue;
+                             }
+                           break;
+                         case EET_COLORSPACE_RGB8_ETC2:
+                           rg_etc2_rgb8_decode_block((uint8_t *) it, 
temporary);
+                           break;
+                         case EET_COLORSPACE_RGBA8_ETC2_EAC:
+                           rg_etc2_rgba8_decode_block((uint8_t *) it, 
temporary);
+                           break;
+                         default: abort();
+                        }
 
                        offset_x = current_etc.x - x - j;
                        offset_y = current_etc.y - y - i;
+                       // FIXME: Import NEON optimizations from Evas.
                        for (k = 0; k < current_etc.h; k++)
                          {
                             memcpy(&p[current_etc.x - 1 +
@@ -830,9 +902,11 @@ eet_data_image_etc1_decode(const void *data,
                          }
                        break;
                     case EET_COLORSPACE_ETC1:
-                       memcpy(&p[current_etc.x +
-                                 current_etc.y * etc1_width],
-                              it, 8);
+                    case EET_COLORSPACE_RGB8_ETC2:
+                    case EET_COLORSPACE_RGBA8_ETC2_EAC:
+                       memcpy(&p_etc[(current_etc.x / 4) * etc_block_size +
+                                     (current_etc.y / 4) * etc_width],
+                              it, etc_block_size);
                        break;
                     default:
                        abort();
@@ -1016,16 +1090,18 @@ eet_data_image_etc1_compressed_convert(int         
*size,
                                        unsigned int w,
                                        unsigned int h,
                                        int          quality,
-                                       int          compress)
+                                       int          compress,
+                                       Eet_Image_Encoding lossy)
 {
    rg_etc1_pack_params param;
-   char *comp;
-   char *buffer;
+   uint8_t *comp = NULL;
+   uint8_t *buffer;
    uint32_t *data;
    uint32_t width, height;
    uint8_t header[8] = "TGV1";
    int block_width, block_height, macro_block_width, macro_block_height;
-   int block_count, image_stride, image_height;
+   int block_count, image_stride, image_height, etc_block_size;
+   Eet_Colorspace cspace;
    Eina_Binbuf *r;
    void *result;
 
@@ -1037,6 +1113,7 @@ eet_data_image_etc1_compressed_convert(int         *size,
    data = (uint32_t *) data8;
    width = htonl(image_stride);
    height = htonl(image_height);
+   compress = !!compress;
 
    // Disable dithering, as it will deteriorate the quality of flat surfaces
    param.m_dithering = 0;
@@ -1053,11 +1130,29 @@ eet_data_image_etc1_compressed_convert(int         
*size,
    block_height = _block_size_get(image_height + 2);
    header[4] = (block_height << 4) | block_width;
 
-   // header[5]: 0 for ETC1
-   header[5] = 0;
+   // header[5]: 0 for ETC1, 1 for RGB8_ETC2, 2 for RGBA8_ETC2_EAC
+   switch (lossy)
+     {
+      case EET_IMAGE_ETC1:
+        cspace = EET_COLORSPACE_ETC1;
+        etc_block_size = 8;
+        header[5] = 0;
+        break;
+      case EET_IMAGE_ETC2_RGB:
+        cspace = EET_COLORSPACE_RGB8_ETC2;
+        etc_block_size = 8;
+        header[5] = 1;
+        break;
+      case EET_IMAGE_ETC2_RGBA:
+        cspace = EET_COLORSPACE_RGBA8_ETC2_EAC;
+        etc_block_size = 16;
+        header[5] = 2;
+        break;
+      default: abort();
+     }
 
    // header[6]: 0 for raw, 1, for LZ4 compressed
-   header[6] = (!!compress & 0x1);
+   header[6] = compress;
 
    // header[7]: options (unused)
    header[7] = 0;
@@ -1073,16 +1168,10 @@ eet_data_image_etc1_compressed_convert(int         
*size,
 
    // Number of ETC1 blocks in a compressed block
    block_count = (macro_block_width * macro_block_height) / (4 * 4);
-   buffer = alloca(block_count * 8);
+   buffer = alloca(block_count * etc_block_size);
 
    if (compress)
-     {
-        comp = alloca(LZ4_compressBound(block_count * 8));
-     }
-   else
-     {
-        comp = NULL;
-     }
+     comp = alloca(LZ4_compressBound(block_count * etc_block_size));
 
    // Write macro block
    for (int y = 0; y < image_height + 2; y += macro_block_height)
@@ -1097,7 +1186,7 @@ eet_data_image_etc1_compressed_convert(int         *size,
 
         for (int x = 0; x < image_stride + 2; x += macro_block_width)
           {
-             char *offset = buffer;
+             uint8_t *offset = buffer;
              int real_x = x;
 
              if (x == 0) real_x = 0;
@@ -1172,19 +1261,33 @@ eet_data_image_etc1_compressed_convert(int         
*size,
                               }
                          }
 
-                       rg_etc1_pack_block(offset, (unsigned int*) todo, 
&param);
-                       offset += 8;
+                       switch (cspace)
+                         {
+                          case EET_COLORSPACE_ETC1:
+                            rg_etc1_pack_block(offset, (uint32_t *) todo, 
&param);
+                            break;
+                          case EET_COLORSPACE_RGB8_ETC2:
+                            etc2_rgb8_block_pack(offset, (uint32_t *) todo, 
&param);
+                            break;
+                          case EET_COLORSPACE_RGBA8_ETC2_EAC:
+                            etc2_rgba8_block_pack(offset, (uint32_t *) todo, 
&param);
+                            break;
+                          default: return 0;
+                         }
+
+                       offset += etc_block_size;
                     }
                }
 
              if (compress)
                {
-                  wlen = LZ4_compressHC(buffer, comp, block_count * 8);
+                  wlen = LZ4_compressHC((char *) buffer, (char *) comp,
+                                        block_count * etc_block_size);
                }
              else
                {
                   comp = buffer;
-                  wlen = block_count * 8;
+                  wlen = block_count * etc_block_size;
                }
 
              if (wlen > 0)
@@ -1757,9 +1860,12 @@ eet_data_image_encode_cipher(const void  *data,
                                                  w, h, alpha, quality);
          break;
       case EET_IMAGE_ETC1:
-         if (alpha) abort();
+      case EET_IMAGE_ETC2_RGB:
+        if (alpha) abort();
+        // fallthrough
+      case EET_IMAGE_ETC2_RGBA:
          d = eet_data_image_etc1_compressed_convert(&size, data, w, h,
-                                                    quality, comp);
+                                                    quality, comp, lossy);
          break;
       default:
          abort();
@@ -1937,9 +2043,24 @@ eet_data_image_header_decode_cipher(const void   *data,
 
         if (w) *w = ntohl(*((unsigned int*) &(m[OFFSET_WIDTH])));
         if (h) *h = ntohl(*((unsigned int*) &(m[OFFSET_HEIGHT])));
-        if (alpha) *alpha = 0; // ETC1 only for now
         if (comp) *comp = m[OFFSET_OPTIONS] & 0x1;
-        if (lossy) *lossy = EET_IMAGE_ETC1;
+        switch (m[OFFSET_ALGORITHM] & 0xFF)
+          {
+           case 0:
+             if (lossy) *lossy = EET_IMAGE_ETC1;
+             if (alpha) *alpha = EINA_FALSE;
+             break;
+           case 1:
+             if (lossy) *lossy = EET_IMAGE_ETC2_RGB;
+             if (alpha) *alpha = EINA_FALSE;
+             break;
+           case 2:
+             if (alpha) *alpha = EINA_TRUE;
+             if (lossy) *lossy = EET_IMAGE_ETC2_RGBA;
+             break;
+           default:
+             return 0;
+          }
         if (quality) *quality = 50;
 
         return 1;
@@ -1983,6 +2104,16 @@ static const Eet_Colorspace _eet_etc1_colorspace[] = {
   EET_COLORSPACE_ARGB8888
 };
 
+static const Eet_Colorspace _eet_etc2_rgb_colorspace[] = {
+  EET_COLORSPACE_RGB8_ETC2,
+  EET_COLORSPACE_ARGB8888
+};
+
+static const Eet_Colorspace _eet_etc2_rgba_colorspace[] = {
+  EET_COLORSPACE_RGBA8_ETC2_EAC,
+  EET_COLORSPACE_ARGB8888
+};
+
 EAPI int
 eet_data_image_colorspace_get(Eet_File *ef,
                               const char *name,
@@ -1995,8 +2126,15 @@ eet_data_image_colorspace_get(Eet_File *ef,
    r = eet_data_image_header_read_cipher(ef, name, cipher_key, NULL, NULL, 
NULL, NULL, NULL, &lossy);
    if (!r) return r;
 
-   if (lossy == EET_IMAGE_ETC1 && cspaces)
-     *cspaces = _eet_etc1_colorspace;
+   if (cspaces)
+     {
+        if (lossy == EET_IMAGE_ETC1)
+          *cspaces = _eet_etc1_colorspace;
+        else if (lossy == EET_IMAGE_ETC2_RGB)
+          *cspaces = _eet_etc2_rgb_colorspace;
+        else if (lossy == EET_IMAGE_ETC2_RGBA)
+          *cspaces = _eet_etc2_rgba_colorspace;
+     }
 
    return r;
 }
@@ -2184,11 +2322,13 @@ _eet_data_image_decode_inside(const void   *data,
                                                  h, row_stride))
           return 0;
      }
-   else if (lossy == EET_IMAGE_ETC1)
+   else if ((lossy == EET_IMAGE_ETC1) ||
+            (lossy == EET_IMAGE_ETC2_RGB) ||
+            (lossy == EET_IMAGE_ETC2_RGBA))
      {
-        return eet_data_image_etc1_decode(data, size, d,
+        return eet_data_image_etc2_decode(data, size, d,
                                           src_x, src_y, src_w, src_h,
-                                          cspace);
+                                          alpha, cspace, lossy);
      }
    else
      abort();
@@ -2326,6 +2466,14 @@ eet_data_image_decode_to_cspace_surface_cipher(const 
void   *data,
        ilossy != EET_IMAGE_ETC1)
      return 0;
 
+   if (cspace == EET_COLORSPACE_RGB8_ETC2 &&
+       ilossy != EET_IMAGE_ETC2_RGB)
+     return 0;
+
+   if (cspace == EET_COLORSPACE_RGBA8_ETC2_EAC &&
+       ilossy != EET_IMAGE_ETC2_RGBA)
+     return 0;
+
    if (cspace == EET_COLORSPACE_ARGB8888 &&
        w * 4 > row_stride)
      return 0;

-- 


Reply via email to