/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "ColorCodecBench.h"
#include "Resources.h"
#include "SkCodec.h"
#include "SkColorSpaceXform.h"
#include "SkCommandLineFlags.h"

#if defined(SK_TEST_QCMS)
DEFINE_bool(qcms, false, "Bench qcms color conversion");
#endif
DEFINE_bool(xform_only, false, "Only time the color xform, do not include the decode time");

ColorCodecBench::ColorCodecBench(const char* name, sk_sp<SkData> encoded)
    : fEncoded(std::move(encoded))
#if defined(SK_TEST_QCMS)
    , fDstSpaceQCMS(nullptr)
#endif
{
    fName.appendf("Color%s", FLAGS_xform_only ? "Xform" : "Codec");
#if defined(SK_TEST_QCMS)
    fName.appendf("%s", FLAGS_qcms ? "QCMS" : "");
#endif
    fName.appendf("_%s", name);
}

const char* ColorCodecBench::onGetName() {
    return fName.c_str();
}

bool ColorCodecBench::isSuitableFor(Backend backend) {
    return kNonRendering_Backend == backend;
}

void ColorCodecBench::decodeAndXform() {
    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded.get()));
#ifdef SK_DEBUG
    const SkCodec::Result result =
#endif
    codec->startScanlineDecode(fInfo);
    SkASSERT(SkCodec::kSuccess == result);

    sk_sp<SkColorSpace> srcSpace = sk_ref_sp(codec->getColorSpace());
    if (!srcSpace) {
        srcSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
    }
    std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcSpace, fDstSpace);
    SkASSERT(xform);

    void* dst = fDst.get();
    for (int y = 0; y < fInfo.height(); y++) {
#ifdef SK_DEBUG
        const int rows =
#endif
        codec->getScanlines(fSrc.get(), 1, 0);
        SkASSERT(1 == rows);

        xform->xform_RGBA_8888((uint32_t*) dst, (uint32_t*) fSrc.get(), fInfo.width());
        dst = SkTAddOffset<void>(dst, fInfo.minRowBytes());
    }
}

#if defined(SK_TEST_QCMS)
void ColorCodecBench::decodeAndXformQCMS() {
    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded.get()));
#ifdef SK_DEBUG
    const SkCodec::Result result =
#endif
    codec->startScanlineDecode(fInfo);
    SkASSERT(SkCodec::kSuccess == result);

    SkAutoTCallVProc<qcms_profile, qcms_profile_release>
            srcSpace(qcms_profile_from_memory(fSrcData->data(), fSrcData->size()));
    SkASSERT(srcSpace);

    SkAutoTCallVProc<qcms_transform, qcms_transform_release>
            transform (qcms_transform_create(srcSpace, QCMS_DATA_RGBA_8, fDstSpaceQCMS.get(),
                                             QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL));
    SkASSERT(transform);

#ifdef SK_PMCOLOR_IS_RGBA
    qcms_output_type outType = QCMS_OUTPUT_RGBX;
#else
    qcms_output_type outType = QCMS_OUTPUT_BGRX;
#endif

    void* dst = fDst.get();
    for (int y = 0; y < fInfo.height(); y++) {
#ifdef SK_DEBUG
        const int rows =
#endif
        codec->getScanlines(fSrc.get(), 1, 0);
        SkASSERT(1 == rows);

        qcms_transform_data_type(transform, fSrc.get(), dst, fInfo.width(), outType);
        dst = SkTAddOffset<void>(dst, fInfo.minRowBytes());
    }
}
#endif

void ColorCodecBench::xformOnly() {
    sk_sp<SkColorSpace> srcSpace = SkColorSpace::NewICC(fSrcData->data(), fSrcData->size());
    if (!srcSpace) {
        srcSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
    }
    std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcSpace, fDstSpace);
    SkASSERT(xform);

    void* dst = fDst.get();
    void* src = fSrc.get();
    for (int y = 0; y < fInfo.height(); y++) {
        // Transform in place
        xform->xform_RGBA_8888((uint32_t*) dst, (uint32_t*) src, fInfo.width());
        dst = SkTAddOffset<void>(dst, fInfo.minRowBytes());
        src = SkTAddOffset<void>(src, fInfo.minRowBytes());
    }
}

#if defined(SK_TEST_QCMS)
void ColorCodecBench::xformOnlyQCMS() {
    SkAutoTCallVProc<qcms_profile, qcms_profile_release>
            srcSpace(qcms_profile_from_memory(fSrcData->data(), fSrcData->size()));
    SkASSERT(srcSpace);

    SkAutoTCallVProc<qcms_transform, qcms_transform_release>
            transform (qcms_transform_create(srcSpace, QCMS_DATA_RGBA_8, fDstSpaceQCMS.get(),
                                             QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL));
    SkASSERT(transform);

#ifdef SK_PMCOLOR_IS_RGBA
    qcms_output_type outType = QCMS_OUTPUT_RGBX;
#else
    qcms_output_type outType = QCMS_OUTPUT_BGRX;
#endif

    void* dst = fDst.get();
    void* src = fSrc.get();
    for (int y = 0; y < fInfo.height(); y++) {
        // Transform in place
        qcms_transform_data_type(transform, src, dst, fInfo.width(), outType);
        dst = SkTAddOffset<void>(dst, fInfo.minRowBytes());
        src = SkTAddOffset<void>(src, fInfo.minRowBytes());
    }
}
#endif

void ColorCodecBench::onDelayedSetup() {
    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded.get()));
    fInfo = codec->getInfo().makeColorType(kRGBA_8888_SkColorType);

    fDst.reset(fInfo.getSafeSize(fInfo.minRowBytes()));
    if (FLAGS_xform_only) {
        fSrc.reset(fInfo.getSafeSize(fInfo.minRowBytes()));
        codec->getPixels(fInfo, fSrc.get(), fInfo.minRowBytes());
    } else {
        // Set-up a row buffer to decode into before transforming to dst.
        fSrc.reset(fInfo.minRowBytes());
    }

    fSrcData = codec->getICCData();
    sk_sp<SkData> dstData = SkData::MakeFromFileName(
            GetResourcePath("monitor_profiles/HP_ZR30w.icc").c_str());
    SkASSERT(dstData);


#if defined(SK_TEST_QCMS)
    if (FLAGS_qcms) {
        fDstSpaceQCMS.reset(qcms_profile_from_memory(dstData->data(), dstData->size()));
        SkASSERT(fDstSpaceQCMS);
    } else
#endif
    {
        fDstSpace = SkColorSpace::NewICC(dstData->data(), dstData->size());
        SkASSERT(fDstSpace);
    }
}

void ColorCodecBench::onDraw(int n, SkCanvas*) {
    for (int i = 0; i < n; i++) {
#if defined(SK_TEST_QCMS)
        if (FLAGS_qcms) {
            if (FLAGS_xform_only) {
                this->xformOnlyQCMS();
            } else {
                this->decodeAndXformQCMS();
            }
        } else
#endif
        {
            if (FLAGS_xform_only) {
                this->xformOnly();
            } else {
                this->decodeAndXform();
            }
        }
    }
}
