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  */
DecodingBench(SkString path,SkColorType colorType)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 
onGetName()52 const char* DecodingBench::onGetName() {
53     return fName.c_str();
54 }
55 
isSuitableFor(Backend backend)56 bool DecodingBench::isSuitableFor(Backend backend) {
57     return kNonRendering_Backend == backend;
58 }
59 
onPreDraw()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:
TargetAllocator(void * storage)78     explicit TargetAllocator(void* storage)
79         : fPixelStorage(storage) {}
80 
allocPixelRef(SkBitmap * bm,SkColorTable * ct)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 
onDraw(const int n,SkCanvas * canvas)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