OLD | NEW |
| (Empty) |
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 "Benchmark.h" | |
9 #include "Resources.h" | |
10 #include "SkCanvas.h" | |
11 #include "SkData.h" | |
12 #include "SkImageGenerator.h" | |
13 #include "SkImageDecoder.h" | |
14 #include "SkOSFile.h" | |
15 #include "SkPixelRef.h" | |
16 | |
17 #ifndef SK_IGNORE_ETC1_SUPPORT | |
18 | |
19 #include "etc1.h" | |
20 | |
21 // This takes the etc1 data pointed to by orig, and copies it `factor` times in
each | |
22 // dimension. The return value is the new data or nullptr on error. | |
23 static etc1_byte* create_expanded_etc1_bitmap(const uint8_t* orig, int factor) { | |
24 SkASSERT(orig); | |
25 SkASSERT(factor > 1); | |
26 | |
27 const etc1_byte* origData = reinterpret_cast<const etc1_byte*>(orig); | |
28 if (!etc1_pkm_is_valid(orig)) { | |
29 return nullptr; | |
30 } | |
31 | |
32 etc1_uint32 origWidth = etc1_pkm_get_width(origData); | |
33 etc1_uint32 origHeight = etc1_pkm_get_height(origData); | |
34 | |
35 // The width and height must be aligned along block boundaries | |
36 static const etc1_uint32 kETC1BlockWidth = 4; | |
37 static const etc1_uint32 kETC1BlockHeight = 4; | |
38 if ((origWidth % kETC1BlockWidth) != 0 || | |
39 (origHeight % kETC1BlockHeight) != 0) { | |
40 return nullptr; | |
41 } | |
42 | |
43 // The picture must be at least as large as a block. | |
44 if (origWidth <= kETC1BlockWidth || origHeight <= kETC1BlockHeight) { | |
45 return nullptr; | |
46 } | |
47 | |
48 etc1_uint32 newWidth = origWidth * factor; | |
49 etc1_uint32 newHeight = origHeight * factor; | |
50 | |
51 etc1_uint32 newDataSz = etc1_get_encoded_data_size(newWidth, newHeight); | |
52 etc1_byte* newData = reinterpret_cast<etc1_byte *>( | |
53 sk_malloc_throw(newDataSz + ETC_PKM_HEADER_SIZE)); | |
54 etc1_pkm_format_header(newData, newWidth, newHeight); | |
55 | |
56 etc1_byte* copyInto = newData; | |
57 | |
58 copyInto += ETC_PKM_HEADER_SIZE; | |
59 origData += ETC_PKM_HEADER_SIZE; | |
60 | |
61 etc1_uint32 origBlocksX = (origWidth >> 2); | |
62 etc1_uint32 origBlocksY = (origHeight >> 2); | |
63 etc1_uint32 newBlocksY = (newHeight >> 2); | |
64 etc1_uint32 origRowSzInBytes = origBlocksX * ETC1_ENCODED_BLOCK_SIZE; | |
65 | |
66 for (etc1_uint32 j = 0; j < newBlocksY; ++j) { | |
67 const etc1_byte* rowStart = origData + ((j % origBlocksY) * origRowSzInB
ytes); | |
68 for(etc1_uint32 i = 0; i < newWidth; i += origWidth) { | |
69 memcpy(copyInto, rowStart, origRowSzInBytes); | |
70 copyInto += origRowSzInBytes; | |
71 } | |
72 } | |
73 return newData; | |
74 } | |
75 | |
76 // Defined in SkImageDecoder_ktx.cpp | |
77 extern SkImageGenerator* decoder_image_generator(SkData*); | |
78 | |
79 // This is the base class for all of the benches in this file. In general | |
80 // the ETC1 benches should all be working on the same data. Due to the | |
81 // simplicity of the PKM file, that data is the 128x128 mandrill etc1 | |
82 // compressed texture repeated by some factor (currently 8 -> 1024x1024) | |
83 class ETCBitmapBenchBase : public Benchmark { | |
84 public: | |
85 ETCBitmapBenchBase() : fPKMData(loadPKM()) { | |
86 if (nullptr == fPKMData) { | |
87 SkDebugf("Could not load PKM data!\n"); | |
88 } | |
89 } | |
90 | |
91 protected: | |
92 SkAutoDataUnref fPKMData; | |
93 | |
94 private: | |
95 SkData* loadPKM() { | |
96 SkString pkmFilename = GetResourcePath("mandrill_128.pkm"); | |
97 // Expand the data | |
98 SkAutoDataUnref fileData(SkData::NewFromFileName(pkmFilename.c_str())); | |
99 if (nullptr == fileData) { | |
100 SkDebugf("Could not open the file. Did you forget to set the resourc
ePath?\n"); | |
101 return nullptr; | |
102 } | |
103 | |
104 const etc1_uint32 kExpansionFactor = 8; | |
105 etc1_byte* expandedETC1 = | |
106 create_expanded_etc1_bitmap(fileData->bytes(), kExpansionFactor); | |
107 if (nullptr == expandedETC1) { | |
108 SkDebugf("Error expanding ETC1 data by factor of %d\n", kExpansionFa
ctor); | |
109 return nullptr; | |
110 } | |
111 | |
112 etc1_uint32 width = etc1_pkm_get_width(expandedETC1); | |
113 etc1_uint32 height = etc1_pkm_get_width(expandedETC1); | |
114 etc1_uint32 dataSz = ETC_PKM_HEADER_SIZE + etc1_get_encoded_data_size(wi
dth, height); | |
115 return SkData::NewFromMalloc(expandedETC1, dataSz); | |
116 } | |
117 | |
118 typedef Benchmark INHERITED; | |
119 }; | |
120 | |
121 // This is the rendering benchmark. Prior to rendering the data, create a | |
122 // bitmap using the etc1 data. | |
123 class ETCBitmapBench : public ETCBitmapBenchBase { | |
124 public: | |
125 ETCBitmapBench(bool decompress, Backend backend) | |
126 : fDecompress(decompress), fBackend(backend) { } | |
127 | |
128 bool isSuitableFor(Backend backend) override { | |
129 return SkToBool(fImage) && backend == this->fBackend; | |
130 } | |
131 | |
132 protected: | |
133 const char* onGetName() override { | |
134 if (kGPU_Backend == this->fBackend) { | |
135 if (this->fDecompress) { | |
136 return "etc1bitmap_render_gpu_decompressed"; | |
137 } else { | |
138 return "etc1bitmap_render_gpu_compressed"; | |
139 } | |
140 } else { | |
141 SkASSERT(kRaster_Backend == this->fBackend); | |
142 if (this->fDecompress) { | |
143 return "etc1bitmap_render_raster_decompressed"; | |
144 } else { | |
145 return "etc1bitmap_render_raster_compressed"; | |
146 } | |
147 } | |
148 } | |
149 | |
150 void onDelayedSetup() override { | |
151 if (nullptr == fPKMData) { | |
152 SkDebugf("Failed to load PKM data!\n"); | |
153 return; | |
154 } | |
155 | |
156 if (fDecompress) { | |
157 SkAutoTDelete<SkImageGenerator> gen(decoder_image_generator(fPKMData
)); | |
158 gen->generateBitmap(&fBitmap); | |
159 } else { | |
160 fImage.reset(SkImage::NewFromGenerator(decoder_image_generator(fPKMD
ata))); | |
161 } | |
162 } | |
163 | |
164 void onDraw(int loops, SkCanvas* canvas) override { | |
165 for (int i = 0; i < loops; ++i) { | |
166 if (fDecompress) { | |
167 canvas->drawBitmap(this->fBitmap, 0, 0, nullptr); | |
168 } else { | |
169 canvas->drawImage(fImage, 0, 0, nullptr); | |
170 } | |
171 } | |
172 } | |
173 | |
174 protected: | |
175 SkBitmap fBitmap; | |
176 SkAutoTUnref<SkImage> fImage; | |
177 | |
178 bool decompress() const { return fDecompress; } | |
179 Backend backend() const { return fBackend; } | |
180 private: | |
181 const bool fDecompress; | |
182 const Backend fBackend; | |
183 typedef ETCBitmapBenchBase INHERITED; | |
184 }; | |
185 | |
186 // This benchmark is identical to the previous benchmark, but it explicitly forc
es | |
187 // an upload to the GPU before each draw call. We do this by notifying the bitma
p | |
188 // that the pixels have changed (even though they haven't). | |
189 class ETCBitmapUploadBench : public ETCBitmapBench { | |
190 public: | |
191 ETCBitmapUploadBench(bool decompress, Backend backend) | |
192 : ETCBitmapBench(decompress, backend) { } | |
193 | |
194 protected: | |
195 const char* onGetName() override { | |
196 if (kGPU_Backend == this->backend()) { | |
197 if (this->decompress()) { | |
198 return "etc1bitmap_upload_gpu_decompressed"; | |
199 } else { | |
200 return "etc1bitmap_upload_gpu_compressed"; | |
201 } | |
202 } else { | |
203 SkASSERT(kRaster_Backend == this->backend()); | |
204 if (this->decompress()) { | |
205 return "etc1bitmap_upload_raster_decompressed"; | |
206 } else { | |
207 return "etc1bitmap_upload_raster_compressed"; | |
208 } | |
209 } | |
210 } | |
211 | |
212 void onDraw(int loops, SkCanvas* canvas) override { | |
213 SkPixelRef* pr = fBitmap.pixelRef(); | |
214 for (int i = 0; i < loops; ++i) { | |
215 if (pr) { | |
216 pr->notifyPixelsChanged(); | |
217 } | |
218 canvas->drawBitmap(this->fBitmap, 0, 0, nullptr); | |
219 } | |
220 } | |
221 | |
222 private: | |
223 typedef ETCBitmapBench INHERITED; | |
224 }; | |
225 | |
226 DEF_BENCH(return new ETCBitmapBench(false, Benchmark::kRaster_Backend);) | |
227 DEF_BENCH(return new ETCBitmapBench(true, Benchmark::kRaster_Backend);) | |
228 | |
229 DEF_BENCH(return new ETCBitmapBench(false, Benchmark::kGPU_Backend);) | |
230 DEF_BENCH(return new ETCBitmapBench(true, Benchmark::kGPU_Backend);) | |
231 | |
232 DEF_BENCH(return new ETCBitmapUploadBench(false, Benchmark::kRaster_Backend);) | |
233 DEF_BENCH(return new ETCBitmapUploadBench(true, Benchmark::kRaster_Backend);) | |
234 | |
235 DEF_BENCH(return new ETCBitmapUploadBench(false, Benchmark::kGPU_Backend);) | |
236 DEF_BENCH(return new ETCBitmapUploadBench(true, Benchmark::kGPU_Backend);) | |
237 | |
238 #endif // SK_IGNORE_ETC1_SUPPORT | |
OLD | NEW |