1 /* 2 * Copyright 2015 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 "DecodingBench.h" 9 #include "SkBitmap.h" 10 #include "SkData.h" 11 #include "SkImageDecoder.h" 12 #include "SkMallocPixelRef.h" 13 #include "SkOSFile.h" 14 #include "SkStream.h" 15 16 /* 17 * 18 * This benchmark is designed to test the performance of image decoding. 19 * It is invoked from the nanobench.cpp file. 20 * 21 */ 22 DecodingBench::DecodingBench(SkString path, SkColorType colorType) 23 : fColorType(colorType) 24 , fData(SkData::NewFromFileName(path.c_str())) 25 { 26 // Parse filename and the color type to give the benchmark a useful name 27 SkString baseName = SkOSPath::Basename(path.c_str()); 28 const char* colorName; 29 switch(colorType) { 30 case kN32_SkColorType: 31 colorName = "N32"; 32 break; 33 case kRGB_565_SkColorType: 34 colorName = "565"; 35 break; 36 case kAlpha_8_SkColorType: 37 colorName = "Alpha8"; 38 break; 39 default: 40 colorName = "Unknown"; 41 } 42 fName.printf("Decode_%s_%s", baseName.c_str(), colorName); 43 44 #ifdef SK_DEBUG 45 // Ensure that we can create a decoder. 46 SkAutoTDelete<SkStreamRewindable> stream(new SkMemoryStream(fData)); 47 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream)); 48 SkASSERT(decoder != NULL); 49 #endif 50 } 51 52 const char* DecodingBench::onGetName() { 53 return fName.c_str(); 54 } 55 56 bool DecodingBench::isSuitableFor(Backend backend) { 57 return kNonRendering_Backend == backend; 58 } 59 60 void DecodingBench::onPreDraw() { 61 // Allocate the pixels now, to remove it from the loop. 62 SkAutoTDelete<SkStreamRewindable> stream(new SkMemoryStream(fData)); 63 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream)); 64 SkBitmap bm; 65 #ifdef SK_DEBUG 66 SkImageDecoder::Result result = 67 #endif 68 decoder->decode(stream, &bm, fColorType, SkImageDecoder::kDecodeBounds_Mode); 69 SkASSERT(SkImageDecoder::kFailure != result); 70 71 const size_t rowBytes = bm.info().minRowBytes(); 72 fPixelStorage.reset(bm.info().getSafeSize(rowBytes)); 73 } 74 75 // Allocator which just uses an existing block of memory. 76 class TargetAllocator : public SkBitmap::Allocator { 77 public: 78 explicit TargetAllocator(void* storage) 79 : fPixelStorage(storage) {} 80 81 bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) override { 82 // We depend on the fact that this will only ever be used to 83 // decode to a bitmap with the same settings used to create 84 // fPixelStorage. 85 bm->setPixelRef(SkMallocPixelRef::NewDirect(bm->info(), 86 fPixelStorage, bm->rowBytes(), ct))->unref(); 87 return true; 88 } 89 90 private: 91 void* fPixelStorage; // Unowned. DecodingBench owns this. 92 }; 93 94 void DecodingBench::onDraw(const int n, SkCanvas* canvas) { 95 SkBitmap bitmap; 96 // Declare the allocator before the decoder, so it will outlive the 97 // decoder, which will unref it. 98 TargetAllocator allocator(fPixelStorage.get()); 99 SkAutoTDelete<SkImageDecoder> decoder; 100 SkAutoTDelete<SkStreamRewindable> stream; 101 for (int i = 0; i < n; i++) { 102 // create a new stream and a new decoder to mimic the behavior of 103 // CodecBench. 104 stream.reset(new SkMemoryStream(fData)); 105 decoder.reset(SkImageDecoder::Factory(stream)); 106 decoder->setAllocator(&allocator); 107 decoder->decode(stream, &bitmap, fColorType, 108 SkImageDecoder::kDecodePixels_Mode); 109 } 110 } 111