ColorCodecBench.cpp revision 43d6651111374b5d1e4ddd9030dcf079b448ec47
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, fDstSpace);
98    SkASSERT(xform);
99
100    void* dst = fDst.get();
101    void* src = fSrc.get();
102    for (int y = 0; y < fSrcInfo.height(); y++) {
103        xform->apply(dst, (uint32_t*) src, fSrcInfo.width(),
104                     select_xform_format(fDstInfo.colorType()), fDstInfo.alphaType());
105        dst = SkTAddOffset<void>(dst, fDstInfo.minRowBytes());
106        src = SkTAddOffset<void>(src, fSrcInfo.minRowBytes());
107    }
108}
109
110#if defined(SK_TEST_QCMS)
111void ColorCodecBench::xformOnlyQCMS() {
112    SkAutoTCallVProc<qcms_profile, qcms_profile_release>
113            srcSpace(qcms_profile_from_memory(fSrcData->data(), fSrcData->size()));
114    SkASSERT(srcSpace);
115
116    SkAutoTCallVProc<qcms_transform, qcms_transform_release>
117            transform (qcms_transform_create(srcSpace, QCMS_DATA_RGBA_8, fDstSpaceQCMS.get(),
118                                             QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL));
119    SkASSERT(transform);
120
121#ifdef SK_PMCOLOR_IS_RGBA
122    qcms_output_type outType = QCMS_OUTPUT_RGBX;
123#else
124    qcms_output_type outType = QCMS_OUTPUT_BGRX;
125#endif
126
127    void* dst = fDst.get();
128    void* src = fSrc.get();
129    for (int y = 0; y < fSrcInfo.height(); y++) {
130        // Transform in place
131        qcms_transform_data_type(transform, src, dst, fSrcInfo.width(), outType);
132        dst = SkTAddOffset<void>(dst, fDstInfo.minRowBytes());
133        src = SkTAddOffset<void>(src, fSrcInfo.minRowBytes());
134    }
135}
136#endif
137
138void ColorCodecBench::onDelayedSetup() {
139    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded));
140    fSrcData = codec->getICCData();
141    sk_sp<SkData> dstData = SkData::MakeFromFileName(
142            GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
143    SkASSERT(dstData);
144
145    fDstSpace = nullptr;
146#if defined(SK_TEST_QCMS)
147    if (FLAGS_qcms) {
148        fDstSpaceQCMS.reset(FLAGS_srgb ?
149                qcms_profile_sRGB() :
150                qcms_profile_from_memory(dstData->data(), dstData->size()));
151        SkASSERT(fDstSpaceQCMS);
152
153        // This call takes a non-trivial amount of time, but I think it's the most fair to
154        // treat it as overhead.  It only needs to happen once.
155        qcms_profile_precache_output_transform(fDstSpaceQCMS);
156    } else
157#endif
158    {
159        fDstSpace = FLAGS_srgb ? SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named) :
160                                 SkColorSpace::NewICC(dstData->data(), dstData->size());
161        SkASSERT(fDstSpace);
162    }
163
164    fSrcInfo = codec->getInfo().makeColorType(kRGBA_8888_SkColorType);
165    fDstInfo = fSrcInfo;
166
167    if (FLAGS_half) {
168        fDstInfo = fDstInfo.makeColorType(kRGBA_F16_SkColorType);
169        fDstSpace = fDstSpace->makeLinearGamma();
170    }
171
172    fDstInfo = fDstInfo.makeColorSpace(fDstSpace);
173
174    fDst.reset(fDstInfo.getSafeSize(fDstInfo.minRowBytes()));
175
176    if (FLAGS_xform_only) {
177        fSrc.reset(fSrcInfo.getSafeSize(fSrcInfo.minRowBytes()));
178        codec->getPixels(fSrcInfo, fSrc.get(), fSrcInfo.minRowBytes());
179    }
180#if defined(SK_TEST_QCMS)
181    else if (FLAGS_qcms) {
182        // Set-up a row buffer to decode into before transforming to dst.
183        fSrc.reset(fSrcInfo.minRowBytes());
184    }
185#endif
186}
187
188void ColorCodecBench::onDraw(int n, SkCanvas*) {
189#if defined(SK_TEST_QCMS)
190    if (FLAGS_qcms && FLAGS_half) {
191        SkDebugf("Error: Contradicting flags.\n");
192        return;
193    }
194#endif
195
196    for (int i = 0; i < n; i++) {
197#if defined(SK_TEST_QCMS)
198        if (FLAGS_qcms) {
199            if (FLAGS_xform_only) {
200                this->xformOnlyQCMS();
201            } else {
202                this->decodeAndXformQCMS();
203            }
204        } else
205#endif
206        {
207            if (FLAGS_xform_only) {
208                this->xformOnly();
209            } else {
210                this->decodeAndXform();
211            }
212        }
213    }
214}
215