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