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