/*
 * 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);
    }
}
