diff options
author | msarett <msarett@google.com> | 2016-06-03 08:25:21 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-06-03 08:25:22 -0700 |
commit | 2cee902847a940c4bab56b42dabbb3721be3f9ac (patch) | |
tree | 528c0fdd2139c95f5edf741db7480d977df4f497 | |
parent | 577967c155fe3e2ce8251b053da60bd0d8fb32f4 (diff) |
Add color correction benchmark - with comparison to qcms
--colorImages is empty by default so this won't affect the runtime of
the bots. To run locally, use --colorImages <path> and
--benchType skcolorcodec.
Two takeaways so far:
Color correction is (currently) slower than jpeg decodes.
Our reference solution is slower than qcms.
TBR=reed@google.com
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2035793002
Review-Url: https://codereview.chromium.org/2035793002
-rw-r--r-- | bench/ColorCodecBench.cpp | 202 | ||||
-rw-r--r-- | bench/ColorCodecBench.h | 50 | ||||
-rw-r--r-- | bench/nanobench.cpp | 21 | ||||
-rw-r--r-- | include/codec/SkCodec.h | 5 |
4 files changed, 277 insertions, 1 deletions
diff --git a/bench/ColorCodecBench.cpp b/bench/ColorCodecBench.cpp new file mode 100644 index 0000000000..1b0ddb36ed --- /dev/null +++ b/bench/ColorCodecBench.cpp @@ -0,0 +1,202 @@ +/* + * 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(GOOGLE3) +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(GOOGLE3) + , fDstSpaceQCMS(nullptr) +#endif +{ + fName.appendf("Color%s", FLAGS_xform_only ? "Xform" : "Codec"); +#if !defined(GOOGLE3) + 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(GOOGLE3) +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(GOOGLE3) +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(GOOGLE3) + 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(GOOGLE3) + if (FLAGS_qcms) { + if (FLAGS_xform_only) { + this->xformOnlyQCMS(); + } else { + this->decodeAndXformQCMS(); + } + } else +#endif + { + if (FLAGS_xform_only) { + this->xformOnly(); + } else { + this->decodeAndXform(); + } + } + } +} diff --git a/bench/ColorCodecBench.h b/bench/ColorCodecBench.h new file mode 100644 index 0000000000..570890de26 --- /dev/null +++ b/bench/ColorCodecBench.h @@ -0,0 +1,50 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef ColorCodecBench_DEFINED +#define ColorCodecBench_DEFINED + +#include "Benchmark.h" +#include "SkData.h" +#include "SkImageInfo.h" + +#if !defined(GOOGLE3) +#include "qcms.h" +#endif + +class ColorCodecBench : public Benchmark { +public: + ColorCodecBench(const char* name, sk_sp<SkData> encoded); + +protected: + const char* onGetName() override; + bool isSuitableFor(Backend backend) override; + void onDraw(int n, SkCanvas* canvas) override; + void onDelayedSetup() override; + +private: + void decodeAndXform(); + void xformOnly(); +#if !defined(GOOGLE3) + void decodeAndXformQCMS(); + void xformOnlyQCMS(); +#endif + + SkString fName; + sk_sp<SkData> fEncoded; + SkImageInfo fInfo; + SkAutoMalloc fDst; + SkAutoMalloc fSrc; + sk_sp<SkColorSpace> fDstSpace; +#if !defined(GOOGLE3) + SkAutoTCallVProc<qcms_profile, qcms_profile_release> fDstSpaceQCMS; +#endif + sk_sp<SkData> fSrcData; + + typedef Benchmark INHERITED; +}; +#endif // ColorCodecBench_DEFINED diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp index 55ef34e79d..a7e9ebb855 100644 --- a/bench/nanobench.cpp +++ b/bench/nanobench.cpp @@ -14,6 +14,7 @@ #include "BitmapRegionDecoderBench.h" #include "CodecBench.h" #include "CodecBenchPriv.h" +#include "ColorCodecBench.h" #include "CrashHandler.h" #include "GMBench.h" #include "ProcStats.h" @@ -558,6 +559,7 @@ public: , fCurrentCodec(0) , fCurrentAndroidCodec(0) , fCurrentBRDImage(0) + , fCurrentColorImage(0) , fCurrentColorType(0) , fCurrentAlphaType(0) , fCurrentSubsetType(0) @@ -602,6 +604,9 @@ public: if (!CollectImages(FLAGS_images, &fImages)) { exit(1); } + if (!CollectImages(FLAGS_colorImages, &fColorImages)) { + exit(1); + } // Choose the candidate color types for image decoding const SkColorType colorTypes[] = @@ -917,6 +922,20 @@ public: fCurrentColorType = 0; } + while (fCurrentColorImage < fColorImages.count()) { + fSourceType = "colorimage"; + fBenchType = "skcolorcodec"; + const SkString& path = fColorImages[fCurrentColorImage]; + fCurrentColorImage++; + sk_sp<SkData> encoded = SkData::MakeFromFileName(path.c_str()); + if (encoded) { + return new ColorCodecBench(SkOSPath::Basename(path.c_str()).c_str(), + std::move(encoded)); + } else { + SkDebugf("Could not read file %s.\n", path.c_str()); + } + } + return nullptr; } @@ -960,6 +979,7 @@ private: SkTArray<SkString> fSKPs; SkTArray<bool> fUseMPDs; SkTArray<SkString> fImages; + SkTArray<SkString> fColorImages; SkTArray<SkColorType, true> fColorTypes; SkScalar fZoomMax; double fZoomPeriodMs; @@ -975,6 +995,7 @@ private: int fCurrentCodec; int fCurrentAndroidCodec; int fCurrentBRDImage; + int fCurrentColorImage; int fCurrentColorType; int fCurrentAlphaType; int fCurrentSubsetType; diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h index f931f2bb12..d2e101dea4 100644 --- a/include/codec/SkCodec.h +++ b/include/codec/SkCodec.h @@ -27,6 +27,7 @@ namespace DM { class CodecSrc; class ColorCodecSrc; } +class ColorCodecBench; /** * Abstraction layer directly on top of an image codec. @@ -776,8 +777,10 @@ private: virtual SkSampler* getSampler(bool /*createIfNecessary*/) { return nullptr; } // For testing with qcms - // FIXME: Remove this when we are done comparing with qcms. + // FIXME: Remove these when we are done comparing with qcms. friend class DM::ColorCodecSrc; + friend class ColorCodecBench; + friend class DM::CodecSrc; // for fillIncompleteImage friend class SkSampledCodec; friend class SkIcoCodec; |