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