ColorCodecBench.cpp revision 31d097e865f266c8398f45114e4c75c0dfdef058
1/*
2 * Copyright 2016 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 "ColorCodecBench.h"
9#include "Resources.h"
10#include "SkCodec.h"
11#include "SkCodecPriv.h"
12#include "SkColorSpaceXform.h"
13#include "SkCommandLineFlags.h"
14
15#if defined(SK_TEST_QCMS)
16DEFINE_bool(qcms,       false, "Bench qcms color conversion");
17#endif
18DEFINE_bool(xform_only, false, "Only time the color xform, do not include the decode time");
19DEFINE_bool(srgb,       false, "Convert to srgb dst space");
20DEFINE_bool(half,       false, "Convert to half floats");
21
22ColorCodecBench::ColorCodecBench(const char* name, sk_sp<SkData> encoded)
23    : fEncoded(std::move(encoded))
24#if defined(SK_TEST_QCMS)
25    , fDstSpaceQCMS(nullptr)
26#endif
27{
28    fName.appendf("Color%s", FLAGS_xform_only ? "Xform" : "Codec");
29#if defined(SK_TEST_QCMS)
30    fName.appendf("%s", FLAGS_qcms ? "QCMS" : "");
31#endif
32    fName.appendf("_%s", name);
33}
34
35const char* ColorCodecBench::onGetName() {
36    return fName.c_str();
37}
38
39bool ColorCodecBench::isSuitableFor(Backend backend) {
40    return kNonRendering_Backend == backend;
41}
42
43void ColorCodecBench::decodeAndXform() {
44    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded));
45    SkASSERT(codec);
46
47#ifdef SK_DEBUG
48    SkCodec::Result result =
49#endif
50    codec->getPixels(fDstInfo, fDst.get(), fDstInfo.minRowBytes());
51    SkASSERT(SkCodec::kSuccess == result);
52}
53
54#if defined(SK_TEST_QCMS)
55void ColorCodecBench::decodeAndXformQCMS() {
56    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded));
57#ifdef SK_DEBUG
58    const SkCodec::Result result =
59#endif
60    codec->startScanlineDecode(fSrcInfo);
61    SkASSERT(SkCodec::kSuccess == result);
62
63    SkAutoTCallVProc<qcms_profile, qcms_profile_release>
64            srcSpace(qcms_profile_from_memory(fSrcData->data(), fSrcData->size()));
65    SkASSERT(srcSpace);
66
67    SkAutoTCallVProc<qcms_transform, qcms_transform_release>
68            transform (qcms_transform_create(srcSpace, QCMS_DATA_RGBA_8, fDstSpaceQCMS.get(),
69                                             QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL));
70    SkASSERT(transform);
71
72#ifdef SK_PMCOLOR_IS_RGBA
73    qcms_output_type outType = QCMS_OUTPUT_RGBX;
74#else
75    qcms_output_type outType = QCMS_OUTPUT_BGRX;
76#endif
77
78    void* dst = fDst.get();
79    for (int y = 0; y < fSrcInfo.height(); y++) {
80#ifdef SK_DEBUG
81        const int rows =
82#endif
83        codec->getScanlines(fSrc.get(), 1, 0);
84        SkASSERT(1 == rows);
85
86        qcms_transform_data_type(transform, fSrc.get(), dst, fSrcInfo.width(), outType);
87        dst = SkTAddOffset<void>(dst, fDstInfo.minRowBytes());
88    }
89}
90#endif
91
92void ColorCodecBench::xformOnly() {
93    sk_sp<SkColorSpace> srcSpace = SkColorSpace::NewICC(fSrcData->data(), fSrcData->size());
94    if (!srcSpace) {
95        srcSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
96    }
97    std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcSpace.get(),
98                                                                      fDstSpace.get());
99    SkASSERT(xform);
100
101    void* dst = fDst.get();
102    void* src = fSrc.get();
103    for (int y = 0; y < fSrcInfo.height(); y++) {
104        SkAssertResult(xform->apply(select_xform_format(fDstInfo.colorType()), dst,
105                                    SkColorSpaceXform::kRGBA_8888_ColorFormat, src,
106                                    fSrcInfo.width(), fDstInfo.alphaType()));
107        dst = SkTAddOffset<void>(dst, fDstInfo.minRowBytes());
108        src = SkTAddOffset<void>(src, fSrcInfo.minRowBytes());
109    }
110}
111
112#if defined(SK_TEST_QCMS)
113void ColorCodecBench::xformOnlyQCMS() {
114    SkAutoTCallVProc<qcms_profile, qcms_profile_release>
115            srcSpace(qcms_profile_from_memory(fSrcData->data(), fSrcData->size()));
116    SkASSERT(srcSpace);
117
118    SkAutoTCallVProc<qcms_transform, qcms_transform_release>
119            transform (qcms_transform_create(srcSpace, QCMS_DATA_RGBA_8, fDstSpaceQCMS.get(),
120                                             QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL));
121    SkASSERT(transform);
122
123#ifdef SK_PMCOLOR_IS_RGBA
124    qcms_output_type outType = QCMS_OUTPUT_RGBX;
125#else
126    qcms_output_type outType = QCMS_OUTPUT_BGRX;
127#endif
128
129    void* dst = fDst.get();
130    void* src = fSrc.get();
131    for (int y = 0; y < fSrcInfo.height(); y++) {
132        // Transform in place
133        qcms_transform_data_type(transform, src, dst, fSrcInfo.width(), outType);
134        dst = SkTAddOffset<void>(dst, fDstInfo.minRowBytes());
135        src = SkTAddOffset<void>(src, fSrcInfo.minRowBytes());
136    }
137}
138#endif
139
140void ColorCodecBench::onDelayedSetup() {
141    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded));
142    fSrcData = codec->getICCData();
143    sk_sp<SkData> dstData = SkData::MakeFromFileName(
144            GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
145    SkASSERT(dstData);
146
147    fDstSpace = nullptr;
148#if defined(SK_TEST_QCMS)
149    if (FLAGS_qcms) {
150        fDstSpaceQCMS.reset(FLAGS_srgb ?
151                qcms_profile_sRGB() :
152                qcms_profile_from_memory(dstData->data(), dstData->size()));
153        SkASSERT(fDstSpaceQCMS);
154
155        // This call takes a non-trivial amount of time, but I think it's the most fair to
156        // treat it as overhead.  It only needs to happen once.
157        qcms_profile_precache_output_transform(fDstSpaceQCMS);
158    } else
159#endif
160    {
161        fDstSpace = FLAGS_srgb ? SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named) :
162                                 SkColorSpace::NewICC(dstData->data(), dstData->size());
163        SkASSERT(fDstSpace);
164    }
165
166    fSrcInfo = codec->getInfo().makeColorType(kRGBA_8888_SkColorType);
167    fDstInfo = fSrcInfo;
168
169    if (FLAGS_half) {
170        fDstInfo = fDstInfo.makeColorType(kRGBA_F16_SkColorType);
171        fDstSpace = fDstSpace->makeLinearGamma();
172    }
173
174    fDstInfo = fDstInfo.makeColorSpace(fDstSpace);
175
176    fDst.reset(fDstInfo.getSafeSize(fDstInfo.minRowBytes()));
177
178    if (FLAGS_xform_only) {
179        fSrc.reset(fSrcInfo.getSafeSize(fSrcInfo.minRowBytes()));
180        codec->getPixels(fSrcInfo, fSrc.get(), fSrcInfo.minRowBytes());
181    }
182#if defined(SK_TEST_QCMS)
183    else if (FLAGS_qcms) {
184        // Set-up a row buffer to decode into before transforming to dst.
185        fSrc.reset(fSrcInfo.minRowBytes());
186    }
187#endif
188}
189
190void ColorCodecBench::onDraw(int n, SkCanvas*) {
191#if defined(SK_TEST_QCMS)
192    if (FLAGS_qcms && FLAGS_half) {
193        SkDebugf("Error: Contradicting flags.\n");
194        return;
195    }
196#endif
197
198    for (int i = 0; i < n; i++) {
199#if defined(SK_TEST_QCMS)
200        if (FLAGS_qcms) {
201            if (FLAGS_xform_only) {
202                this->xformOnlyQCMS();
203            } else {
204                this->decodeAndXformQCMS();
205            }
206        } else
207#endif
208        {
209            if (FLAGS_xform_only) {
210                this->xformOnly();
211            } else {
212                this->decodeAndXform();
213            }
214        }
215    }
216}
217