 Chromium Code Reviews
 Chromium Code Reviews Issue 317023002:
  Two new benches for ETC1 bitmaps.  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master
    
  
    Issue 317023002:
  Two new benches for ETC1 bitmaps.  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master| OLD | NEW | 
|---|---|
| (Empty) | |
| 1 /* | |
| 
robertphillips
2014/06/04 18:53:36
2014 ?
 
krajcevski
2014/06/04 19:26:53
Done.
 | |
| 2 * Copyright 2013 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 "SkBenchmark.h" | |
| 
robertphillips
2014/06/04 18:53:36
Do we need SkBitmapDevice.h ?
 
krajcevski
2014/06/04 19:26:53
Nope. Removed.
 | |
| 9 #include "SkBitmapDevice.h" | |
| 10 #include "SkCanvas.h" | |
| 11 #include "SkData.h" | |
| 12 #include "SkDecodingImageGenerator.h" | |
| 13 #include "SkImageDecoder.h" | |
| 14 #include "SkOSFile.h" | |
| 15 | |
| 16 #ifndef SK_IGNORE_ETC1_SUPPORT | |
| 17 | |
| 18 #include "etc1.h" | |
| 19 | |
| 20 // This takes the etc1 data pointed to by orig, and copies it `factor` times in each | |
| 21 // dimension. The return value is the new data or NULL on error. | |
| 22 static etc1_byte* create_expanded_etc1_bitmap(const uint8_t* orig, int factor) { | |
| 23 SkASSERT(NULL != orig); | |
| 24 SkASSERT(factor > 1); | |
| 25 | |
| 26 const etc1_byte* origData = reinterpret_cast<const etc1_byte*>(orig); | |
| 27 if (!etc1_pkm_is_valid(orig)) { | |
| 28 return NULL; | |
| 29 } | |
| 30 | |
| 31 etc1_uint32 origWidth = etc1_pkm_get_width(origData); | |
| 32 etc1_uint32 origHeight = etc1_pkm_get_height(origData); | |
| 33 | |
| 34 // The width and height must be aligned along block boundaries | |
| 35 if ((origWidth & 3) != 0 || (origHeight & 3) != 0) { | |
| 36 return NULL; | |
| 37 } | |
| 38 | |
| 39 // The picture must be at least as large as a block. | |
| 
robertphillips
2014/06/04 18:53:36
Is the block width & height already #defined somew
 
krajcevski
2014/06/04 19:26:53
No, but "everyone knows" etc1 data is 4x4 pixel bl
 
robertphillips
2014/06/04 19:46:37
Probably just put a "static const int kETC1BlockSi
 
krajcevski
2014/06/04 19:57:16
Done.
 | |
| 40 if (origWidth <= 4 || origHeight <= 4) { | |
| 41 return NULL; | |
| 42 } | |
| 43 | |
| 44 etc1_uint32 newWidth = origWidth * factor; | |
| 45 etc1_uint32 newHeight = origHeight * factor; | |
| 46 | |
| 47 etc1_uint32 newDataSz = etc1_get_encoded_data_size(newWidth, newHeight); | |
| 48 etc1_byte* newData = reinterpret_cast<etc1_byte *>( | |
| 49 sk_malloc_throw(newDataSz + ETC_PKM_HEADER_SIZE)); | |
| 50 etc1_pkm_format_header(newData, newWidth, newHeight); | |
| 51 | |
| 52 etc1_byte* copyInto = newData; | |
| 53 | |
| 54 copyInto += ETC_PKM_HEADER_SIZE; | |
| 55 origData += ETC_PKM_HEADER_SIZE; | |
| 56 | |
| 57 etc1_uint32 origBlocksX = (origWidth >> 2); | |
| 58 etc1_uint32 origBlocksY = (origHeight >> 2); | |
| 59 etc1_uint32 newBlocksY = (newHeight >> 2); | |
| 60 etc1_uint32 origRowSzInBytes = origBlocksX * ETC1_ENCODED_BLOCK_SIZE; | |
| 61 | |
| 62 for (etc1_uint32 j = 0; j < newBlocksY; ++j) { | |
| 63 etc1_uint32 row = j % origBlocksY; | |
| 64 for(etc1_uint32 i = 0; i < newWidth; i += origWidth) { | |
| 
robertphillips
2014/06/04 18:53:36
rename rowStart to be srcRow and move it out of th
 
krajcevski
2014/06/04 19:26:53
Done.
 | |
| 65 const etc1_byte* rowStart = origData + (row * origRowSzInBytes); | |
| 66 memcpy(copyInto, rowStart, origRowSzInBytes); | |
| 67 copyInto += origRowSzInBytes; | |
| 68 } | |
| 69 } | |
| 70 return newData; | |
| 71 } | |
| 72 | |
| 73 // This is the base class for all of the benches in this file. In general | |
| 74 // the ETC1 benches should all be working on the same data. Due to the | |
| 75 // simplicity of the PKM file, that data is the 128x128 mandrill etc1 | |
| 76 // compressed texture repeated by some factor (currently 8 -> 1024x1024) | |
| 77 class ETCBitmapBenchBase : public SkBenchmark { | |
| 78 public: | |
| 
robertphillips
2014/06/04 18:53:36
Don't think you need explicit here.
this->loadPKM(
 
krajcevski
2014/06/04 19:26:53
Done.
 | |
| 79 explicit ETCBitmapBenchBase() : fPKMData(loadPKM()) { | |
| 80 if (NULL == fPKMData) { | |
| 81 SkDebugf("Could not load PKM data!"); | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 protected: | |
| 86 SkAutoDataUnref fPKMData; | |
| 87 | |
| 88 private: | |
| 89 SkData *loadPKM() { | |
| 90 SkString filename = SkOSPath::SkPathJoin( | |
| 91 INHERITED::GetResourcePath().c_str(), "mandrill_128.pkm"); | |
| 92 | |
| 93 // Expand the data | |
| 94 SkAutoDataUnref fileData(SkData::NewFromFileName(filename.c_str())); | |
| 95 if (NULL == fileData) { | |
| 96 SkDebugf("Could not open the file. Did you forget to set the resourc ePath?\n"); | |
| 97 return NULL; | |
| 98 } | |
| 99 | |
| 
robertphillips
2014/06/04 18:53:36
static const etc1_uint32 kExpansionFactor = 8; ?
 
krajcevski
2014/06/04 19:26:53
Done.
 | |
| 100 const etc1_uint32 factor = 8; | |
| 101 etc1_byte* expandedETC1 = create_expanded_etc1_bitmap(fileData->bytes(), factor); | |
| 102 if (NULL == expandedETC1) { | |
| 103 SkDebugf("Error expanding ETC1 data by factor of %d\n", factor); | |
| 104 return NULL; | |
| 105 } | |
| 106 | |
| 107 etc1_uint32 width = etc1_pkm_get_width(expandedETC1); | |
| 108 etc1_uint32 height = etc1_pkm_get_width(expandedETC1); | |
| 109 etc1_uint32 dataSz = ETC_PKM_HEADER_SIZE + etc1_get_encoded_data_size(wi dth, height); | |
| 110 return SkData::NewFromMalloc(expandedETC1, dataSz); | |
| 111 } | |
| 112 | |
| 113 typedef SkBenchmark INHERITED; | |
| 114 }; | |
| 115 | |
| 116 // This is the rendering benchmark. Prior to rendering the data, create a | |
| 117 // bitmap using the etc1 data. We repurpose the isSuitableFor override since it | |
| 118 // gets called on every config outside of the timing loop. | |
| 119 class ETCBitmapBench : public ETCBitmapBenchBase { | |
| 120 public: | |
| 121 explicit ETCBitmapBench(bool decompress) : fDecompress(decompress) { } | |
| 122 | |
| 123 protected: | |
| 124 virtual const char* onGetName() SK_OVERRIDE { | |
| 125 if (fDecompress) { | |
| 126 return "etc1bitmap_render_decompressed"; | |
| 127 } else { | |
| 128 return "etc1bitmap_render_compressed"; | |
| 129 } | |
| 130 } | |
| 131 | |
| 
robertphillips
2014/06/04 18:53:36
I think we should actually parameterize the bench
 
krajcevski
2014/06/04 19:26:53
Done.
 | |
| 132 virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { | |
| 133 // !HACK! Since this function gets called on every config | |
| 134 // we can create our bitmap here so that it doesn't get | |
| 135 // decompressed in 8888 and then rendered as a bitmap in | |
| 136 // the gpu... | |
| 137 if (NULL == fPKMData) { | |
| 138 return false; | |
| 139 } | |
| 140 | |
| 141 // Install pixel ref | |
| 142 if (!SkInstallDiscardablePixelRef( | |
| 143 SkDecodingImageGenerator::Create( | |
| 144 fPKMData, SkDecodingImageGenerator::Options()), &(this->fBit map))) { | |
| 145 SkDebugf("Could not install discardable pixel ref.\n"); | |
| 146 // !HACK! If there was an error don't bother rendering for this conf ig... | |
| 147 return false; | |
| 148 } | |
| 149 | |
| 150 // Decompress it if necessary | |
| 151 if (this->fDecompress) { | |
| 152 this->fBitmap.lockPixels(); | |
| 153 } | |
| 154 | |
| 155 // What this function is actually for | |
| 156 return backend == kRaster_Backend || backend == kGPU_Backend; | |
| 157 } | |
| 158 | |
| 159 virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { | |
| 160 for (int i = 0; i < loops; i++) { | |
| 161 canvas->drawBitmap(this->fBitmap, 0, 0, NULL); | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 protected: | |
| 166 SkBitmap fBitmap; | |
| 167 bool decompress() const { return fDecompress; } | |
| 168 private: | |
| 169 const bool fDecompress; | |
| 170 typedef ETCBitmapBenchBase INHERITED; | |
| 171 }; | |
| 172 | |
| 173 // This benchmark is identical to the previous benchmark, but it explicitly forc es | |
| 174 // an upload to the GPU before each draw call. We do this by notifying the bitma p | |
| 175 // that the pixels have changed (even though they haven't). | |
| 176 class ETCBitmapUploadBench : public ETCBitmapBench { | |
| 177 public: | |
| 178 explicit ETCBitmapUploadBench(bool decompress) : ETCBitmapBench(decompress) { } | |
| 179 | |
| 180 protected: | |
| 181 virtual const char* onGetName() SK_OVERRIDE { | |
| 182 if (this->decompress()) { | |
| 183 return "etc1bitmap_upload_decompressed"; | |
| 184 } else { | |
| 185 return "etc1bitmap_upload_compressed"; | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { | |
| 190 for (int i = 0; i < loops; i++) { | |
| 191 this->fBitmap.notifyPixelsChanged(); | |
| 192 canvas->drawBitmap(this->fBitmap, 0, 0, NULL); | |
| 193 } | |
| 194 } | |
| 195 | |
| 196 private: | |
| 197 typedef ETCBitmapBenchBase INHERITED; | |
| 198 }; | |
| 199 | |
| 200 DEF_BENCH(return new ETCBitmapBench(false);) | |
| 201 DEF_BENCH(return new ETCBitmapBench(true);) | |
| 202 | |
| 203 DEF_BENCH(return new ETCBitmapUploadBench(false);) | |
| 204 DEF_BENCH(return new ETCBitmapUploadBench(true);) | |
| 205 | |
| 206 #endif // SK_IGNORE_ETC1_SUPPORT | |
| OLD | NEW |