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