Add ETC1 format to SkTextureCompressor

R=robertphillips@google.com

Author: krajcevski@google.com

Review URL: https://codereview.chromium.org/432143002
diff --git a/gyp/utils.gyp b/gyp/utils.gyp
index f6b00da..e12c87a 100644
--- a/gyp/utils.gyp
+++ b/gyp/utils.gyp
@@ -8,6 +8,7 @@
       'standalone_static_library': 1,
       'dependencies': [
         'core.gyp:*',
+        'etc1.gyp:libetc1',
       ],
       'includes': [
         'utils.gypi',
diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp
index be6eb03..744fa1d 100644
--- a/src/gpu/GrSWMaskHelper.cpp
+++ b/src/gpu/GrSWMaskHelper.cpp
@@ -40,11 +40,13 @@
     static const GrPixelConfig configMap[] = {
         kLATC_GrPixelConfig,       // kLATC_Format,
         kR11_EAC_GrPixelConfig,    // kR11_EAC_Format,
+        kETC1_GrPixelConfig,       // kETC1_Format,
         kASTC_12x12_GrPixelConfig  // kASTC_12x12_Format,
     };
     GR_STATIC_ASSERT(0 == SkTextureCompressor::kLATC_Format);
     GR_STATIC_ASSERT(1 == SkTextureCompressor::kR11_EAC_Format);
-    GR_STATIC_ASSERT(2 == SkTextureCompressor::kASTC_12x12_Format);
+    GR_STATIC_ASSERT(2 == SkTextureCompressor::kETC1_Format);
+    GR_STATIC_ASSERT(3 == SkTextureCompressor::kASTC_12x12_Format);
     GR_STATIC_ASSERT(SK_ARRAY_COUNT(configMap) == SkTextureCompressor::kFormatCnt);
 
     return configMap[fmt];
diff --git a/src/images/SkImageDecoder_pkm.cpp b/src/images/SkImageDecoder_pkm.cpp
index 738d98e..f5fd4b3 100644
--- a/src/images/SkImageDecoder_pkm.cpp
+++ b/src/images/SkImageDecoder_pkm.cpp
@@ -10,6 +10,7 @@
 #include "SkScaledBitmapSampler.h"
 #include "SkStream.h"
 #include "SkStreamPriv.h"
+#include "SkTextureCompressor.h"
 #include "SkTypes.h"
 
 #include "etc1.h"
@@ -80,10 +81,11 @@
     // ETC1 Data is encoded as RGB pixels, so we should extract it as such
     int nPixels = width * height;
     SkAutoMalloc outRGBData(nPixels * 3);
-    etc1_byte *outRGBDataPtr = reinterpret_cast<etc1_byte *>(outRGBData.get());
+    uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get());
 
     // Decode ETC1
