• 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 resourcePath = GetResourcePath();
99         SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), "mandrill_128.");
100         filename.append(this->fileExtension());
101 
102         SkAutoTUnref<SkData> fileData(SkData::NewFromFileName(filename.c_str()));
103         if (NULL == fileData) {
104             SkDebugf("Could not open the file. Did you forget to set the resourcePath?\n");
105             return;
106         }
107 
108         if (!SkInstallDiscardablePixelRef(
109                 SkDecodingImageGenerator::Create(
110                     fileData, SkDecodingImageGenerator::Options()), &bm)) {
111             SkDebugf("Could not install discardable pixel ref.\n");
112             return;
113         }
114 
115         canvas->drawBitmap(bm, 0, 0);
116     }
117 
118 private:
119     typedef GM INHERITED;
120 };
121 
122 // This class specializes ETC1BitmapGM to load the mandrill_128.pkm file.
123 class ETC1Bitmap_PKM_GM : public ETC1BitmapGM {
124 public:
ETC1Bitmap_PKM_GM()125     ETC1Bitmap_PKM_GM() : ETC1BitmapGM() { }
~ETC1Bitmap_PKM_GM()126     virtual ~ETC1Bitmap_PKM_GM() { }
127 
128 protected:
129 
fileExtension() const130     virtual SkString fileExtension() const SK_OVERRIDE { return SkString("pkm"); }
131 
132 private:
133     typedef ETC1BitmapGM INHERITED;
134 };
135 
136 // This class specializes ETC1BitmapGM to load the mandrill_128.ktx file.
137 class ETC1Bitmap_KTX_GM : public ETC1BitmapGM {
138 public:
ETC1Bitmap_KTX_GM()139     ETC1Bitmap_KTX_GM() : ETC1BitmapGM() { }
~ETC1Bitmap_KTX_GM()140     virtual ~ETC1Bitmap_KTX_GM() { }
141 
142 protected:
143 
fileExtension() const144     virtual SkString fileExtension() const SK_OVERRIDE { return SkString("ktx"); }
145 
146 private:
147     typedef ETC1BitmapGM INHERITED;
148 };
149 
150 #ifndef SK_IGNORE_ETC1_SUPPORT
151 /**
152  *  Test decoding an image from a PKM file and then
153  *  from non-power-of-two compressed ETC1 data. First slice
154  *  off a row and column of blocks in order to make it non-power
155  *  of two.
156  */
157 class ETC1Bitmap_NPOT_GM : public GM {
158 public:
ETC1Bitmap_NPOT_GM()159     ETC1Bitmap_NPOT_GM() { }
~ETC1Bitmap_NPOT_GM()160     virtual ~ETC1Bitmap_NPOT_GM() { }
161 
162 protected:
onShortName()163     virtual SkString onShortName() SK_OVERRIDE {
164         return SkString("etc1bitmap_npot");
165     }
166 
onISize()167     virtual SkISize onISize() SK_OVERRIDE {
168         return SkISize::Make(124, 124);
169     }
170 
onDraw(SkCanvas * canvas)171     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
172         SkBitmap bm;
173         SkString resourcePath = GetResourcePath();
174         SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), "mandrill_128.pkm");
175 
176         SkAutoDataUnref fileData(SkData::NewFromFileName(filename.c_str()));
177         if (NULL == fileData) {
178             SkDebugf("Could not open the file. Did you forget to set the resourcePath?\n");
179             return;
180         }
181 
182         SkAutoMalloc am(fileData->size());
183         memcpy(am.get(), fileData->data(), fileData->size());
184 
185         int width, height;
186         if (!slice_etc1_data(am.get(), &width, &height)) {
187             SkDebugf("ETC1 Data is poorly formatted.\n");
188             return;
189         }
190 
191         SkASSERT(124 == width);
192         SkASSERT(124 == height);
193 
194         size_t dataSz = etc1_get_encoded_data_size(width, height) + ETC_PKM_HEADER_SIZE;
195         SkAutoDataUnref nonPOTData(SkData::NewWithCopy(am.get(), dataSz));
196 
197         if (!SkInstallDiscardablePixelRef(
198                 SkDecodingImageGenerator::Create(
199                     nonPOTData, SkDecodingImageGenerator::Options()), &bm)) {
200             SkDebugf("Could not install discardable pixel ref.\n");
201             return;
202         }
203 
204         canvas->drawBitmap(bm, 0, 0);
205     }
206 
207 private:
208     typedef GM INHERITED;
209 };
210 #endif  // SK_IGNORE_ETC1_SUPPORT
211 
212 }  // namespace skiagm
213 
214 //////////////////////////////////////////////////////////////////////////////
215 
216 DEF_GM( return SkNEW(skiagm::ETC1Bitmap_PKM_GM); )
217 DEF_GM( return SkNEW(skiagm::ETC1Bitmap_KTX_GM); )
218 
219 #ifndef SK_IGNORE_ETC1_SUPPORT
220 DEF_GM( return SkNEW(skiagm::ETC1Bitmap_NPOT_GM); )
221 #endif  // SK_IGNORE_ETC1_SUPPORT
222