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