|  | /* | 
|  | * Copyright 2015 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #include "CodecBenchPriv.h" | 
|  | #include "DecodingBench.h" | 
|  | #include "SkBitmap.h" | 
|  | #include "SkData.h" | 
|  | #include "SkImageDecoder.h" | 
|  | #include "SkMallocPixelRef.h" | 
|  | #include "SkOSFile.h" | 
|  | #include "SkStream.h" | 
|  |  | 
|  | /* | 
|  | * | 
|  | * This benchmark is designed to test the performance of image decoding. | 
|  | * It is invoked from the nanobench.cpp file. | 
|  | * | 
|  | */ | 
|  | DecodingBench::DecodingBench(SkString path, SkColorType colorType) | 
|  | : fColorType(colorType) | 
|  | , fData(SkData::NewFromFileName(path.c_str())) | 
|  | { | 
|  | // Parse filename and the color type to give the benchmark a useful name | 
|  | SkString baseName = SkOSPath::Basename(path.c_str()); | 
|  | fName.printf("Decode_%s_%s", baseName.c_str(), color_type_to_str(colorType)); | 
|  |  | 
|  | #ifdef SK_DEBUG | 
|  | // Ensure that we can create a decoder. | 
|  | SkAutoTDelete<SkStreamRewindable> stream(new SkMemoryStream(fData)); | 
|  | SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream)); | 
|  | SkASSERT(decoder != nullptr); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | const char* DecodingBench::onGetName() { | 
|  | return fName.c_str(); | 
|  | } | 
|  |  | 
|  | bool DecodingBench::isSuitableFor(Backend backend) { | 
|  | return kNonRendering_Backend == backend; | 
|  | } | 
|  |  | 
|  | void DecodingBench::onDelayedSetup() { | 
|  | // Allocate the pixels now, to remove it from the loop. | 
|  | SkAutoTDelete<SkStreamRewindable> stream(new SkMemoryStream(fData)); | 
|  | SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream)); | 
|  | SkBitmap bm; | 
|  | #ifdef SK_DEBUG | 
|  | SkImageDecoder::Result result = | 
|  | #endif | 
|  | decoder->decode(stream, &bm, fColorType, SkImageDecoder::kDecodeBounds_Mode); | 
|  | SkASSERT(SkImageDecoder::kFailure != result); | 
|  |  | 
|  | const size_t rowBytes = bm.info().minRowBytes(); | 
|  | fPixelStorage.reset(bm.info().getSafeSize(rowBytes)); | 
|  | } | 
|  |  | 
|  | // Allocator which just uses an existing block of memory. | 
|  | class TargetAllocator : public SkBitmap::Allocator { | 
|  | public: | 
|  | explicit TargetAllocator(void* storage) | 
|  | : fPixelStorage(storage) {} | 
|  |  | 
|  | bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) override { | 
|  | // We depend on the fact that this will only ever be used to | 
|  | // decode to a bitmap with the same settings used to create | 
|  | // fPixelStorage. | 
|  | bm->setPixelRef(SkMallocPixelRef::NewDirect(bm->info(), | 
|  | fPixelStorage, bm->rowBytes(), ct))->unref(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | private: | 
|  | void* fPixelStorage; // Unowned. DecodingBench owns this. | 
|  | }; | 
|  |  | 
|  | void DecodingBench::onDraw(int n, SkCanvas* canvas) { | 
|  | SkBitmap bitmap; | 
|  | // Declare the allocator before the decoder, so it will outlive the | 
|  | // decoder, which will unref it. | 
|  | TargetAllocator allocator(fPixelStorage.get()); | 
|  | SkAutoTDelete<SkImageDecoder> decoder; | 
|  | SkAutoTDelete<SkStreamRewindable> stream; | 
|  | for (int i = 0; i < n; i++) { | 
|  | // create a new stream and a new decoder to mimic the behavior of | 
|  | // CodecBench. | 
|  | stream.reset(new SkMemoryStream(fData)); | 
|  | decoder.reset(SkImageDecoder::Factory(stream)); | 
|  | decoder->setAllocator(&allocator); | 
|  | decoder->decode(stream, &bitmap, fColorType, | 
|  | SkImageDecoder::kDecodePixels_Mode); | 
|  | } | 
|  | } |