ColorCodecBench.cpp revision 9488833428e83c93a7e6002f4d056084fb57112f
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::NewICC(fSrcData->data(), fSrcData->size()); 96 if (!srcSpace) { 97 srcSpace = SkColorSpace::NewNamed(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::NewNamed(SkColorSpace::kSRGB_Named) : 164 SkColorSpace::NewICC(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::NewRGB(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