• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
slice_etc1_data(void * data,int * width,int * height)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:
ETC1BitmapGM()80     ETC1BitmapGM() { }
~ETC1BitmapGM()81     virtual ~ETC1BitmapGM() { }
82 
83 protected:
onShortName()84     virtual SkString onShortName() SK_OVERRIDE {
85         SkString str = SkString("etc1bitmap_");
86         str.append(this->fileExtension());
87         return str;
88     }
89 
onISize()90     virtual SkISize onISize() SK_OVERRIDE {
91         return SkISize::Make(128, 128);
92     }
93 
94     virtual SkString fileExtension() const = 0;
95 
onDraw(SkCanvas * canvas)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:
ETC1Bitmap_PKM_GM()123     ETC1Bitmap_PKM_GM() : ETC1BitmapGM() { }
~ETC1Bitmap_PKM_GM()124     virtual ~ETC1Bitmap_PKM_GM() { }
125 
126 protected:
127 
fileExtension() const128     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:
ETC1Bitmap_KTX_GM()137     ETC1Bitmap_KTX_GM() : ETC1BitmapGM() { }
~ETC1Bitmap_KTX_GM()138     virtual ~ETC1Bitmap_KTX_GM() { }
139 
140 protected:
141 
fileExtension() const142     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:
ETC1Bitmap_R11_KTX_GM()151     ETC1Bitmap_R11_KTX_GM() : ETC1BitmapGM() { }
~ETC1Bitmap_R11_KTX_GM()152     virtual ~ETC1Bitmap_R11_KTX_GM() { }
153 
154 protected:
155 
fileExtension() const156     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:
ETC1Bitmap_NPOT_GM()171     ETC1Bitmap_NPOT_GM() { }
~ETC1Bitmap_NPOT_GM()172     virtual ~ETC1Bitmap_NPOT_GM() { }
173 
174 protected:
onShortName()175     virtual SkString onShortName() SK_OVERRIDE {
176         return SkString("etc1bitmap_npot");
177     }
178 
onISize()179     virtual SkISize onISize() SK_OVERRIDE {
180         return SkISize::Make(124, 124);
181     }
182 
onDraw(SkCanvas * canvas)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