msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 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" |
msarett | c044461 | 2016-09-16 11:45:58 -0700 | [diff] [blame] | 11 | #include "SkCodecPriv.h" |
raftias | 9488833 | 2016-10-18 10:02:51 -0700 | [diff] [blame] | 12 | #include "SkColorSpace_XYZ.h" |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 13 | #include "SkColorSpaceXform.h" |
| 14 | #include "SkCommandLineFlags.h" |
| 15 | |
msarett | 469f1c5 | 2016-06-06 08:20:37 -0700 | [diff] [blame] | 16 | #if defined(SK_TEST_QCMS) |
msarett | d280957 | 2016-06-20 06:07:45 -0700 | [diff] [blame] | 17 | DEFINE_bool(qcms, false, "Bench qcms color conversion"); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 18 | #endif |
| 19 | DEFINE_bool(xform_only, false, "Only time the color xform, do not include the decode time"); |
msarett | d280957 | 2016-06-20 06:07:45 -0700 | [diff] [blame] | 20 | DEFINE_bool(srgb, false, "Convert to srgb dst space"); |
Matt Sarett | f489886 | 2016-10-16 10:20:41 -0400 | [diff] [blame] | 21 | DEFINE_bool(nonstd, false, "Convert to non-standard dst space"); |
msarett | 6bdbf44 | 2016-07-19 09:07:55 -0700 | [diff] [blame] | 22 | DEFINE_bool(half, false, "Convert to half floats"); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 23 | |
| 24 | ColorCodecBench::ColorCodecBench(const char* name, sk_sp<SkData> encoded) |
| 25 | : fEncoded(std::move(encoded)) |
msarett | 469f1c5 | 2016-06-06 08:20:37 -0700 | [diff] [blame] | 26 | #if defined(SK_TEST_QCMS) |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 27 | , fDstSpaceQCMS(nullptr) |
| 28 | #endif |
| 29 | { |
| 30 | fName.appendf("Color%s", FLAGS_xform_only ? "Xform" : "Codec"); |
msarett | 469f1c5 | 2016-06-06 08:20:37 -0700 | [diff] [blame] | 31 | #if defined(SK_TEST_QCMS) |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 32 | fName.appendf("%s", FLAGS_qcms ? "QCMS" : ""); |
| 33 | #endif |
| 34 | fName.appendf("_%s", name); |
| 35 | } |
| 36 | |
| 37 | const char* ColorCodecBench::onGetName() { |
| 38 | return fName.c_str(); |
| 39 | } |
| 40 | |
| 41 | bool ColorCodecBench::isSuitableFor(Backend backend) { |
| 42 | return kNonRendering_Backend == backend; |
| 43 | } |
| 44 | |
| 45 | void ColorCodecBench::decodeAndXform() { |
reed | 42943c8 | 2016-09-12 12:01:44 -0700 | [diff] [blame] | 46 | SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded)); |
msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 47 | SkASSERT(codec); |
| 48 | |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 49 | #ifdef SK_DEBUG |
msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 50 | SkCodec::Result result = |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 51 | #endif |
msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 52 | codec->getPixels(fDstInfo, fDst.get(), fDstInfo.minRowBytes()); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 53 | SkASSERT(SkCodec::kSuccess == result); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 54 | } |
| 55 | |
msarett | 469f1c5 | 2016-06-06 08:20:37 -0700 | [diff] [blame] | 56 | #if defined(SK_TEST_QCMS) |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 57 | void ColorCodecBench::decodeAndXformQCMS() { |
reed | 42943c8 | 2016-09-12 12:01:44 -0700 | [diff] [blame] | 58 | SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded)); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 59 | #ifdef SK_DEBUG |
| 60 | const SkCodec::Result result = |
| 61 | #endif |
msarett | 6bdbf44 | 2016-07-19 09:07:55 -0700 | [diff] [blame] | 62 | codec->startScanlineDecode(fSrcInfo); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 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(); |
msarett | 6bdbf44 | 2016-07-19 09:07:55 -0700 | [diff] [blame] | 81 | for (int y = 0; y < fSrcInfo.height(); y++) { |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 82 | #ifdef SK_DEBUG |
| 83 | const int rows = |
| 84 | #endif |
| 85 | codec->getScanlines(fSrc.get(), 1, 0); |
| 86 | SkASSERT(1 == rows); |
| 87 | |
msarett | 6bdbf44 | 2016-07-19 09:07:55 -0700 | [diff] [blame] | 88 | qcms_transform_data_type(transform, fSrc.get(), dst, fSrcInfo.width(), outType); |
| 89 | dst = SkTAddOffset<void>(dst, fDstInfo.minRowBytes()); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 90 | } |
| 91 | } |
| 92 | #endif |
| 93 | |
| 94 | void ColorCodecBench::xformOnly() { |
Brian Osman | 526972e | 2016-10-24 09:24:02 -0400 | [diff] [blame] | 95 | sk_sp<SkColorSpace> srcSpace = SkColorSpace::MakeICC(fSrcData->data(), fSrcData->size()); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 96 | if (!srcSpace) { |
Brian Osman | 526972e | 2016-10-24 09:24:02 -0400 | [diff] [blame] | 97 | srcSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 98 | } |
msarett | 4be0e7c | 2016-09-22 07:02:24 -0700 | [diff] [blame] | 99 | std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcSpace.get(), |
| 100 | fDstSpace.get()); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 101 | SkASSERT(xform); |
| 102 | |
| 103 | void* dst = fDst.get(); |
| 104 | void* src = fSrc.get(); |
msarett | 6bdbf44 | 2016-07-19 09:07:55 -0700 | [diff] [blame] | 105 | for (int y = 0; y < fSrcInfo.height(); y++) { |
msarett | 31d097e8 | 2016-10-11 12:15:03 -0700 | [diff] [blame] | 106 | SkAssertResult(xform->apply(select_xform_format(fDstInfo.colorType()), dst, |
| 107 | SkColorSpaceXform::kRGBA_8888_ColorFormat, src, |
| 108 | fSrcInfo.width(), fDstInfo.alphaType())); |
msarett | 6bdbf44 | 2016-07-19 09:07:55 -0700 | [diff] [blame] | 109 | dst = SkTAddOffset<void>(dst, fDstInfo.minRowBytes()); |
| 110 | src = SkTAddOffset<void>(src, fSrcInfo.minRowBytes()); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 111 | } |
| 112 | } |
| 113 | |
msarett | 469f1c5 | 2016-06-06 08:20:37 -0700 | [diff] [blame] | 114 | #if defined(SK_TEST_QCMS) |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 115 | void 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(); |
msarett | 6bdbf44 | 2016-07-19 09:07:55 -0700 | [diff] [blame] | 133 | for (int y = 0; y < fSrcInfo.height(); y++) { |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 134 | // Transform in place |
msarett | 6bdbf44 | 2016-07-19 09:07:55 -0700 | [diff] [blame] | 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()); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 138 | } |
| 139 | } |
| 140 | #endif |
| 141 | |
| 142 | void ColorCodecBench::onDelayedSetup() { |
reed | 42943c8 | 2016-09-12 12:01:44 -0700 | [diff] [blame] | 143 | SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded)); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 144 | fSrcData = codec->getICCData(); |
| 145 | sk_sp<SkData> dstData = SkData::MakeFromFileName( |
msarett | a714bc3 | 2016-07-29 08:58:33 -0700 | [diff] [blame] | 146 | GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str()); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 147 | SkASSERT(dstData); |
| 148 | |
msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 149 | fDstSpace = nullptr; |
msarett | 469f1c5 | 2016-06-06 08:20:37 -0700 | [diff] [blame] | 150 | #if defined(SK_TEST_QCMS) |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 151 | if (FLAGS_qcms) { |
msarett | d280957 | 2016-06-20 06:07:45 -0700 | [diff] [blame] | 152 | fDstSpaceQCMS.reset(FLAGS_srgb ? |
| 153 | qcms_profile_sRGB() : |
| 154 | qcms_profile_from_memory(dstData->data(), dstData->size())); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 155 | SkASSERT(fDstSpaceQCMS); |
msarett | a9e878c | 2016-06-08 14:43:53 -0700 | [diff] [blame] | 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); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 160 | } else |
| 161 | #endif |
| 162 | { |
Brian Osman | 526972e | 2016-10-24 09:24:02 -0400 | [diff] [blame] | 163 | fDstSpace = FLAGS_srgb ? SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named) : |
| 164 | SkColorSpace::MakeICC(dstData->data(), dstData->size()); |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 165 | SkASSERT(fDstSpace); |
| 166 | } |
msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 167 | |
| 168 | fSrcInfo = codec->getInfo().makeColorType(kRGBA_8888_SkColorType); |
msarett | 8bbcd5a | 2016-09-14 07:06:08 -0700 | [diff] [blame] | 169 | fDstInfo = fSrcInfo; |
msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 170 | |
msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 171 | if (FLAGS_half) { |
| 172 | fDstInfo = fDstInfo.makeColorType(kRGBA_F16_SkColorType); |
raftias | 9488833 | 2016-10-18 10:02:51 -0700 | [diff] [blame] | 173 | SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(fDstSpace)->type()); |
| 174 | fDstSpace = static_cast<SkColorSpace_XYZ*>(fDstSpace.get())->makeLinearGamma(); |
msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 175 | } |
msarett | 2ecc35f | 2016-09-08 11:55:16 -0700 | [diff] [blame] | 176 | |
Matt Sarett | f489886 | 2016-10-16 10:20:41 -0400 | [diff] [blame] | 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); |
Brian Osman | 526972e | 2016-10-24 09:24:02 -0400 | [diff] [blame] | 181 | fDstSpace = SkColorSpace::MakeRGB(gammas, matrix); |
Matt Sarett | f489886 | 2016-10-16 10:20:41 -0400 | [diff] [blame] | 182 | } |
| 183 | |
msarett | 8bbcd5a | 2016-09-14 07:06:08 -0700 | [diff] [blame] | 184 | fDstInfo = fDstInfo.makeColorSpace(fDstSpace); |
msarett | 2ecc35f | 2016-09-08 11:55:16 -0700 | [diff] [blame] | 185 | |
msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 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 |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 198 | } |
| 199 | |
| 200 | void ColorCodecBench::onDraw(int n, SkCanvas*) { |
msarett | 575b2a3 | 2016-07-19 13:00:35 -0700 | [diff] [blame] | 201 | #if defined(SK_TEST_QCMS) |
msarett | 200877e | 2016-08-15 08:10:44 -0700 | [diff] [blame] | 202 | if (FLAGS_qcms && FLAGS_half) { |
msarett | 6bdbf44 | 2016-07-19 09:07:55 -0700 | [diff] [blame] | 203 | SkDebugf("Error: Contradicting flags.\n"); |
| 204 | return; |
| 205 | } |
msarett | 200877e | 2016-08-15 08:10:44 -0700 | [diff] [blame] | 206 | #endif |
msarett | 6bdbf44 | 2016-07-19 09:07:55 -0700 | [diff] [blame] | 207 | |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 208 | for (int i = 0; i < n; i++) { |
msarett | 469f1c5 | 2016-06-06 08:20:37 -0700 | [diff] [blame] | 209 | #if defined(SK_TEST_QCMS) |
msarett | 2cee902 | 2016-06-03 08:25:21 -0700 | [diff] [blame] | 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 | } |