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