| 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 |