Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2014 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "gm.h"
      9 
     10 #include "Resources.h"
     11 #include "SkCanvas.h"
     12 #include "SkData.h"
     13 #include "SkDecodingImageGenerator.h"
     14 #include "SkImageDecoder.h"
     15 #include "SkOSFile.h"
     16 
     17 #ifndef SK_IGNORE_ETC1_SUPPORT
     18 
     19 #include "etc1.h"
     20 
     21 /**
     22  *  Remove the last row and column of ETC1 blocks, effectively
     23  *  making a texture that started as power of two into a texture
     24  *  that is no longer power of two...
     25  */
     26 bool slice_etc1_data(void *data, int* width, int* height) {
     27 
     28     // First, parse the data and get to it...
     29     etc1_byte *origData = reinterpret_cast<etc1_byte *>(data);
     30     if (!etc1_pkm_is_valid(origData)) {
     31         return false;
     32     }
     33 
     34     int origW = etc1_pkm_get_width(origData);
     35     int origH = etc1_pkm_get_height(origData);
     36 
     37     int blockWidth = (origW + 3) >> 2;
     38     int blockHeight = (origH + 3) >> 2;
     39 
     40     // Make sure that we have blocks to trim off..
     41     if (blockWidth < 2 || blockHeight < 2) {
     42         return false;
     43     }
     44 
     45     int newWidth = (blockWidth - 1) << 2;
     46     int newHeight = (blockHeight - 1) << 2;
     47 
     48     size_t newDataSz = etc1_get_encoded_data_size(newWidth, newHeight) + ETC_PKM_HEADER_SIZE;
     49     SkAutoMalloc am(newDataSz);
     50 
     51     etc1_byte *newData = reinterpret_cast<etc1_byte *>(am.get());
     52 
     53     etc1_pkm_format_header(newData, newWidth, newHeight);
     54     newData += ETC_PKM_HEADER_SIZE;
     55     origData += ETC_PKM_HEADER_SIZE;
     56 
     57     for (int j = 0; j < blockHeight - 1; ++j) {
     58         memcpy(newData, origData, (blockWidth - 1)*ETC1_ENCODED_BLOCK_SIZE);
     59         origData += blockWidth*ETC1_ENCODED_BLOCK_SIZE;
     60         newData += (blockWidth - 1)*ETC1_ENCODED_BLOCK_SIZE;
     61     }
     62 
     63     // Stick the data back whence it came
     64     memcpy(data, am.get(), newDataSz);
     65     *width = newWidth;
     66     *height = newHeight;
     67 
     68     return true;
     69 }
     70 #endif  // SK_IGNORE_ETC1_SUPPORT
     71 
     72 namespace skiagm {
     73 
     74 /**
     75  *  Test decoding an image from a PKM or KTX file and then
     76  *  from compressed ETC1 data.
     77  */
     78 class ETC1BitmapGM : public GM {
     79 public:
     80     ETC1BitmapGM() { }
     81     virtual ~ETC1BitmapGM() { }
     82 
     83 protected:
     84     virtual SkString onShortName() SK_OVERRIDE {
     85         SkString str = SkString("etc1bitmap_");
     86         str.append(this->fileExtension());
     87         return str;
     88     }
     89 
     90     virtual SkISize onISize() SK_OVERRIDE {
     91         return SkISize::Make(128, 128);
     92     }
     93 
     94     virtual SkString fileExtension() const = 0;
     95 
     96     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
     97         SkBitmap bm;
     98         SkString filename = GetResourcePath("mandrill_128.");
     99         filename.append(this->fileExtension());
    100         SkAutoTUnref<SkData> fileData(SkData::NewFromFileName(filename.c_str()));
    101         if (NULL == fileData) {
    102             SkDebugf("Could not open the file. Did you forget to set the resourcePath?\n");
    103             return;
    104         }
    105 
    106         if (!SkInstallDiscardablePixelRef(
    107                 SkDecodingImageGenerator::Create(
    108                     fileData, SkDecodingImageGenerator::Options()), &bm)) {
    109             SkDebugf("Could not install discardable pixel ref.\n");
    110             return;
    111         }
    112 
    113         canvas->drawBitmap(bm, 0, 0);
    114     }
    115 
    116 private:
    117     typedef GM INHERITED;
    118 };
    119 
    120 // This class specializes ETC1BitmapGM to load the mandrill_128.pkm file.
    121 class ETC1Bitmap_PKM_GM : public ETC1BitmapGM {
    122 public:
    123     ETC1Bitmap_PKM_GM() : ETC1BitmapGM() { }
    124     virtual ~ETC1Bitmap_PKM_GM() { }
    125 
    126 protected:
    127 
    128     virtual SkString fileExtension() const SK_OVERRIDE { return SkString("pkm"); }
    129 
    130 private:
    131     typedef ETC1BitmapGM INHERITED;
    132 };
    133 
    134 // This class specializes ETC1BitmapGM to load the mandrill_128.ktx file.
    135 class ETC1Bitmap_KTX_GM : public ETC1BitmapGM {
    136 public:
    137     ETC1Bitmap_KTX_GM() : ETC1BitmapGM() { }
    138     virtual ~ETC1Bitmap_KTX_GM() { }
    139 
    140 protected:
    141 
    142     virtual SkString fileExtension() const SK_OVERRIDE { return SkString("ktx"); }
    143 
    144 private:
    145     typedef ETC1BitmapGM INHERITED;
    146 };
    147 
    148 // This class specializes ETC1BitmapGM to load the mandrill_128.r11.ktx file.
    149 class ETC1Bitmap_R11_KTX_GM : public ETC1BitmapGM {
    150 public:
    151     ETC1Bitmap_R11_KTX_GM() : ETC1BitmapGM() { }
    152     virtual ~ETC1Bitmap_R11_KTX_GM() { }
    153 
    154 protected:
    155 
    156     virtual SkString fileExtension() const SK_OVERRIDE { return SkString("r11.ktx"); }
    157 
    158 private:
    159     typedef ETC1BitmapGM INHERITED;
    160 };
    161 
    162 #ifndef SK_IGNORE_ETC1_SUPPORT
    163 /**
    164  *  Test decoding an image from a PKM file and then
    165  *  from non-power-of-two compressed ETC1 data. First slice
    166  *  off a row and column of blocks in order to make it non-power
    167  *  of two.
    168  */
    169 class ETC1Bitmap_NPOT_GM : public GM {
    170 public:
    171     ETC1Bitmap_NPOT_GM() { }
    172     virtual ~ETC1Bitmap_NPOT_GM() { }
    173 
    174 protected:
    175     virtual SkString onShortName() SK_OVERRIDE {
    176         return SkString("etc1bitmap_npot");
    177     }
    178 
    179     virtual SkISize onISize() SK_OVERRIDE {
    180         return SkISize::Make(124, 124);
    181     }
    182 
    183     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
    184         SkBitmap bm;
    185         SkString pkmFilename = GetResourcePath("mandrill_128.pkm");
    186         SkAutoDataUnref fileData(SkData::NewFromFileName(pkmFilename.c_str()));
    187         if (NULL == fileData) {
    188             SkDebugf("Could not open the file. Did you forget to set the resourcePath?\n");
    189             return;
    190         }
    191 
    192         SkAutoMalloc am(fileData->size());
    193         memcpy(am.get(), fileData->data(), fileData->size());
    194 
    195         int width, height;
    196         if (!slice_etc1_data(am.get(), &width, &height)) {
    197             SkDebugf("ETC1 Data is poorly formatted.\n");
    198             return;
    199         }
    200 
    201         SkASSERT(124 == width);
    202         SkASSERT(124 == height);
    203 
    204         size_t dataSz = etc1_get_encoded_data_size(width, height) + ETC_PKM_HEADER_SIZE;
    205         SkAutoDataUnref nonPOTData(SkData::NewWithCopy(am.get(), dataSz));
    206 
    207         if (!SkInstallDiscardablePixelRef(
    208                 SkDecodingImageGenerator::Create(
    209                     nonPOTData, SkDecodingImageGenerator::Options()), &bm)) {
    210             SkDebugf("Could not install discardable pixel ref.\n");
    211             return;
    212         }
    213 
    214         canvas->drawBitmap(bm, 0, 0);
    215     }
    216 
    217 private:
    218     typedef GM INHERITED;
    219 };
    220 #endif  // SK_IGNORE_ETC1_SUPPORT
    221 
    222 }  // namespace skiagm
    223 
    224 //////////////////////////////////////////////////////////////////////////////
    225 
    226 DEF_GM( return SkNEW(skiagm::ETC1Bitmap_PKM_GM); )
    227 DEF_GM( return SkNEW(skiagm::ETC1Bitmap_KTX_GM); )
    228 DEF_GM( return SkNEW(skiagm::ETC1Bitmap_R11_KTX_GM); )
    229 
    230 #ifndef SK_IGNORE_ETC1_SUPPORT
    231 DEF_GM( return SkNEW(skiagm::ETC1Bitmap_NPOT_GM); )
    232 #endif  // SK_IGNORE_ETC1_SUPPORT
    233