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 */ 22DecodingBench::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 52const char* DecodingBench::onGetName() { 53 return fName.c_str(); 54} 55 56bool DecodingBench::isSuitableFor(Backend backend) { 57 return kNonRendering_Backend == backend; 58} 59 60void 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. 76class TargetAllocator : public SkBitmap::Allocator { 77public: 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 90private: 91 void* fPixelStorage; // Unowned. DecodingBench owns this. 92}; 93 94void 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