SkColorSpaceXform_A2B.cpp revision 50d0d053576a4895bdd4c837bf990b499da209cb
12563601fc2b0505619f905f86bd249ae630197ccraftias/* 22563601fc2b0505619f905f86bd249ae630197ccraftias * Copyright 2016 Google Inc. 32563601fc2b0505619f905f86bd249ae630197ccraftias * 42563601fc2b0505619f905f86bd249ae630197ccraftias * Use of this source code is governed by a BSD-style license that can be 52563601fc2b0505619f905f86bd249ae630197ccraftias * found in the LICENSE file. 62563601fc2b0505619f905f86bd249ae630197ccraftias */ 72563601fc2b0505619f905f86bd249ae630197ccraftias 82563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpaceXform_A2B.h" 92563601fc2b0505619f905f86bd249ae630197ccraftias 102563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorPriv.h" 112563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpace_A2B.h" 122563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpace_XYZ.h" 132563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpacePriv.h" 142563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpaceXformPriv.h" 152563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkMakeUnique.h" 162563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkNx.h" 172563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkSRGB.h" 182563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkTypes.h" 19c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein#include "../jumper/SkJumper.h" 202563601fc2b0505619f905f86bd249ae630197ccraftias 212563601fc2b0505619f905f86bd249ae630197ccraftiasbool SkColorSpaceXform_A2B::onApply(ColorFormat dstFormat, void* dst, ColorFormat srcFormat, 222563601fc2b0505619f905f86bd249ae630197ccraftias const void* src, int count, SkAlphaType alphaType) const { 23b24704d35f67f5b460be9c92794892e06adceb46Mike Klein SkRasterPipeline_<256> pipeline; 2445c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein 2545c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein SkJumper_MemoryCtx src_ctx = { (void*)src, 0 }, 2645c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein dst_ctx = { (void*)dst, 0 }; 2745c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein 282563601fc2b0505619f905f86bd249ae630197ccraftias switch (srcFormat) { 292563601fc2b0505619f905f86bd249ae630197ccraftias case kBGRA_8888_ColorFormat: 3045c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein pipeline.append(SkRasterPipeline::load_bgra, &src_ctx); 312563601fc2b0505619f905f86bd249ae630197ccraftias break; 322563601fc2b0505619f905f86bd249ae630197ccraftias case kRGBA_8888_ColorFormat: 3345c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein pipeline.append(SkRasterPipeline::load_8888, &src_ctx); 342563601fc2b0505619f905f86bd249ae630197ccraftias break; 35379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett case kRGBA_U16_BE_ColorFormat: 3645c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein pipeline.append(SkRasterPipeline::load_u16_be, &src_ctx); 37379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett break; 385bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett case kRGB_U16_BE_ColorFormat: 3945c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src_ctx); 405bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett break; 412563601fc2b0505619f905f86bd249ae630197ccraftias default: 424c55027dbf57d0701361b123e36b8fad46c341c3Matt Sarett SkCSXformPrintf("F16/F32 sources must be linear.\n"); 432563601fc2b0505619f905f86bd249ae630197ccraftias return false; 442563601fc2b0505619f905f86bd249ae630197ccraftias } 452563601fc2b0505619f905f86bd249ae630197ccraftias 462563601fc2b0505619f905f86bd249ae630197ccraftias pipeline.extend(fElementsPipeline); 472563601fc2b0505619f905f86bd249ae630197ccraftias 482563601fc2b0505619f905f86bd249ae630197ccraftias if (kPremul_SkAlphaType == alphaType) { 492563601fc2b0505619f905f86bd249ae630197ccraftias pipeline.append(SkRasterPipeline::premul); 502563601fc2b0505619f905f86bd249ae630197ccraftias } 512563601fc2b0505619f905f86bd249ae630197ccraftias 522563601fc2b0505619f905f86bd249ae630197ccraftias switch (dstFormat) { 532563601fc2b0505619f905f86bd249ae630197ccraftias case kBGRA_8888_ColorFormat: 5445c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein pipeline.append(SkRasterPipeline::store_bgra, &dst_ctx); 552563601fc2b0505619f905f86bd249ae630197ccraftias break; 562563601fc2b0505619f905f86bd249ae630197ccraftias case kRGBA_8888_ColorFormat: 5745c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein pipeline.append(SkRasterPipeline::store_8888, &dst_ctx); 582563601fc2b0505619f905f86bd249ae630197ccraftias break; 592563601fc2b0505619f905f86bd249ae630197ccraftias case kRGBA_F16_ColorFormat: 602563601fc2b0505619f905f86bd249ae630197ccraftias if (!fLinearDstGamma) { 612563601fc2b0505619f905f86bd249ae630197ccraftias return false; 622563601fc2b0505619f905f86bd249ae630197ccraftias } 6345c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein pipeline.append(SkRasterPipeline::store_f16, &dst_ctx); 642563601fc2b0505619f905f86bd249ae630197ccraftias break; 652563601fc2b0505619f905f86bd249ae630197ccraftias case kRGBA_F32_ColorFormat: 662563601fc2b0505619f905f86bd249ae630197ccraftias if (!fLinearDstGamma) { 672563601fc2b0505619f905f86bd249ae630197ccraftias return false; 682563601fc2b0505619f905f86bd249ae630197ccraftias } 6945c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein pipeline.append(SkRasterPipeline::store_f32, &dst_ctx); 702563601fc2b0505619f905f86bd249ae630197ccraftias break; 713725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett case kBGR_565_ColorFormat: 723725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett if (kOpaque_SkAlphaType != alphaType) { 733725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett return false; 743725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett } 7545c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein pipeline.append(SkRasterPipeline::store_565, &dst_ctx); 763725f0a7dd2916c10bc6d0059821e19a5b4452c3Matt Sarett break; 77379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett default: 78379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett return false; 792563601fc2b0505619f905f86bd249ae630197ccraftias } 8045c16fa82cd2fec010d4cb7763b654a413cabd0cMike Klein pipeline.run(0,0, count,1); 812563601fc2b0505619f905f86bd249ae630197ccraftias 822563601fc2b0505619f905f86bd249ae630197ccraftias return true; 832563601fc2b0505619f905f86bd249ae630197ccraftias} 842563601fc2b0505619f905f86bd249ae630197ccraftias 85113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistrystatic inline bool gamma_to_parametric(SkColorSpaceTransferFn* coeffs, const SkGammas& gammas, 86113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry int channel) { 872563601fc2b0505619f905f86bd249ae630197ccraftias switch (gammas.type(channel)) { 882563601fc2b0505619f905f86bd249ae630197ccraftias case SkGammas::Type::kNamed_Type: 89113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry return named_to_parametric(coeffs, gammas.data(channel).fNamed); 902563601fc2b0505619f905f86bd249ae630197ccraftias case SkGammas::Type::kValue_Type: 91113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry value_to_parametric(coeffs, gammas.data(channel).fValue); 92113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry return true; 932563601fc2b0505619f905f86bd249ae630197ccraftias case SkGammas::Type::kParam_Type: 94113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry *coeffs = gammas.params(channel); 95113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry return true; 962563601fc2b0505619f905f86bd249ae630197ccraftias default: 97113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry return false; 982563601fc2b0505619f905f86bd249ae630197ccraftias } 992563601fc2b0505619f905f86bd249ae630197ccraftias} 1002563601fc2b0505619f905f86bd249ae630197ccraftias 1012563601fc2b0505619f905f86bd249ae630197ccraftiasSkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace, 1022563601fc2b0505619f905f86bd249ae630197ccraftias SkColorSpace_XYZ* dstSpace) 103b24704d35f67f5b460be9c92794892e06adceb46Mike Klein : fElementsPipeline(&fAlloc) 104b24704d35f67f5b460be9c92794892e06adceb46Mike Klein , fLinearDstGamma(kLinear_SkGammaNamed == dstSpace->gammaNamed()) { 1052563601fc2b0505619f905f86bd249ae630197ccraftias#if (SkCSXformPrintfDefined) 1062563601fc2b0505619f905f86bd249ae630197ccraftias static const char* debugGammaNamed[4] = { 1072563601fc2b0505619f905f86bd249ae630197ccraftias "Linear", "SRGB", "2.2", "NonStandard" 1082563601fc2b0505619f905f86bd249ae630197ccraftias }; 1092563601fc2b0505619f905f86bd249ae630197ccraftias static const char* debugGammas[5] = { 1102563601fc2b0505619f905f86bd249ae630197ccraftias "None", "Named", "Value", "Table", "Param" 1112563601fc2b0505619f905f86bd249ae630197ccraftias }; 1122563601fc2b0505619f905f86bd249ae630197ccraftias#endif 113523116d9fee8b79af09563b55b19cbd267353300Matt Sarett int currentChannels; 114523116d9fee8b79af09563b55b19cbd267353300Matt Sarett switch (srcSpace->iccType()) { 115523116d9fee8b79af09563b55b19cbd267353300Matt Sarett case SkColorSpace_Base::kRGB_ICCTypeFlag: 1165476128f0a88217414f05e6a7ee518cdb411d026raftias currentChannels = 3; 1175476128f0a88217414f05e6a7ee518cdb411d026raftias break; 118c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein case SkColorSpace_Base::kCMYK_ICCTypeFlag: { 1195476128f0a88217414f05e6a7ee518cdb411d026raftias currentChannels = 4; 1205476128f0a88217414f05e6a7ee518cdb411d026raftias // CMYK images from JPEGs (the only format that supports it) are actually 1215476128f0a88217414f05e6a7ee518cdb411d026raftias // inverted CMYK, so we need to invert every channel. 12250d0d053576a4895bdd4c837bf990b499da209cbMike Klein fElementsPipeline.append(SkRasterPipeline::invert); 1235476128f0a88217414f05e6a7ee518cdb411d026raftias break; 124c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein } 1255476128f0a88217414f05e6a7ee518cdb411d026raftias default: 126523116d9fee8b79af09563b55b19cbd267353300Matt Sarett currentChannels = 0; 1275476128f0a88217414f05e6a7ee518cdb411d026raftias SkASSERT(false); 1285476128f0a88217414f05e6a7ee518cdb411d026raftias } 1292563601fc2b0505619f905f86bd249ae630197ccraftias // add in all input color space -> PCS xforms 1302563601fc2b0505619f905f86bd249ae630197ccraftias for (int i = 0; i < srcSpace->count(); ++i) { 1312563601fc2b0505619f905f86bd249ae630197ccraftias const SkColorSpace_A2B::Element& e = srcSpace->element(i); 1325476128f0a88217414f05e6a7ee518cdb411d026raftias SkASSERT(e.inputChannels() == currentChannels); 1335476128f0a88217414f05e6a7ee518cdb411d026raftias currentChannels = e.outputChannels(); 1342563601fc2b0505619f905f86bd249ae630197ccraftias switch (e.type()) { 13550d0d053576a4895bdd4c837bf990b499da209cbMike Klein case SkColorSpace_A2B::Element::Type::kGammaNamed: { 136113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry if (kLinear_SkGammaNamed == e.gammaNamed()) { 137113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry break; 138113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry } 139113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry 140c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein // Take the fast path for ordinary sRGB. 141c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein if (3 == currentChannels && kSRGB_SkGammaNamed == e.gammaNamed()) { 142c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein SkCSXformPrintf("fast path from sRGB\n"); 143c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein // Images should always start the pipeline as unpremul 144c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein fElementsPipeline.append_from_srgb(kUnpremul_SkAlphaType); 145c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein break; 146975245407a16dba58ee42cb12f70f8db87f02da0raftias } 147113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry 148113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry SkCSXformPrintf("Gamma stage added: %s\n", debugGammaNamed[(int)e.gammaNamed()]); 14950d0d053576a4895bdd4c837bf990b499da209cbMike Klein auto fn = fAlloc.make<SkColorSpaceTransferFn>(); 15050d0d053576a4895bdd4c837bf990b499da209cbMike Klein SkAssertResult(named_to_parametric(fn, e.gammaNamed())); 15150d0d053576a4895bdd4c837bf990b499da209cbMike Klein 15250d0d053576a4895bdd4c837bf990b499da209cbMike Klein fElementsPipeline.append(SkRasterPipeline::parametric_r, fn); 15350d0d053576a4895bdd4c837bf990b499da209cbMike Klein fElementsPipeline.append(SkRasterPipeline::parametric_g, fn); 15450d0d053576a4895bdd4c837bf990b499da209cbMike Klein fElementsPipeline.append(SkRasterPipeline::parametric_b, fn); 1552563601fc2b0505619f905f86bd249ae630197ccraftias break; 15650d0d053576a4895bdd4c837bf990b499da209cbMike Klein } 1572563601fc2b0505619f905f86bd249ae630197ccraftias case SkColorSpace_A2B::Element::Type::kGammas: { 158db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett const SkGammas& gammas = e.gammas(); 159db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett SkCSXformPrintf("Gamma stage added:"); 1605476128f0a88217414f05e6a7ee518cdb411d026raftias for (int channel = 0; channel < gammas.channels(); ++channel) { 161db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett SkCSXformPrintf(" %s", debugGammas[(int)gammas.type(channel)]); 162db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett } 163db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett SkCSXformPrintf("\n"); 164db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett bool gammaNeedsRef = false; 1655476128f0a88217414f05e6a7ee518cdb411d026raftias for (int channel = 0; channel < gammas.channels(); ++channel) { 166db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett if (SkGammas::Type::kTable_Type == gammas.type(channel)) { 167db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett SkTableTransferFn table = { 168db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett gammas.table(channel), 169db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett gammas.data(channel).fTable.fSize, 170db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett }; 171db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett 1729d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett gammaNeedsRef |= !this->buildTableFn(&table); 1735476128f0a88217414f05e6a7ee518cdb411d026raftias this->addTableFn(table, channel); 174db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett } else { 175113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry SkColorSpaceTransferFn fn; 176113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry SkAssertResult(gamma_to_parametric(&fn, gammas, channel)); 1775476128f0a88217414f05e6a7ee518cdb411d026raftias this->addTransferFn(fn, channel); 1782563601fc2b0505619f905f86bd249ae630197ccraftias } 1792563601fc2b0505619f905f86bd249ae630197ccraftias } 180db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett if (gammaNeedsRef) { 181de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein this->copy(sk_ref_sp(&gammas)); 182db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett } 1832563601fc2b0505619f905f86bd249ae630197ccraftias break; 184db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett } 185de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein case SkColorSpace_A2B::Element::Type::kCLUT: { 1865476128f0a88217414f05e6a7ee518cdb411d026raftias SkCSXformPrintf("CLUT (%d -> %d) stage added\n", e.colorLUT().inputChannels(), 1875476128f0a88217414f05e6a7ee518cdb411d026raftias e.colorLUT().outputChannels()); 188c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein struct CallbackCtx : SkJumper_CallbackCtx { 189c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein sk_sp<const SkColorLookUpTable> clut; 190c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein // clut->interp() can't always safely alias its arguments, 191c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein // so we allocate a second buffer to hold our results. 192c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein float results[4*SkJumper_kMaxStride]; 193c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein }; 194c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein auto cb = fAlloc.make<CallbackCtx>(); 195c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein cb->clut = sk_ref_sp(&e.colorLUT()); 196c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein cb->read_from = cb->results; 197c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein cb->fn = [](SkJumper_CallbackCtx* ctx, int active_pixels) { 198c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein auto c = (CallbackCtx*)ctx; 199c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein for (int i = 0; i < active_pixels; i++) { 200c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein // Look up red, green, and blue for this pixel using 3-4 values from rgba. 201c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein c->clut->interp(c->results+4*i, c->rgba+4*i); 202c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein 203c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein // If we used 3 inputs (rgb) preserve the fourth as alpha. 204c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein // If we used 4 inputs (cmyk) force alpha to 1. 205c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein c->results[4*i+3] = (3 == c->clut->inputChannels()) ? c->rgba[4*i+3] : 1.0f; 206c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein } 207c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein }; 208c17dc24fa9994eacc640d3adc6633a02fd96d3fcMike Klein fElementsPipeline.append(SkRasterPipeline::callback, cb); 2092563601fc2b0505619f905f86bd249ae630197ccraftias break; 210de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein } 2112563601fc2b0505619f905f86bd249ae630197ccraftias case SkColorSpace_A2B::Element::Type::kMatrix: 2122563601fc2b0505619f905f86bd249ae630197ccraftias if (!e.matrix().isIdentity()) { 2132563601fc2b0505619f905f86bd249ae630197ccraftias SkCSXformPrintf("Matrix stage added\n"); 2142563601fc2b0505619f905f86bd249ae630197ccraftias addMatrix(e.matrix()); 2152563601fc2b0505619f905f86bd249ae630197ccraftias } 2162563601fc2b0505619f905f86bd249ae630197ccraftias break; 2172563601fc2b0505619f905f86bd249ae630197ccraftias } 2182563601fc2b0505619f905f86bd249ae630197ccraftias } 2192563601fc2b0505619f905f86bd249ae630197ccraftias 2202563601fc2b0505619f905f86bd249ae630197ccraftias // Lab PCS -> XYZ PCS 2212563601fc2b0505619f905f86bd249ae630197ccraftias if (SkColorSpace_A2B::PCS::kLAB == srcSpace->pcs()) { 2222563601fc2b0505619f905f86bd249ae630197ccraftias SkCSXformPrintf("Lab -> XYZ element added\n"); 2232563601fc2b0505619f905f86bd249ae630197ccraftias fElementsPipeline.append(SkRasterPipeline::lab_to_xyz); 2242563601fc2b0505619f905f86bd249ae630197ccraftias } 2252563601fc2b0505619f905f86bd249ae630197ccraftias 22691db12d89c214235e24599f3ec18df2f952e99ebraftias // we should now be in XYZ PCS 22791db12d89c214235e24599f3ec18df2f952e99ebraftias SkASSERT(3 == currentChannels); 22891db12d89c214235e24599f3ec18df2f952e99ebraftias 2292563601fc2b0505619f905f86bd249ae630197ccraftias // and XYZ PCS -> output color space xforms 2302563601fc2b0505619f905f86bd249ae630197ccraftias if (!dstSpace->fromXYZD50()->isIdentity()) { 2312563601fc2b0505619f905f86bd249ae630197ccraftias addMatrix(*dstSpace->fromXYZD50()); 2322563601fc2b0505619f905f86bd249ae630197ccraftias } 2332563601fc2b0505619f905f86bd249ae630197ccraftias 234975245407a16dba58ee42cb12f70f8db87f02da0raftias switch (dstSpace->gammaNamed()) { 235975245407a16dba58ee42cb12f70f8db87f02da0raftias case kLinear_SkGammaNamed: 236975245407a16dba58ee42cb12f70f8db87f02da0raftias // do nothing 237975245407a16dba58ee42cb12f70f8db87f02da0raftias break; 238c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein case k2Dot2Curve_SkGammaNamed: { 239c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein SkColorSpaceTransferFn fn = {0,0,0,0,0,0,0}; 240c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein fn.fG = 1/2.2f; 241c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein fn.fA = 1; 242c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein auto to_2dot2 = this->copy(fn); 243c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein fElementsPipeline.append(SkRasterPipeline::parametric_r, to_2dot2); 244c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein fElementsPipeline.append(SkRasterPipeline::parametric_g, to_2dot2); 245c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein fElementsPipeline.append(SkRasterPipeline::parametric_b, to_2dot2); 246975245407a16dba58ee42cb12f70f8db87f02da0raftias break; 247c7be00366bb0171e2d247ea71e291a64e3d10254Mike Klein } 248975245407a16dba58ee42cb12f70f8db87f02da0raftias case kSRGB_SkGammaNamed: 249975245407a16dba58ee42cb12f70f8db87f02da0raftias fElementsPipeline.append(SkRasterPipeline::to_srgb); 250975245407a16dba58ee42cb12f70f8db87f02da0raftias break; 251975245407a16dba58ee42cb12f70f8db87f02da0raftias case kNonStandard_SkGammaNamed: { 252975245407a16dba58ee42cb12f70f8db87f02da0raftias for (int channel = 0; channel < 3; ++channel) { 253975245407a16dba58ee42cb12f70f8db87f02da0raftias const SkGammas& gammas = *dstSpace->gammas(); 254975245407a16dba58ee42cb12f70f8db87f02da0raftias if (SkGammas::Type::kTable_Type == gammas.type(channel)) { 255975245407a16dba58ee42cb12f70f8db87f02da0raftias static constexpr int kInvTableSize = 256; 256de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein auto storage = fAlloc.makeArray<float>(kInvTableSize); 257de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein invert_table_gamma(storage, nullptr, kInvTableSize, 258975245407a16dba58ee42cb12f70f8db87f02da0raftias gammas.table(channel), 259975245407a16dba58ee42cb12f70f8db87f02da0raftias gammas.data(channel).fTable.fSize); 260de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein SkTableTransferFn table = { storage, kInvTableSize }; 261975245407a16dba58ee42cb12f70f8db87f02da0raftias this->addTableFn(table, channel); 262975245407a16dba58ee42cb12f70f8db87f02da0raftias } else { 263113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry SkColorSpaceTransferFn fn; 264113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry SkAssertResult(gamma_to_parametric(&fn, gammas, channel)); 26573e627074839bc00569117235eb4e7d4fc3cc39fBrian Osman this->addTransferFn(fn.invert(), channel); 266975245407a16dba58ee42cb12f70f8db87f02da0raftias } 2672563601fc2b0505619f905f86bd249ae630197ccraftias } 2682563601fc2b0505619f905f86bd249ae630197ccraftias } 269975245407a16dba58ee42cb12f70f8db87f02da0raftias break; 270db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett } 271db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett} 272db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett 2735476128f0a88217414f05e6a7ee518cdb411d026raftiasvoid SkColorSpaceXform_A2B::addTransferFn(const SkColorSpaceTransferFn& fn, int channelIndex) { 2745476128f0a88217414f05e6a7ee518cdb411d026raftias switch (channelIndex) { 2755476128f0a88217414f05e6a7ee518cdb411d026raftias case 0: 276de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein fElementsPipeline.append(SkRasterPipeline::parametric_r, this->copy(fn)); 277db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett break; 2785476128f0a88217414f05e6a7ee518cdb411d026raftias case 1: 279de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein fElementsPipeline.append(SkRasterPipeline::parametric_g, this->copy(fn)); 280db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett break; 2815476128f0a88217414f05e6a7ee518cdb411d026raftias case 2: 282de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein fElementsPipeline.append(SkRasterPipeline::parametric_b, this->copy(fn)); 283db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett break; 2845476128f0a88217414f05e6a7ee518cdb411d026raftias case 3: 285de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein fElementsPipeline.append(SkRasterPipeline::parametric_a, this->copy(fn)); 2865476128f0a88217414f05e6a7ee518cdb411d026raftias break; 287db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett default: 288db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett SkASSERT(false); 2892563601fc2b0505619f905f86bd249ae630197ccraftias } 2902563601fc2b0505619f905f86bd249ae630197ccraftias} 2912563601fc2b0505619f905f86bd249ae630197ccraftias 2929d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett/** 2939d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett * |fn| is an in-out parameter. If the table is too small to perform reasonable table-lookups 2949d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett * without interpolation, we will build a bigger table. 2959d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett * 2969d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett * This returns false if we use the original table, meaning we do nothing here but need to keep 2979d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett * a reference to the original table. This returns true if we build a new table and the original 2989d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett * table can be discarded. 2999d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett */ 3009d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarettbool SkColorSpaceXform_A2B::buildTableFn(SkTableTransferFn* fn) { 3019d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett // Arbitrary, but seems like a reasonable guess. 3029d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett static constexpr int kMinTableSize = 256; 3039d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett 3049d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett if (fn->fSize >= kMinTableSize) { 3059d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett return false; 3069d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett } 3079d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett 3089d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett float* outTable = fAlloc.makeArray<float>(kMinTableSize); 3099d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett float step = 1.0f / (kMinTableSize - 1); 3109d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett for (int i = 0; i < kMinTableSize; i++) { 3119d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett outTable[i] = interp_lut(i * step, fn->fData, fn->fSize); 3129d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett } 3139d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett 3149d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett fn->fData = outTable; 3159d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett fn->fSize = kMinTableSize; 3169d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett return true; 3179d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett} 3189d2d7bfc920772b5e8ec31eae8e3ec88704e943fMatt Sarett 3195476128f0a88217414f05e6a7ee518cdb411d026raftiasvoid SkColorSpaceXform_A2B::addTableFn(const SkTableTransferFn& fn, int channelIndex) { 3205476128f0a88217414f05e6a7ee518cdb411d026raftias switch (channelIndex) { 3215476128f0a88217414f05e6a7ee518cdb411d026raftias case 0: 322de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein fElementsPipeline.append(SkRasterPipeline::table_r, this->copy(fn)); 3232563601fc2b0505619f905f86bd249ae630197ccraftias break; 3245476128f0a88217414f05e6a7ee518cdb411d026raftias case 1: 325de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein fElementsPipeline.append(SkRasterPipeline::table_g, this->copy(fn)); 3262563601fc2b0505619f905f86bd249ae630197ccraftias break; 3275476128f0a88217414f05e6a7ee518cdb411d026raftias case 2: 328de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein fElementsPipeline.append(SkRasterPipeline::table_b, this->copy(fn)); 3292563601fc2b0505619f905f86bd249ae630197ccraftias break; 3305476128f0a88217414f05e6a7ee518cdb411d026raftias case 3: 331de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein fElementsPipeline.append(SkRasterPipeline::table_a, this->copy(fn)); 3325476128f0a88217414f05e6a7ee518cdb411d026raftias break; 3332563601fc2b0505619f905f86bd249ae630197ccraftias default: 3342563601fc2b0505619f905f86bd249ae630197ccraftias SkASSERT(false); 3352563601fc2b0505619f905f86bd249ae630197ccraftias } 3362563601fc2b0505619f905f86bd249ae630197ccraftias} 3372563601fc2b0505619f905f86bd249ae630197ccraftias 338de1cad99b353bad080a04ccfde955a8f3c0af295Mike Kleinvoid SkColorSpaceXform_A2B::addMatrix(const SkMatrix44& m44) { 339de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein auto m = fAlloc.makeArray<float>(12); 340de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein m[0] = m44.get(0,0); m[ 1] = m44.get(1,0); m[ 2] = m44.get(2,0); 341de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein m[3] = m44.get(0,1); m[ 4] = m44.get(1,1); m[ 5] = m44.get(2,1); 342de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein m[6] = m44.get(0,2); m[ 7] = m44.get(1,2); m[ 8] = m44.get(2,2); 343de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein m[9] = m44.get(0,3); m[10] = m44.get(1,3); m[11] = m44.get(2,3); 344de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein 345de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein SkASSERT(m44.get(3,0) == 0.0f); 346de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein SkASSERT(m44.get(3,1) == 0.0f); 347de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein SkASSERT(m44.get(3,2) == 0.0f); 348de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein SkASSERT(m44.get(3,3) == 1.0f); 349de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein 350de1cad99b353bad080a04ccfde955a8f3c0af295Mike Klein fElementsPipeline.append(SkRasterPipeline::matrix_3x4, m); 3512563601fc2b0505619f905f86bd249ae630197ccraftias fElementsPipeline.append(SkRasterPipeline::clamp_0); 352db4d406e7e311113e56663b1f2286c18adcee985Matt Sarett fElementsPipeline.append(SkRasterPipeline::clamp_1); 3532563601fc2b0505619f905f86bd249ae630197ccraftias} 354