-    if (etc1_decode_image(buf, outRGBDataPtr, width, height, 3, width*3)) {
+    if (!SkTextureCompressor::DecompressBufferFromFormat(
+            outRGBDataPtr, width*3, buf, width, height, SkTextureCompressor::kETC1_Format)) {
         return false;
     }
 
diff --git a/src/utils/SkTextureCompressor.cpp b/src/utils/SkTextureCompressor.cpp
index 8013286..4034615 100644
--- a/src/utils/SkTextureCompressor.cpp
+++ b/src/utils/SkTextureCompressor.cpp
@@ -16,6 +16,20 @@
 
 #include "SkTextureCompression_opts.h"
 
+#ifndef SK_IGNORE_ETC1_SUPPORT
+#  include "etc1.h"
+#endif
+
+// Convert ETC1 functions to our function signatures
+static bool compress_etc1_565(uint8_t* dst, const uint8_t* src,
+                              int width, int height, int rowBytes) {
+#ifndef SK_IGNORE_ETC1_SUPPORT
+    return 0 == etc1_encode_image(src, width, height, 2, rowBytes, dst);
+#else
+    return false;
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 namespace SkTextureCompressor {
@@ -35,8 +49,9 @@
         default:
             SkDEBUGFAIL("Unknown compression format!");
             // fall through
-        case kR11_EAC_Format:
         case kLATC_Format:
+        case kR11_EAC_Format:
+        case kETC1_Format: 
             *dimX = 4;
             *dimY = 4;
             break;
@@ -57,8 +72,9 @@
             
     switch (fmt) {
         // These formats are 64 bits per 4x4 block.
-        case kR11_EAC_Format:
         case kLATC_Format:
+        case kR11_EAC_Format:
+        case kETC1_Format:
             encodedBlockSize = 8;
             break;
 
@@ -110,6 +126,19 @@
             }
             break;
 
+            case kRGB_565_SkColorType:
+            {
+                switch (format) {
+                    case kETC1_Format:
+                        proc = compress_etc1_565;
+                        break;
+                    default:
+                        // Do nothing...
+                        break;
+                }
+            }
+            break;
+
             default:
                 // Do nothing...
                 break;
@@ -179,9 +208,17 @@
             DecompressR11EAC(dst, dstRowBytes, src, width, height);
             return true;
 
+#ifndef SK_IGNORE_ETC1_SUPPORT
+        case kETC1_Format:
+            return 0 == etc1_decode_image(src, dst, width, height, 3, dstRowBytes);
+#endif
         case kASTC_12x12_Format:
             // TODO(krajcevski) .. right now just fall through and return false.
             return false;
+
+        default:
+            // Do nothing...
+            break;
     }
 
     return false;
diff --git a/src/utils/SkTextureCompressor.h b/src/utils/SkTextureCompressor.h
index eac8c5e..4254ae7 100644
--- a/src/utils/SkTextureCompressor.h
+++ b/src/utils/SkTextureCompressor.h
@@ -18,9 +18,18 @@
     // Various texture compression formats that we support.
     enum Format {
         // Alpha only formats.
-        kLATC_Format,       // 4x4 blocks, compresses A8
-        kR11_EAC_Format,    // 4x4 blocks, compresses A8
-        kASTC_12x12_Format, // 12x12 blocks, compresses A8
+        kLATC_Format,       // 4x4 blocks, (de)compresses A8
+        kR11_EAC_Format,    // 4x4 blocks, (de)compresses A8
+
+        // RGB only formats
+        kETC1_Format,       // 4x4 blocks, compresses RGB 565, decompresses 8-bit RGB
+                            //    NOTE: ETC1 supports 8-bit RGB compression, but we
+                            //    currently don't have any RGB8 SkColorTypes. We could
+                            //    support 8-bit RGBA but we would have to preprocess the
+                            //    bitmap to insert alphas.
+
+        // Multi-purpose formats
+        kASTC_12x12_Format, // 12x12 blocks, compresses A8, decompresses RGBA
 
         kLast_Format = kASTC_12x12_Format
     };
@@ -48,11 +57,7 @@
     // destination buffer. The width and height of the data passed corresponds
     // to the width and height of the uncompressed image. The destination buffer (dst)
     // is assumed to be large enough to hold the entire decompressed image. The
-    // decompressed image colors are determined based on the passed format:
-    //
-    // LATC -> Alpha 8
-    // R11_EAC -> Alpha 8
-    // ASTC -> RGBA
+    // decompressed image colors are determined based on the passed format.
     //
     // Note, CompressBufferToFormat compresses A8 data into ASTC. However,
     // general ASTC data encodes RGBA data, so that is what the decompressor
diff --git a/tests/TextureCompressionTest.cpp b/tests/TextureCompressionTest.cpp
index daf9883..8694389 100644
--- a/tests/TextureCompressionTest.cpp
+++ b/tests/TextureCompressionTest.cpp
@@ -132,11 +132,12 @@
     for (int i = 0; i < SkTextureCompressor::kFormatCnt; ++i) {
         const SkTextureCompressor::Format fmt = static_cast<SkTextureCompressor::Format>(i);
 
-        // ASTC is for RGBA data, and the decompressed buffer
+        // Ignore formats for RGBA data, since the decompressed buffer
         // won't match the size and contents of the original.
         // TODO: Create separate tests for RGB and RGBA data once
-        // ASTC decompression is implemented.
-        if (SkTextureCompressor::kASTC_12x12_Format == fmt) {
+        // ASTC and ETC1 decompression is implemented.
+        if (SkTextureCompressor::kASTC_12x12_Format == fmt ||
+            SkTextureCompressor::kETC1_Format == fmt) {
             continue;
         }