19876ac5b3016e5353c072378ac1545a0a2270757msarett/*
29876ac5b3016e5353c072378ac1545a0a2270757msarett * Copyright 2016 Google Inc.
39876ac5b3016e5353c072378ac1545a0a2270757msarett *
49876ac5b3016e5353c072378ac1545a0a2270757msarett * Use of this source code is governed by a BSD-style license that can be
59876ac5b3016e5353c072378ac1545a0a2270757msarett * found in the LICENSE file.
69876ac5b3016e5353c072378ac1545a0a2270757msarett */
79876ac5b3016e5353c072378ac1545a0a2270757msarett
89876ac5b3016e5353c072378ac1545a0a2270757msarett#include "SkColorPriv.h"
99488833428e83c93a7e6002f4d056084fb57112fraftias#include "SkColorSpace_A2B.h"
109876ac5b3016e5353c072378ac1545a0a2270757msarett#include "SkColorSpace_Base.h"
119488833428e83c93a7e6002f4d056084fb57112fraftias#include "SkColorSpace_XYZ.h"
12200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkColorSpacePriv.h"
132563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpaceXform_A2B.h"
1431d097e865f266c8398f45114e4c75c0dfdef058msarett#include "SkColorSpaceXform_Base.h"
152563601fc2b0505619f905f86bd249ae630197ccraftias#include "SkColorSpaceXformPriv.h"
16200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkHalf.h"
17200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett#include "SkOpts.h"
185e15961fa77281540a80ac0d036fefe071c11574Mike Klein#include "SkPM4fPriv.h"
19f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett#include "SkRasterPipeline.h"
20ac41bac40f5a80d2bc5ccec584c23478a6900179mtklein#include "SkSRGB.h"
219876ac5b3016e5353c072378ac1545a0a2270757msarett
226006f678e78af7b6f67a454cd4bc213048983f9dmsarettstatic constexpr float sk_linear_from_2dot2[256] = {
23b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.000056921765712193f,
24b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.000367136269815943f,
25b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.000992374304074325f,
26b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.001963416213396470f,
27b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.003302703032003640f,
28b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.005028203456855540f,
29b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.007155037004573030f,
30b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.007751027397660610f, 0.008373117745148580f, 0.009021491898012130f, 0.009696328701658230f,
31b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.010397802292555300f, 0.011126082368383200f, 0.011881334434813700f, 0.012663720031582100f,
32b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.013473396940142600f, 0.014310519374884100f, 0.015175238159625200f, 0.016067700890886900f,
33b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.016988052089250000f, 0.017936433339950200f, 0.018912983423721500f, 0.019917838438785700f,
34b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.020951131914781100f, 0.022012994919336500f, 0.023103556157921400f, 0.024222942067534200f,
35b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.025371276904734600f, 0.026548682828472900f, 0.027755279978126000f, 0.028991186547107800f,
36b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.030256518852388700f, 0.031551391400226400f, 0.032875916948383800f, 0.034230206565082000f,
37b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.035614369684918800f, 0.037028514161960200f, 0.038472746320194600f, 0.039947171001525600f,
38b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.041451891611462500f, 0.042987010162657100f, 0.044552627316421400f, 0.046148842422351000f,
39b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.047775753556170600f, 0.049433457555908000f, 0.051122050056493400f, 0.052841625522879000f,
40b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.054592277281760300f, 0.056374097551979800f, 0.058187177473685400f, 0.060031607136313200f,
41b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.061907475605455800f, 0.063814870948677200f, 0.065753880260330100f, 0.067724589685424300f,
42b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.069727084442598800f, 0.071761448846239100f, 0.073827766327784600f, 0.075926119456264800f,
43b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.078056589958101900f, 0.080219258736215100f, 0.082414205888459200f, 0.084641510725429500f,
44b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.086901251787660300f, 0.089193506862247800f, 0.091518352998919500f, 0.093875866525577800f,
45b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.096266123063339700f, 0.098689197541094500f, 0.101145164209600000f, 0.103634096655137000f,
46b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.106156067812744000f, 0.108711149979039000f, 0.111299414824660000f, 0.113920933406333000f,
47b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.116575776178572000f, 0.119264013005047000f, 0.121985713169619000f, 0.124740945387051000f,
48b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.127529777813422000f, 0.130352278056244000f, 0.133208513184300000f, 0.136098549737202000f,
49b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.139022453734703000f, 0.141980290685736000f, 0.144972125597231000f, 0.147998022982685000f,
50b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.151058046870511000f, 0.154152260812165000f, 0.157280727890073000f, 0.160443510725344000f,
51b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.163640671485290000f, 0.166872271890766000f, 0.170138373223312000f, 0.173439036332135000f,
52b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.176774321640903000f, 0.180144289154390000f, 0.183548998464951000f, 0.186988508758844000f,
53b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.190462878822409000f, 0.193972167048093000f, 0.197516431440340000f, 0.201095729621346000f,
54b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.204710118836677000f, 0.208359655960767000f, 0.212044397502288000f, 0.215764399609395000f,
55b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.219519718074868000f, 0.223310408341127000f, 0.227136525505149000f, 0.230998124323267000f,
56b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.234895259215880000f, 0.238827984272048000f, 0.242796353254002000f, 0.246800419601550000f,
57b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.250840236436400000f, 0.254915856566385000f, 0.259027332489606000f, 0.263174716398492000f,
58b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.267358060183772000f, 0.271577415438375000f, 0.275832833461245000f, 0.280124365261085000f,
59b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.284452061560024000f, 0.288815972797219000f, 0.293216149132375000f, 0.297652640449211000f,
60b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.302125496358853000f, 0.306634766203158000f, 0.311180499057984000f, 0.315762743736397000f,
61b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.320381548791810000f, 0.325036962521076000f, 0.329729032967515000f, 0.334457807923889000f,
62b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.339223334935327000f, 0.344025661302187000f, 0.348864834082879000f, 0.353740900096629000f,
63b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.358653905926199000f, 0.363603897920553000f, 0.368590922197487000f, 0.373615024646202000f,
64b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.378676250929840000f, 0.383774646487975000f, 0.388910256539059000f, 0.394083126082829000f,
65b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.399293299902674000f, 0.404540822567962000f, 0.409825738436323000f, 0.415148091655907000f,
66b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.420507926167587000f, 0.425905285707146000f, 0.431340213807410000f, 0.436812753800359000f,
67b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.442322948819202000f, 0.447870841800410000f, 0.453456475485731000f, 0.459079892424160000f,
68b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.464741134973889000f, 0.470440245304218000f, 0.476177265397440000f, 0.481952237050698000f,
69b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.487765201877811000f, 0.493616201311074000f, 0.499505276603030000f, 0.505432468828216000f,
70b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.511397818884880000f, 0.517401367496673000f, 0.523443155214325000f, 0.529523222417277000f,
71b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.535641609315311000f, 0.541798355950137000f, 0.547993502196972000f, 0.554227087766085000f,
72b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.560499152204328000f, 0.566809734896638000f, 0.573158875067523000f, 0.579546611782525000f,
73b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.585972983949661000f, 0.592438030320847000f, 0.598941789493296000f, 0.605484299910907000f,
74b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.612065599865624000f, 0.618685727498780000f, 0.625344720802427000f, 0.632042617620641000f,
75b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.638779455650817000f, 0.645555272444935000f, 0.652370105410821000f, 0.659223991813387000f,
76b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.666116968775851000f, 0.673049073280942000f, 0.680020342172095000f, 0.687030812154625000f,
77b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.694080519796882000f, 0.701169501531402000f, 0.708297793656032000f, 0.715465432335048000f,
78b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.722672453600255000f, 0.729918893352071000f, 0.737204787360605000f, 0.744530171266715000f,
79b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.751895080583051000f, 0.759299550695091000f, 0.766743616862161000f, 0.774227314218442000f,
80b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.781750677773962000f, 0.789313742415586000f, 0.796916542907978000f, 0.804559113894567000f,
81b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.812241489898490000f, 0.819963705323528000f, 0.827725794455034000f, 0.835527791460841000f,
82b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.843369730392169000f, 0.851251645184515000f, 0.859173569658532000f, 0.867135537520905000f,
83b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.875137582365205000f, 0.883179737672745000f, 0.891262036813419000f, 0.899384513046529000f,
84b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.907547199521614000f, 0.915750129279253000f, 0.923993335251873000f, 0.932276850264543000f,
85b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.940600707035753000f, 0.948964938178195000f, 0.957369576199527000f, 0.965814653503130000f,
86b39067696ad08a26bbe49b71a71f0546dc42a075msarett        0.974300202388861000f, 0.982826255053791000f, 0.991392843592940000f, 1.000000000000000000f,
87b39067696ad08a26bbe49b71a71f0546dc42a075msarett};
88b39067696ad08a26bbe49b71a71f0546dc42a075msarett
896006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
906006f678e78af7b6f67a454cd4bc213048983f9dmsarett
9115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, float exponent) {
9215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
9315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        *outTable++ = powf(x, exponent);
9415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
9515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
9615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
9715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett// outTable is always 256 entries, inTable may be larger or smaller.
9815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, const float* inTable,
9915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett                                          int inTableSize) {
10015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    if (256 == inTableSize) {
10115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        memcpy(outTable, inTable, sizeof(float) * 256);
10215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        return;
10315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
10415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
10515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
10615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        *outTable++ = interp_lut(x, inTable, inTableSize);
10715ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
10815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
10915ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
110aa34f7ea58330cb73ea17f01715cb6c7d439fae9Matt Sarett
11115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarettstatic void build_table_linear_from_gamma(float* outTable, float g, float a, float b, float c,
11215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett                                          float d, float e, float f) {
1132410717f900c2691db880d84a2e03a6a24905ee2Matt Sarett    // Y = (aX + b)^g + e  for X >= d
1142410717f900c2691db880d84a2e03a6a24905ee2Matt Sarett    // Y = cX + f          otherwise
11515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
11615ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        if (x >= d) {
1172410717f900c2691db880d84a2e03a6a24905ee2Matt Sarett            *outTable++ = clamp_0_1(powf(a * x + b, g) + e);
11815ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        } else {
1192410717f900c2691db880d84a2e03a6a24905ee2Matt Sarett            *outTable++ = clamp_0_1(c * x + f);
12015ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett        }
12115ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett    }
12215ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett}
12315ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
12415ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett///////////////////////////////////////////////////////////////////////////////////////////////////
12515ee3deee8aca2bf6e658449f25ee34a8153e6eemsarett
126f489886915034093278353d06c6f1973b2e8b7d2Matt Sarettstatic const int kDstGammaTableSize = SkColorSpaceXform_Base::kDstGammaTableSize;
1273418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett
1281b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, float exponent) {
129b39067696ad08a26bbe49b71a71f0546dc42a075msarett    float toGammaExp = 1.0f / exponent;
130b39067696ad08a26bbe49b71a71f0546dc42a075msarett
1313418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    for (int i = 0; i < kDstGammaTableSize; i++) {
1323418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
133b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp));
134b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
135dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett}
136dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
1371b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable,
138b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                        int inTableSize) {
139197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias    invert_table_gamma(nullptr, outTable, kDstGammaTableSize, inTable, inTableSize);
140b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
141dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
142b39067696ad08a26bbe49b71a71f0546dc42a075msarettstatic float inverse_parametric(float x, float g, float a, float b, float c, float d, float e,
143b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                float f) {
144b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // We need to take the inverse of the following piecewise function.
145b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Y = (aX + b)^g + c  for X >= d
146b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Y = eX + f          otherwise
147b39067696ad08a26bbe49b71a71f0546dc42a075msarett
148b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Assume that the gamma function is continuous, or this won't make much sense anyway.
149b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Plug in |d| to the first equation to calculate the new piecewise interval.
150b39067696ad08a26bbe49b71a71f0546dc42a075msarett    // Then simply use the inverse of the original functions.
1512410717f900c2691db880d84a2e03a6a24905ee2Matt Sarett    float interval = c * d + f;
152b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (x < interval) {
1532410717f900c2691db880d84a2e03a6a24905ee2Matt Sarett        // X = (Y - F) / C
1542410717f900c2691db880d84a2e03a6a24905ee2Matt Sarett        if (0.0f == c) {
155b39067696ad08a26bbe49b71a71f0546dc42a075msarett            // The gamma curve for this segment is constant, so the inverse is undefined.
156b39067696ad08a26bbe49b71a71f0546dc42a075msarett            // Since this is the lower segment, guess zero.
157b39067696ad08a26bbe49b71a71f0546dc42a075msarett            return 0.0f;
158b39067696ad08a26bbe49b71a71f0546dc42a075msarett        }
159b39067696ad08a26bbe49b71a71f0546dc42a075msarett
1602410717f900c2691db880d84a2e03a6a24905ee2Matt Sarett        return (x - f) / c;
161b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
162b39067696ad08a26bbe49b71a71f0546dc42a075msarett
1632410717f900c2691db880d84a2e03a6a24905ee2Matt Sarett    // X = ((Y - E)^(1 / G) - B) / A
164b39067696ad08a26bbe49b71a71f0546dc42a075msarett    if (0.0f == a || 0.0f == g) {
165b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // The gamma curve for this segment is constant, so the inverse is undefined.
166b39067696ad08a26bbe49b71a71f0546dc42a075msarett        // Since this is the upper segment, guess one.
167b39067696ad08a26bbe49b71a71f0546dc42a075msarett        return 1.0f;
168b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
169b39067696ad08a26bbe49b71a71f0546dc42a075msarett
1702410717f900c2691db880d84a2e03a6a24905ee2Matt Sarett    return (powf(x - e, 1.0f / g) - b) / a;
171b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
172b39067696ad08a26bbe49b71a71f0546dc42a075msarett
1731b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_table_linear_to_gamma(uint8_t* outTable, float g, float a,
174b39067696ad08a26bbe49b71a71f0546dc42a075msarett                                        float b, float c, float d, float e, float f) {
1753418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett    for (int i = 0; i < kDstGammaTableSize; i++) {
1763418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
177b39067696ad08a26bbe49b71a71f0546dc42a075msarett        float y = inverse_parametric(x, g, a, b, c, d, e, f);
178b39067696ad08a26bbe49b71a71f0546dc42a075msarett        outTable[i] = clamp_normalized_float_to_byte(y);
179b39067696ad08a26bbe49b71a71f0546dc42a075msarett    }
180b39067696ad08a26bbe49b71a71f0546dc42a075msarett}
181b39067696ad08a26bbe49b71a71f0546dc42a075msarett
1826006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
1836006f678e78af7b6f67a454cd4bc213048983f9dmsarett
1841b93bd1e6eba3d14593490e4e24a34546638c8damsaretttemplate <typename T>
1851b93bd1e6eba3d14593490e4e24a34546638c8damsarettstruct GammaFns {
1861b93bd1e6eba3d14593490e4e24a34546638c8damsarett    const T* fSRGBTable;
1871b93bd1e6eba3d14593490e4e24a34546638c8damsarett    const T* f2Dot2Table;
1881b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromValue)(T*, float);
1891b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromTable)(T*, const float*, int);
1901b93bd1e6eba3d14593490e4e24a34546638c8damsarett    void (*fBuildFromParam)(T*, float, float, float, float, float, float, float);
1911b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
1921b93bd1e6eba3d14593490e4e24a34546638c8damsarett
1931b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic const GammaFns<float> kToLinear {
1941b93bd1e6eba3d14593490e4e24a34546638c8damsarett    sk_linear_from_srgb,
1951b93bd1e6eba3d14593490e4e24a34546638c8damsarett    sk_linear_from_2dot2,
1961b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
1971b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
1981b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_from_gamma,
1991b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
2001b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2011b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic const GammaFns<uint8_t> kFromLinear {
20255bcc8e0af3415601b3d62252a0d579fbe87c85amsarett    nullptr,
20355bcc8e0af3415601b3d62252a0d579fbe87c85amsarett    nullptr,
2041b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
2051b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
2061b93bd1e6eba3d14593490e4e24a34546638c8damsarett    &build_table_linear_to_gamma,
2071b93bd1e6eba3d14593490e4e24a34546638c8damsarett};
2081b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2091b93bd1e6eba3d14593490e4e24a34546638c8damsarett// Build tables to transform src gamma to linear.
2101b93bd1e6eba3d14593490e4e24a34546638c8damsaretttemplate <typename T>
2111b93bd1e6eba3d14593490e4e24a34546638c8damsarettstatic void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, int gammaTableSize,
2129488833428e83c93a7e6002f4d056084fb57112fraftias                               const SkColorSpace_XYZ* space, const GammaFns<T>& fns,
213f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                               bool gammasAreMatching)
2144be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett{
2159488833428e83c93a7e6002f4d056084fb57112fraftias    switch (space->gammaNamed()) {
216600c737b64eae2c7379442ae2c852853cce3a278msarett        case kSRGB_SkGammaNamed:
2171b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRGBTable;
2181b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
219600c737b64eae2c7379442ae2c852853cce3a278msarett        case k2Dot2Curve_SkGammaNamed:
2201b93bd1e6eba3d14593490e4e24a34546638c8damsarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Dot2Table;
2211b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
222600c737b64eae2c7379442ae2c852853cce3a278msarett        case kLinear_SkGammaNamed:
2238bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = nullptr;
2241b93bd1e6eba3d14593490e4e24a34546638c8damsarett            break;
2251b93bd1e6eba3d14593490e4e24a34546638c8damsarett        default: {
2269488833428e83c93a7e6002f4d056084fb57112fraftias            const SkGammas* gammas = space->gammas();
2271b93bd1e6eba3d14593490e4e24a34546638c8damsarett            SkASSERT(gammas);
2281b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2297bbda991af353fbe6b34132132d211d23a3dba8cmsarett            auto build_table = [=](int i) {
2301b93bd1e6eba3d14593490e4e24a34546638c8damsarett                if (gammas->isNamed(i)) {
2311b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    switch (gammas->data(i).fNamed) {
232600c737b64eae2c7379442ae2c852853cce3a278msarett                        case kSRGB_SkGammaNamed:
23355bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], 2.4f,
2342410717f900c2691db880d84a2e03a6a24905ee2Matt Sarett                                                   (1.0f / 1.055f), (0.055f / 1.055f),
2352410717f900c2691db880d84a2e03a6a24905ee2Matt Sarett                                                   (1.0f / 12.92f), 0.04045f, 0.0f, 0.0f);
23655bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2371b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
238600c737b64eae2c7379442ae2c852853cce3a278msarett                        case k2Dot2Curve_SkGammaNamed:
23955bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 2.2f);
24055bcc8e0af3415601b3d62252a0d579fbe87c85amsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2411b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
242600c737b64eae2c7379442ae2c852853cce3a278msarett                        case kLinear_SkGammaNamed:
2431b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 1.0f);
2441b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2451b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
2461b93bd1e6eba3d14593490e4e24a34546638c8damsarett                        default:
2471b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            SkASSERT(false);
2481b93bd1e6eba3d14593490e4e24a34546638c8damsarett                            break;
2491b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    }
2501b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else if (gammas->isValue(i)) {
2511b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize],
2521b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           gammas->data(i).fValue);
2531b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2541b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else if (gammas->isTable(i)) {
2551b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromTable)(&gammaTableStorage[i * gammaTableSize], gammas->table(i),
2561b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           gammas->data(i).fTable.fSize);
2571b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2581b93bd1e6eba3d14593490e4e24a34546638c8damsarett                } else {
2591b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    SkASSERT(gammas->isParametric(i));
260df44fc5f2bb282557df291e20dbd26c070533aa6Matt Sarett                    const SkColorSpaceTransferFn& params = gammas->params(i);
2611b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG,
2621b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           params.fA, params.fB, params.fC, params.fD, params.fE,
2631b93bd1e6eba3d14593490e4e24a34546638c8damsarett                                           params.fF);
2641b93bd1e6eba3d14593490e4e24a34546638c8damsarett                    outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
2651b93bd1e6eba3d14593490e4e24a34546638c8damsarett                }
2667bbda991af353fbe6b34132132d211d23a3dba8cmsarett            };
2677bbda991af353fbe6b34132132d211d23a3dba8cmsarett
2687bbda991af353fbe6b34132132d211d23a3dba8cmsarett            if (gammasAreMatching) {
2697bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(0);
2707bbda991af353fbe6b34132132d211d23a3dba8cmsarett                outGammaTables[1] = outGammaTables[0];
2717bbda991af353fbe6b34132132d211d23a3dba8cmsarett                outGammaTables[2] = outGammaTables[0];
2727bbda991af353fbe6b34132132d211d23a3dba8cmsarett            } else {
2737bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(0);
2747bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(1);
2757bbda991af353fbe6b34132132d211d23a3dba8cmsarett                build_table(2);
2761b93bd1e6eba3d14593490e4e24a34546638c8damsarett            }
2777bbda991af353fbe6b34132132d211d23a3dba8cmsarett
2787bbda991af353fbe6b34132132d211d23a3dba8cmsarett            break;
2791b93bd1e6eba3d14593490e4e24a34546638c8damsarett        }
2801b93bd1e6eba3d14593490e4e24a34546638c8damsarett    }
2811b93bd1e6eba3d14593490e4e24a34546638c8damsarett}
2821b93bd1e6eba3d14593490e4e24a34546638c8damsarett
283f489886915034093278353d06c6f1973b2e8b7d2Matt Sarettvoid SkColorSpaceXform_Base::BuildDstGammaTables(const uint8_t* dstGammaTables[3],
2849488833428e83c93a7e6002f4d056084fb57112fraftias                                                 uint8_t* dstStorage,
2859488833428e83c93a7e6002f4d056084fb57112fraftias                                                 const SkColorSpace_XYZ* space,
286f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                                                 bool gammasAreMatching) {
287f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    build_gamma_tables(dstGammaTables, dstStorage, kDstGammaTableSize, space, kFromLinear,
288f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                       gammasAreMatching);
289f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett}
290f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett
2911b93bd1e6eba3d14593490e4e24a34546638c8damsarett///////////////////////////////////////////////////////////////////////////////////////////////////
2921b93bd1e6eba3d14593490e4e24a34546638c8damsarett
2934be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarettstd::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace,
2944be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett                                                          SkColorSpace* dstSpace) {
295cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett    return SkColorSpaceXform_Base::New(srcSpace, dstSpace, SkTransferFunctionBehavior::kRespect);
296cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett}
297cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett
298cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarettstd::unique_ptr<SkColorSpaceXform> SkColorSpaceXform_Base::New(SkColorSpace* srcSpace,
299cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett        SkColorSpace* dstSpace, SkTransferFunctionBehavior premulBehavior) {
300cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett
3016006f678e78af7b6f67a454cd4bc213048983f9dmsarett    if (!srcSpace || !dstSpace) {
3026006f678e78af7b6f67a454cd4bc213048983f9dmsarett        // Invalid input
3036006f678e78af7b6f67a454cd4bc213048983f9dmsarett        return nullptr;
3046006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
3056006f678e78af7b6f67a454cd4bc213048983f9dmsarett
3069488833428e83c93a7e6002f4d056084fb57112fraftias    if (SkColorSpace_Base::Type::kA2B == as_CSB(dstSpace)->type()) {
3072563601fc2b0505619f905f86bd249ae630197ccraftias        SkCSXformPrintf("A2B destinations not supported\n");
3089488833428e83c93a7e6002f4d056084fb57112fraftias        return nullptr;
3099488833428e83c93a7e6002f4d056084fb57112fraftias    }
3109488833428e83c93a7e6002f4d056084fb57112fraftias
3119488833428e83c93a7e6002f4d056084fb57112fraftias    if (SkColorSpace_Base::Type::kA2B == as_CSB(srcSpace)->type()) {
3122563601fc2b0505619f905f86bd249ae630197ccraftias        SkColorSpace_A2B* src = static_cast<SkColorSpace_A2B*>(srcSpace);
3132563601fc2b0505619f905f86bd249ae630197ccraftias        SkColorSpace_XYZ* dst = static_cast<SkColorSpace_XYZ*>(dstSpace);
3142563601fc2b0505619f905f86bd249ae630197ccraftias        return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_A2B(src, dst));
3159488833428e83c93a7e6002f4d056084fb57112fraftias    }
3169488833428e83c93a7e6002f4d056084fb57112fraftias    SkColorSpace_XYZ* srcSpaceXYZ = static_cast<SkColorSpace_XYZ*>(srcSpace);
3179488833428e83c93a7e6002f4d056084fb57112fraftias    SkColorSpace_XYZ* dstSpaceXYZ = static_cast<SkColorSpace_XYZ*>(dstSpace);
3189488833428e83c93a7e6002f4d056084fb57112fraftias
319200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    ColorSpaceMatch csm = kNone_ColorSpaceMatch;
3206006f678e78af7b6f67a454cd4bc213048983f9dmsarett    SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor);
321f3880933092c3226cd7ffd1690fe72c9c0cc376cMatt Sarett    if (SkColorSpace::Equals(srcSpace, dstSpace)) {
322200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        srcToDst.setIdentity();
323200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        csm = kFull_ColorSpaceMatch;
324971cd496b9e25f87f3a75a0015c203322907136abrianosman    } else {
325bbf251bf225489a0939fff6df938035a290f4d16Brian Osman        if (srcSpaceXYZ->toXYZD50Hash() == dstSpaceXYZ->toXYZD50Hash()) {
326bbf251bf225489a0939fff6df938035a290f4d16Brian Osman            SkASSERT(*srcSpaceXYZ->toXYZD50() == *dstSpaceXYZ->toXYZD50() && "Hash collision");
327971cd496b9e25f87f3a75a0015c203322907136abrianosman            srcToDst.setIdentity();
328971cd496b9e25f87f3a75a0015c203322907136abrianosman            csm = kGamut_ColorSpaceMatch;
329bbf251bf225489a0939fff6df938035a290f4d16Brian Osman        } else {
330bbf251bf225489a0939fff6df938035a290f4d16Brian Osman            srcToDst.setConcat(*dstSpaceXYZ->fromXYZD50(), *srcSpaceXYZ->toXYZD50());
331971cd496b9e25f87f3a75a0015c203322907136abrianosman        }
3326006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
3336006f678e78af7b6f67a454cd4bc213048983f9dmsarett
334200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    switch (csm) {
335200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kNone_ColorSpaceMatch:
336379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
337cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett                    <kNone_ColorSpaceMatch>(srcSpaceXYZ, srcToDst, dstSpaceXYZ, premulBehavior));
338200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kGamut_ColorSpaceMatch:
339379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
340cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett                    <kGamut_ColorSpaceMatch>(srcSpaceXYZ, srcToDst, dstSpaceXYZ, premulBehavior));
341200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        case kFull_ColorSpaceMatch:
342379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
343cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett                    <kFull_ColorSpaceMatch>(srcSpaceXYZ, srcToDst, dstSpaceXYZ, premulBehavior));
3443418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett        default:
345200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            SkASSERT(false);
346200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett            return nullptr;
3476006f678e78af7b6f67a454cd4bc213048983f9dmsarett    }
3486006f678e78af7b6f67a454cd4bc213048983f9dmsarett}
3496006f678e78af7b6f67a454cd4bc213048983f9dmsarett
3506006f678e78af7b6f67a454cd4bc213048983f9dmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
3516006f678e78af7b6f67a454cd4bc213048983f9dmsarett
352df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett#define AI SK_ALWAYS_INLINE
353df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett
35426a0543579cf7473de2099ce0d056ac8aba83811Matt Sarettstatic AI void load_matrix(const float matrix[13],
355df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                           Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& rTgTbT) {
35626a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    rXgXbX = Sk4f::Load(matrix + 0);
35726a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    rYgYbY = Sk4f::Load(matrix + 3);
35826a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    rZgZbZ = Sk4f::Load(matrix + 6);
35926a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    rTgTbT = Sk4f::Load(matrix + 9);
360200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
361200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
362cf7b877d62537672b67449bc96858cc1262be5f8msarettenum Order {
363cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_Order,
364cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_Order,
365cf7b877d62537672b67449bc96858cc1262be5f8msarett};
366cf7b877d62537672b67449bc96858cc1262be5f8msarett
367df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void set_rb_shifts(Order kOrder, int* kRShift, int* kBShift) {
368cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kRGBA_Order == kOrder) {
369cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kRShift = 0;
370cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kBShift = 16;
371cf7b877d62537672b67449bc96858cc1262be5f8msarett    } else {
372cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kRShift = 16;
373cf7b877d62537672b67449bc96858cc1262be5f8msarett        *kBShift = 0;
374cf7b877d62537672b67449bc96858cc1262be5f8msarett    }
375cf7b877d62537672b67449bc96858cc1262be5f8msarett}
376cf7b877d62537672b67449bc96858cc1262be5f8msarett
377cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
378df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_rgb_from_tables(const uint32_t* src,
379df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                    Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
380df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                    const float* const srcTables[3]) {
381cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
382cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
383cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = { srcTables[0][(src[0] >> kRShift) & 0xFF],
384cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[1] >> kRShift) & 0xFF],
385cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[2] >> kRShift) & 0xFF],
386cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[3] >> kRShift) & 0xFF], };
387cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = { srcTables[1][(src[0] >> kGShift) & 0xFF],
388cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[1] >> kGShift) & 0xFF],
389cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[2] >> kGShift) & 0xFF],
390cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[3] >> kGShift) & 0xFF], };
391cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = { srcTables[2][(src[0] >> kBShift) & 0xFF],
392cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[1] >> kBShift) & 0xFF],
393cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[2] >> kBShift) & 0xFF],
394cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[3] >> kBShift) & 0xFF], };
395200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
396200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
397200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
398cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
399df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_rgba_from_tables(const uint32_t* src,
400df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                     Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
401df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                     const float* const srcTables[3]) {
402cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
403cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
404cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = { srcTables[0][(src[0] >> kRShift) & 0xFF],
405cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[1] >> kRShift) & 0xFF],
406cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[2] >> kRShift) & 0xFF],
407cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[0][(src[3] >> kRShift) & 0xFF], };
4085414be06935ce0f990a2df5dccaf9ddec78ec553msarett    g = { srcTables[1][(src[0] >> kGShift) & 0xFF],
409cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[1] >> kGShift) & 0xFF],
410cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[2] >> kGShift) & 0xFF],
411cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[1][(src[3] >> kGShift) & 0xFF], };
412cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = { srcTables[2][(src[0] >> kBShift) & 0xFF],
413cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[1] >> kBShift) & 0xFF],
414cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[2] >> kBShift) & 0xFF],
415cf7b877d62537672b67449bc96858cc1262be5f8msarett          srcTables[2][(src[3] >> kBShift) & 0xFF], };
416200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = (1.0f / 255.0f) * SkNx_cast<float>(Sk4u::Load(src) >> 24);
417200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
418200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
419cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
4202563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void load_rgb_linear(const uint32_t* src, Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
421df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               const float* const[3]) {
422cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
423cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
424cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kRShift) & 0xFF);
425cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kGShift) & 0xFF);
426cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kBShift) & 0xFF);
427be362774f9b9e8964544a579281603ed995e6e5amsarett    a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
4288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
4298bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
430cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
4312563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void load_rgba_linear(const uint32_t* src, Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
432df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                const float* const[3]) {
433cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
434cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
435cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kRShift) & 0xFF);
436cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kGShift) & 0xFF);
437cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kBShift) & 0xFF);
438cf7b877d62537672b67449bc96858cc1262be5f8msarett    a = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> 24));
4398bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
4408bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
441cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
442df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_rgb_from_tables_1(const uint32_t* src,
443df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                      Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
444df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                      const float* const srcTables[3]) {
445cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
446cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
447cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]);
448cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]);
449cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]);
450a9f64dec63b6f4169ba16f8b6c63fff5a6494029Matt Sarett    a = 0.0f; // Don't let MSAN complain that |a| is uninitialized.
451200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
452200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
453cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
454df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_rgba_from_tables_1(const uint32_t* src,
455df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                       Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
456df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                       const float* const srcTables[3]) {
457cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
458cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
459cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]);
460cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]);
461cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]);
462200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    a = (1.0f / 255.0f) * Sk4f(*src >> 24);
463200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
464200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
465cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
466df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_rgb_linear_1(const uint32_t* src,
467df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
468df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                 const float* const srcTables[3]) {
469cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
470cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
471cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF));
472cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF));
473cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF));
474a9f64dec63b6f4169ba16f8b6c63fff5a6494029Matt Sarett    a = 0.0f; // Don't let MSAN complain that |a| is uninitialized.
4758bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
4768bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
477cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
478df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void load_rgba_linear_1(const uint32_t* src,
479df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                  Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
480df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                  const float* const srcTables[3]) {
481cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
482cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
483cf7b877d62537672b67449bc96858cc1262be5f8msarett    r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF));
484cf7b877d62537672b67449bc96858cc1262be5f8msarett    g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF));
485cf7b877d62537672b67449bc96858cc1262be5f8msarett    b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF));
486cf7b877d62537672b67449bc96858cc1262be5f8msarett    a = Sk4f((1.0f / 255.0f) * ((*src >> 24)));
4878bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
4888bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
489df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void transform_gamut(const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a,
490df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
491df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) {
492200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = rXgXbX[0]*r + rYgYbY[0]*g + rZgZbZ[0]*b;
493200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = rXgXbX[1]*r + rYgYbY[1]*g + rZgZbZ[1]*b;
494200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = rXgXbX[2]*r + rYgYbY[2]*g + rZgZbZ[2]*b;
495200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    da = a;
496200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
497200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
498df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void transform_gamut_1(const Sk4f& r, const Sk4f& g, const Sk4f& b,
499df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                 const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
500df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                 Sk4f& rgba) {
501200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = rXgXbX*r + rYgYbY*g + rZgZbZ*b;
502200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
503200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
504df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void translate_gamut(const Sk4f& rTgTbT, Sk4f& dr, Sk4f& dg, Sk4f& db) {
505200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = dr + rTgTbT[0];
506200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = dg + rTgTbT[1];
507200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = db + rTgTbT[2];
508200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
509200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
510df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void translate_gamut_1(const Sk4f& rTgTbT, Sk4f& rgba) {
511200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = rgba + rTgTbT;
512200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
513200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
514cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
5152563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_srgb(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
516df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                          const uint8_t* const[3]) {
517cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
518cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
519200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = sk_linear_to_srgb_needs_trunc(dr);
520200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = sk_linear_to_srgb_needs_trunc(dg);
521200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = sk_linear_to_srgb_needs_trunc(db);
522200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
52317e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    dr = sk_clamp_0_255(dr);
52417e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    dg = sk_clamp_0_255(dg);
52517e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    db = sk_clamp_0_255(db);
52617e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett
527200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
528200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
529200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i rgba = (SkNx_cast<int>(dr) << kRShift)
530200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (SkNx_cast<int>(dg) << kGShift)
531200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (SkNx_cast<int>(db) << kBShift)
532200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (da                           );
533200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba.store(dst);
534200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
535200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
536cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
537df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_srgb_1(void* dst, const uint32_t* src,
538df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                            Sk4f& rgba, const Sk4f&,
539df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                            const uint8_t* const[3]) {
54017e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    rgba = sk_clamp_0_255(sk_linear_to_srgb_needs_trunc(rgba));
541200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
542200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t tmp;
543200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkNx_cast<uint8_t>(SkNx_cast<int32_t>(rgba)).store(&tmp);
544200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
545cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kBGRA_Order == kOrder) {
546200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        tmp = SkSwizzle_RB(tmp);
547200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
548200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
549200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *(uint32_t*)dst = tmp;
550200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
551200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
552df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI Sk4f linear_to_2dot2(const Sk4f& x) {
553200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // x^(29/64) is a very good approximation of the true value, x^(1/2.2).
554200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    auto x2  = x.rsqrt(),                            // x^(-1/2)
555200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett         x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(),   // x^(-1/32)
556200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett         x64 = x32.rsqrt();                          // x^(+1/64)
557200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
558200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    // 29 = 32 - 2 - 1
559200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    return 255.0f * x2.invert() * x32 * x64.invert();
560200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
561200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
562cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
5632563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_2dot2(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
564df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                           const uint8_t* const[3]) {
565cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
566cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
567200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dr = linear_to_2dot2(dr);
568200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dg = linear_to_2dot2(dg);
569200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    db = linear_to_2dot2(db);
570200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
57117e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    dr = sk_clamp_0_255(dr);
57217e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    dg = sk_clamp_0_255(dg);
57317e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    db = sk_clamp_0_255(db);
57417e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett
575200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
576200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
577200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i rgba = (Sk4f_round(dr) << kRShift)
578200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (Sk4f_round(dg) << kGShift)
579200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (Sk4f_round(db) << kBShift)
580200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett              | (da                       );
581200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba.store(dst);
582200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
583200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
584cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
585df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_2dot2_1(void* dst, const uint32_t* src,
586df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                             Sk4f& rgba, const Sk4f&,
587df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                             const uint8_t* const[3]) {
58817e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    rgba = sk_clamp_0_255(linear_to_2dot2(rgba));
589200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
590200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t tmp;
591200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
592200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
593cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kBGRA_Order == kOrder) {
594200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        tmp = SkSwizzle_RB(tmp);
595200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
596200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
597200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *(uint32_t*)dst = tmp;
598200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
599200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
600cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
6012563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_linear(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
602df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                            const uint8_t* const[3]) {
603cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
604cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
60517e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    dr = sk_clamp_0_255(255.0f * dr);
60617e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    dg = sk_clamp_0_255(255.0f * dg);
60717e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    db = sk_clamp_0_255(255.0f * db);
6088bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
6098bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
6108bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
6118bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Sk4i rgba = (Sk4f_round(dr) << kRShift)
6128bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (Sk4f_round(dg) << kGShift)
6138bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (Sk4f_round(db) << kBShift)
6148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett              | (da                       );
6158bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    rgba.store(dst);
6168bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
6178bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
618cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
619df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_linear_1(void* dst, const uint32_t* src,
620df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                              Sk4f& rgba, const Sk4f&,
621df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                              const uint8_t* const[3]) {
62217e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    rgba = sk_clamp_0_255(255.0f * rgba);
6238bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
6248bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    uint32_t tmp;
6258bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
6268bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
627cf7b877d62537672b67449bc96858cc1262be5f8msarett    if (kBGRA_Order == kOrder) {
6288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        tmp = SkSwizzle_RB(tmp);
6298bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
6308bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
6318bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    *(uint32_t*)dst = tmp;
6328bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
6338bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
634cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
6352563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_f16(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
6362563601fc2b0505619f905f86bd249ae630197ccraftias                         const uint8_t* const[3]) {
63733cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein    Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr),
63833cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(dg),
63933cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(db),
64033cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(da));
641200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
642200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
643cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
644df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_f16_1(void* dst, const uint32_t* src,
645df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                           Sk4f& rgba, const Sk4f& a,
646df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                           const uint8_t* const[3]) {
647200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]);
6488ae991e433d2c0814ea5579613f00173805ff057mtklein    SkFloatToHalf_finite_ftz(rgba).store((uint64_t*) dst);
649200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
650200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
651cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
6522563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_f16_opaque(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db,
6532563601fc2b0505619f905f86bd249ae630197ccraftias                                Sk4f&, const uint8_t* const[3]) {
65433cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein    Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr),
65533cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(dg),
65633cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SkFloatToHalf_finite_ftz(db),
65733cbfd75afdd383770bb6253c06ba819a2481a35Mike Klein                      SK_Half1);
658200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
659200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
660cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
661df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_f16_1_opaque(void* dst, const uint32_t* src,
662df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                  Sk4f& rgba, const Sk4f&,
663df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                                  const uint8_t* const[3]) {
664200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint64_t tmp;
6658ae991e433d2c0814ea5579613f00173805ff057mtklein    SkFloatToHalf_finite_ftz(rgba).store(&tmp);
666e980155dd5d0cb6a10c9823c351763d50993a08dMatt Sarett    tmp &= 0x0000FFFFFFFFFFFF;
667200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    tmp |= static_cast<uint64_t>(SK_Half1) << 48;
668200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    *((uint64_t*) dst) = tmp;
669200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
670200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
671cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
6722563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI void store_generic(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
6732563601fc2b0505619f905f86bd249ae630197ccraftias                             const uint8_t* const dstTables[3]) {
674cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
675cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
67617e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    dr = Sk4f::Min(Sk4f::Max(1023.0f * dr, 0.0f), 1023.0f);
67717e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    dg = Sk4f::Min(Sk4f::Max(1023.0f * dg, 0.0f), 1023.0f);
67817e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    db = Sk4f::Min(Sk4f::Max(1023.0f * db, 0.0f), 1023.0f);
679200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
680200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ir = Sk4f_round(dr);
681200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ig = Sk4f_round(dg);
682200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i ib = Sk4f_round(db);
683200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
684200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i da = Sk4i::Load(src) & 0xFF000000;
685200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
686200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    uint32_t* dst32 = (uint32_t*) dst;
687200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[0] = dstTables[0][ir[0]] << kRShift
688200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[0]] << kGShift
689200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[0]] << kBShift
690200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[0];
691200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[1] = dstTables[0][ir[1]] << kRShift
692200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[1]] << kGShift
693200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[1]] << kBShift
694200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[1];
695200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[2] = dstTables[0][ir[2]] << kRShift
696200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[2]] << kGShift
697200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[2]] << kBShift
698200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[2];
699200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    dst32[3] = dstTables[0][ir[3]] << kRShift
700200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[1][ig[3]] << kGShift
701200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | dstTables[2][ib[3]] << kBShift
702200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett             | da[3];
703200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
704200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
705cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <Order kOrder>
706df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI void store_generic_1(void* dst, const uint32_t* src,
707df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               Sk4f& rgba, const Sk4f&,
708df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               const uint8_t* const dstTables[3]) {
709cf7b877d62537672b67449bc96858cc1262be5f8msarett    int kRShift, kGShift = 8, kBShift;
710cf7b877d62537672b67449bc96858cc1262be5f8msarett    set_rb_shifts(kOrder, &kRShift, &kBShift);
71117e494070ab1c76b2e5e4c0780b7a83c737dd84cMatt Sarett    rgba = Sk4f::Min(Sk4f::Max(1023.0f * rgba, 0.0f), 1023.0f);
712200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
713200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    Sk4i indices = Sk4f_round(rgba);
714200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
7159dc6cf6b8833d36c29a23d2519989b069745fcd5msarett    *((uint32_t*) dst) = dstTables[0][indices[0]] << kRShift
7169dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                       | dstTables[1][indices[1]] << kGShift
7179dc6cf6b8833d36c29a23d2519989b069745fcd5msarett                       | dstTables[2][indices[2]] << kBShift
718200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett                       | (*src & 0xFF000000);
719200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett}
720200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
721cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(load_rgb_from_tables<kRGBA_Order>  )* LoadFn;
722cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(load_rgb_from_tables_1<kRGBA_Order>)* Load1Fn;
723cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(store_generic<kRGBA_Order>         )* StoreFn;
724cf7b877d62537672b67449bc96858cc1262be5f8msaretttypedef decltype(store_generic_1<kRGBA_Order>       )* Store1Fn;
7258bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7268bbcd5aab81dc0742c3367479c0c9d97363b1203msarettenum SrcFormat {
7278bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kRGBA_8888_Linear_SrcFormat,
7288bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kRGBA_8888_Table_SrcFormat,
729cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Linear_SrcFormat,
730cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Table_SrcFormat,
7318bbcd5aab81dc0742c3367479c0c9d97363b1203msarett};
7328bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7338bbcd5aab81dc0742c3367479c0c9d97363b1203msarettenum DstFormat {
734cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_Linear_DstFormat,
735cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_SRGB_DstFormat,
736cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_2Dot2_DstFormat,
737cf7b877d62537672b67449bc96858cc1262be5f8msarett    kRGBA_8888_Table_DstFormat,
738cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Linear_DstFormat,
739cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_SRGB_DstFormat,
740cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_2Dot2_DstFormat,
741cf7b877d62537672b67449bc96858cc1262be5f8msarett    kBGRA_8888_Table_DstFormat,
7428bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    kF16_Linear_DstFormat,
7438bbcd5aab81dc0742c3367479c0c9d97363b1203msarett};
7448bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7458bbcd5aab81dc0742c3367479c0c9d97363b1203msaretttemplate <SrcFormat kSrc,
7468bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          DstFormat kDst,
7478bbcd5aab81dc0742c3367479c0c9d97363b1203msarett          SkAlphaType kAlphaType,
748cf7b877d62537672b67449bc96858cc1262be5f8msarett          ColorSpaceMatch kCSM>
7495934646b4937a05d5e8297448ea6613a89f8903aMatt Sarettstatic void color_xform_RGBA(void* dst, const void* vsrc, int len,
75026a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                             const float* const srcTables[3], const float matrix[13],
7515934646b4937a05d5e8297448ea6613a89f8903aMatt Sarett                             const uint8_t* const dstTables[3]) {
7528bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    LoadFn load;
7538bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Load1Fn load_1;
754e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett    const bool kLoadAlpha = kF16_Linear_DstFormat == kDst && kOpaque_SkAlphaType != kAlphaType;
7558bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (kSrc) {
7568bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kRGBA_8888_Linear_SrcFormat:
757abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett            if (kLoadAlpha) {
758cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_linear<kRGBA_Order>;
759cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_linear_1<kRGBA_Order>;
7608bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            } else {
761cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_linear<kRGBA_Order>;
762cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_linear_1<kRGBA_Order>;
7638bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            }
7648bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
7658bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kRGBA_8888_Table_SrcFormat:
766abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett            if (kLoadAlpha) {
767cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_from_tables<kRGBA_Order>;
768cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_from_tables_1<kRGBA_Order>;
7698bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            } else {
770cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_from_tables<kRGBA_Order>;
771cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_from_tables_1<kRGBA_Order>;
772cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
773cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
774cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Linear_SrcFormat:
775abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett            if (kLoadAlpha) {
776cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_linear<kBGRA_Order>;
777cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_linear_1<kBGRA_Order>;
778cf7b877d62537672b67449bc96858cc1262be5f8msarett            } else {
779cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_linear<kBGRA_Order>;
780cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_linear_1<kBGRA_Order>;
781cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
782cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
783cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Table_SrcFormat:
784abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett            if (kLoadAlpha) {
785cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgba_from_tables<kBGRA_Order>;
786cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgba_from_tables_1<kBGRA_Order>;
787cf7b877d62537672b67449bc96858cc1262be5f8msarett            } else {
788cf7b877d62537672b67449bc96858cc1262be5f8msarett                load = load_rgb_from_tables<kBGRA_Order>;
789cf7b877d62537672b67449bc96858cc1262be5f8msarett                load_1 = load_rgb_from_tables_1<kBGRA_Order>;
7908bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            }
7918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
7928bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
7938bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
7948bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    StoreFn store;
7958bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    Store1Fn store_1;
7968bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    size_t sizeOfDstPixel;
7978bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (kDst) {
798cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_Linear_DstFormat:
799cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_linear<kRGBA_Order>;
800cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_linear_1<kRGBA_Order>;
801cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
802cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
803cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_SRGB_DstFormat:
804cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_srgb<kRGBA_Order>;
805cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_srgb_1<kRGBA_Order>;
806cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
807cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
808cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_2Dot2_DstFormat:
809cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_2dot2<kRGBA_Order>;
810cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_2dot2_1<kRGBA_Order>;
8118bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
8128bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
813cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kRGBA_8888_Table_DstFormat:
814cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_generic<kRGBA_Order>;
815cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_generic_1<kRGBA_Order>;
8168bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
8178bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
818cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Linear_DstFormat:
819cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_linear<kBGRA_Order>;
820cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_linear_1<kBGRA_Order>;
8218bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
8228bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
823cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_SRGB_DstFormat:
824cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_srgb<kBGRA_Order>;
825cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_srgb_1<kBGRA_Order>;
826cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
827cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
828cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_2Dot2_DstFormat:
829cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_2dot2<kBGRA_Order>;
830cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_2dot2_1<kBGRA_Order>;
831cf7b877d62537672b67449bc96858cc1262be5f8msarett            sizeOfDstPixel = 4;
832cf7b877d62537672b67449bc96858cc1262be5f8msarett            break;
833cf7b877d62537672b67449bc96858cc1262be5f8msarett        case kBGRA_8888_Table_DstFormat:
834cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = store_generic<kBGRA_Order>;
835cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = store_generic_1<kBGRA_Order>;
8368bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 4;
8378bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
8388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kF16_Linear_DstFormat:
839cf7b877d62537672b67449bc96858cc1262be5f8msarett            store   = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_opaque<kRGBA_Order> :
840cf7b877d62537672b67449bc96858cc1262be5f8msarett                                                            store_f16<kRGBA_Order>;
841cf7b877d62537672b67449bc96858cc1262be5f8msarett            store_1 = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_1_opaque<kRGBA_Order> :
842cf7b877d62537672b67449bc96858cc1262be5f8msarett                                                            store_f16_1<kRGBA_Order>;
8438bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            sizeOfDstPixel = 8;
8448bbcd5aab81dc0742c3367479c0c9d97363b1203msarett            break;
8458bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
8468bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
847d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    const uint32_t* src = (const uint32_t*) vsrc;
848d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT;
849d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    load_matrix(matrix, rXgXbX, rYgYbY, rZgZbZ, rTgTbT);
850d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
851d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    if (len >= 4) {
852d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        // Naively this would be a loop of load-transform-store, but we found it faster to
853d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        // move the N+1th load ahead of the Nth store.  We don't bother doing this for N<4.
854d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        Sk4f r, g, b, a;
855d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        load(src, r, g, b, a, srcTables);
856d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        src += 4;
857d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        len -= 4;
858d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
859d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        Sk4f dr, dg, db, da;
860d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        while (len >= 4) {
861d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            if (kNone_ColorSpaceMatch == kCSM) {
862d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
863d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                translate_gamut(rTgTbT, dr, dg, db);
864d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            } else {
865d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                dr = r;
866d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                dg = g;
867d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                db = b;
868d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett                da = a;
869d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            }
870d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
871d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            load(src, r, g, b, a, srcTables);
872d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
873d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            store(dst, src - 4, dr, dg, db, da, dstTables);
874d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
875d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            src += 4;
876d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            len -= 4;
877d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
878d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
879d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        if (kNone_ColorSpaceMatch == kCSM) {
880d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
881d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            translate_gamut(rTgTbT, dr, dg, db);
882d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        } else {
883d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            dr = r;
884d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            dg = g;
885d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            db = b;
886d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            da = a;
887d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
888d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
889d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        store(dst, src - 4, dr, dg, db, da, dstTables);
890d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
891d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    }
892d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
893d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    while (len > 0) {
894d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        Sk4f r, g, b, a;
895d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        load_1(src, r, g, b, a, srcTables);
896d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
897d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        Sk4f rgba;
898d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        if (kNone_ColorSpaceMatch == kCSM) {
899d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            transform_gamut_1(r, g, b, rXgXbX, rYgYbY, rZgZbZ, rgba);
900d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            translate_gamut_1(rTgTbT, rgba);
901d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        } else {
902d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett            rgba = Sk4f(r[0], g[0], b[0], a[0]);
903d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        }
904d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
905d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        store_1(dst, src, rgba, a, dstTables);
906d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett
907d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        src += 1;
908d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        len -= 1;
909d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett        dst = SkTAddOffset<void>(dst, sizeOfDstPixel);
910d478a99f5c29f0e8fa64b50831f53232f5577f2dMatt Sarett    }
9118bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
9128bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
9133418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett///////////////////////////////////////////////////////////////////////////////////////////////////
9140f83e0151f757ecd8d55d55ffefef58ecb11a97bmsarett
9152563601fc2b0505619f905f86bd249ae630197ccraftiasstatic AI int num_tables(SkColorSpace_XYZ* space) {
9169488833428e83c93a7e6002f4d056084fb57112fraftias    switch (space->gammaNamed()) {
9177bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case kSRGB_SkGammaNamed:
9187bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case k2Dot2Curve_SkGammaNamed:
9197bbda991af353fbe6b34132132d211d23a3dba8cmsarett        case kLinear_SkGammaNamed:
9207bbda991af353fbe6b34132132d211d23a3dba8cmsarett            return 0;
9217bbda991af353fbe6b34132132d211d23a3dba8cmsarett        default: {
9229488833428e83c93a7e6002f4d056084fb57112fraftias            const SkGammas* gammas = space->gammas();
9237bbda991af353fbe6b34132132d211d23a3dba8cmsarett            SkASSERT(gammas);
9247bbda991af353fbe6b34132132d211d23a3dba8cmsarett
9257bbda991af353fbe6b34132132d211d23a3dba8cmsarett            bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) &&
9267bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->data(0) == gammas->data(1)) &&
9277bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->type(0) == gammas->type(2)) &&
9287bbda991af353fbe6b34132132d211d23a3dba8cmsarett                                     (gammas->data(0) == gammas->data(2));
9297bbda991af353fbe6b34132132d211d23a3dba8cmsarett
9307bbda991af353fbe6b34132132d211d23a3dba8cmsarett            // It's likely that each component will have the same gamma.  In this case,
9317bbda991af353fbe6b34132132d211d23a3dba8cmsarett            // we only need to build one table.
9327bbda991af353fbe6b34132132d211d23a3dba8cmsarett            return gammasAreMatching ? 1 : 3;
9337bbda991af353fbe6b34132132d211d23a3dba8cmsarett        }
9347bbda991af353fbe6b34132132d211d23a3dba8cmsarett    }
9357bbda991af353fbe6b34132132d211d23a3dba8cmsarett}
9367bbda991af353fbe6b34132132d211d23a3dba8cmsarett
937379938e47bc9edb6edfd21aabefa01aed71dd135Matt Saretttemplate <ColorSpaceMatch kCSM>
938379938e47bc9edb6edfd21aabefa01aed71dd135Matt SarettSkColorSpaceXform_XYZ<kCSM>
9399488833428e83c93a7e6002f4d056084fb57112fraftias::SkColorSpaceXform_XYZ(SkColorSpace_XYZ* srcSpace, const SkMatrix44& srcToDst,
940cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett                        SkColorSpace_XYZ* dstSpace, SkTransferFunctionBehavior premulBehavior)
941cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett    : fPremulBehavior(premulBehavior)
9423418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett{
94326a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[ 0] = srcToDst.get(0, 0);
94426a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[ 1] = srcToDst.get(1, 0);
94526a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[ 2] = srcToDst.get(2, 0);
94626a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[ 3] = srcToDst.get(0, 1);
94726a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[ 4] = srcToDst.get(1, 1);
94826a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[ 5] = srcToDst.get(2, 1);
94926a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[ 6] = srcToDst.get(0, 2);
95026a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[ 7] = srcToDst.get(1, 2);
95126a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[ 8] = srcToDst.get(2, 2);
95226a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[ 9] = srcToDst.get(0, 3);
95326a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[10] = srcToDst.get(1, 3);
95426a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[11] = srcToDst.get(2, 3);
95526a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    fSrcToDst[12] = 0.0f;
9567bbda991af353fbe6b34132132d211d23a3dba8cmsarett
9574be0e7cfe0efceeaf4c7a4d598d77c27cfd3e69bmsarett    const int numSrcTables = num_tables(srcSpace);
958f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    const size_t srcEntries = numSrcTables * 256;
9597bbda991af353fbe6b34132132d211d23a3dba8cmsarett    const bool srcGammasAreMatching = (1 >= numSrcTables);
960f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    fSrcStorage.reset(srcEntries);
961f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    build_gamma_tables(fSrcGammaTables, fSrcStorage.get(), 256, srcSpace, kToLinear,
962f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                       srcGammasAreMatching);
963f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett
964f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    const int numDstTables = num_tables(dstSpace);
9659488833428e83c93a7e6002f4d056084fb57112fraftias    dstSpace->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTables);
966379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett
967379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett    if (srcSpace->gammaIsLinear()) {
968379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        fSrcGamma = kLinear_SrcGamma;
969379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett    } else if (kSRGB_SkGammaNamed == srcSpace->gammaNamed()) {
970379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        fSrcGamma = kSRGB_SrcGamma;
971379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett    } else {
972379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        fSrcGamma = kTable_SrcGamma;
973379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett    }
974379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett
975379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett    switch (dstSpace->gammaNamed()) {
976379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        case kSRGB_SkGammaNamed:
977379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            fDstGamma = kSRGB_DstGamma;
978379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            break;
979379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        case k2Dot2Curve_SkGammaNamed:
980379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            fDstGamma = k2Dot2_DstGamma;
981379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            break;
982379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        case kLinear_SkGammaNamed:
983379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            fDstGamma = kLinear_DstGamma;
984379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            break;
985379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        default:
986379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            fDstGamma = kTable_DstGamma;
987379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            break;
988379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett    }
9893418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett}
990dc27a648d2ff23b2e96232c00c15976c46e1d48dmsarett
9917bbda991af353fbe6b34132132d211d23a3dba8cmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
9927bbda991af353fbe6b34132132d211d23a3dba8cmsarett
993cf7b877d62537672b67449bc96858cc1262be5f8msaretttemplate <SrcFormat kSrc, DstFormat kDst, ColorSpaceMatch kCSM>
994df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI bool apply_set_alpha(void* dst, const void* src, int len, SkAlphaType alphaType,
99526a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                               const float* const srcTables[3], const float matrix[13],
996df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                               const uint8_t* const dstTables[3]) {
9978bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    switch (alphaType) {
9988bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kOpaque_SkAlphaType:
99931d097e865f266c8398f45114e4c75c0dfdef058msarett            color_xform_RGBA<kSrc, kDst, kOpaque_SkAlphaType, kCSM>
10008bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
100131d097e865f266c8398f45114e4c75c0dfdef058msarett            return true;
10028bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        case kUnpremul_SkAlphaType:
100331d097e865f266c8398f45114e4c75c0dfdef058msarett            color_xform_RGBA<kSrc, kDst, kUnpremul_SkAlphaType, kCSM>
10048bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                    (dst, src, len, srcTables, matrix, dstTables);
100531d097e865f266c8398f45114e4c75c0dfdef058msarett            return true;
10068bbcd5aab81dc0742c3367479c0c9d97363b1203msarett        default:
100731d097e865f266c8398f45114e4c75c0dfdef058msarett            return false;
10088bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
10098bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
10108bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
1011379938e47bc9edb6edfd21aabefa01aed71dd135Matt Saretttemplate <DstFormat kDst, ColorSpaceMatch kCSM>
1012df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarettstatic AI bool apply_set_src(void* dst, const void* src, int len, SkAlphaType alphaType,
101326a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                             const float* const srcTables[3], const float matrix[13],
1014df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett                             const uint8_t* const dstTables[3],
1015379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                             SkColorSpaceXform::ColorFormat srcColorFormat,
1016379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                             SrcGamma srcGamma) {
1017cf7b877d62537672b67449bc96858cc1262be5f8msarett    switch (srcColorFormat) {
1018cf7b877d62537672b67449bc96858cc1262be5f8msarett        case SkColorSpaceXform::kRGBA_8888_ColorFormat:
1019379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            switch (srcGamma) {
1020cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kLinear_SrcGamma:
1021cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kRGBA_8888_Linear_SrcFormat, kDst, kCSM>
1022cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, nullptr, matrix, dstTables);
1023379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                default:
1024cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kRGBA_8888_Table_SrcFormat, kDst, kCSM>
1025cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, srcTables, matrix, dstTables);
1026cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
1027cf7b877d62537672b67449bc96858cc1262be5f8msarett        case SkColorSpaceXform::kBGRA_8888_ColorFormat:
1028379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            switch (srcGamma) {
1029cf7b877d62537672b67449bc96858cc1262be5f8msarett                case kLinear_SrcGamma:
1030cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kBGRA_8888_Linear_SrcFormat, kDst, kCSM>
1031cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, nullptr, matrix, dstTables);
1032379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                default:
1033cf7b877d62537672b67449bc96858cc1262be5f8msarett                    return apply_set_alpha<kBGRA_8888_Table_SrcFormat, kDst, kCSM>
1034cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, srcTables, matrix, dstTables);
1035cf7b877d62537672b67449bc96858cc1262be5f8msarett            }
1036cf7b877d62537672b67449bc96858cc1262be5f8msarett        default:
103731d097e865f266c8398f45114e4c75c0dfdef058msarett            return false;
10388bbcd5aab81dc0742c3367479c0c9d97363b1203msarett    }
10398bbcd5aab81dc0742c3367479c0c9d97363b1203msarett}
10408bbcd5aab81dc0742c3367479c0c9d97363b1203msarett
1041df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett#undef AI
1042df303a6f59a2121c133738d6304d2476689a4fd9Matt Sarett
1043379938e47bc9edb6edfd21aabefa01aed71dd135Matt Saretttemplate <ColorSpaceMatch kCSM>
1044379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarettbool SkColorSpaceXform_XYZ<kCSM>
104531d097e865f266c8398f45114e4c75c0dfdef058msarett::onApply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat, const void* src,
104631d097e865f266c8398f45114e4c75c0dfdef058msarett          int len, SkAlphaType alphaType) const
10473418c0e797e2ee841d1c031ca9d7a5ba73205f51msarett{
1048200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    if (kFull_ColorSpaceMatch == kCSM) {
1049abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett        if (kPremul_SkAlphaType != alphaType) {
1050abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett            if ((kRGBA_8888_ColorFormat == dstColorFormat &&
1051abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett                 kRGBA_8888_ColorFormat == srcColorFormat) ||
1052abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett                (kBGRA_8888_ColorFormat == dstColorFormat &&
1053abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett                 kBGRA_8888_ColorFormat == srcColorFormat))
1054abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett            {
1055abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett                memcpy(dst, src, len * sizeof(uint32_t));
1056abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett                return true;
1057abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett            }
1058abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett            if ((kRGBA_8888_ColorFormat == dstColorFormat &&
1059abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett                 kBGRA_8888_ColorFormat == srcColorFormat) ||
1060abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett                (kBGRA_8888_ColorFormat == dstColorFormat &&
1061abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett                 kRGBA_8888_ColorFormat == srcColorFormat))
1062abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett            {
1063abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett                SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len);
1064abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett                return true;
1065abf8ba34c8038b814e67fe7c4dcf6c9915d81698Matt Sarett            }
1066200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett        }
1067200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett    }
1068200877eecaba782e56a1dd9e13a92f36d7b1ba12msarett
10695bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett    if (kRGBA_F32_ColorFormat == dstColorFormat ||
107068185be3389102cb8c979a26cbea72a39ac214caMatt Sarett        kBGR_565_ColorFormat == dstColorFormat ||
10714c55027dbf57d0701361b123e36b8fad46c341c3Matt Sarett        kRGBA_F32_ColorFormat == srcColorFormat ||
1072b1168a7c9a360bf80b447e2e399bdc5721d5152eBrian Osman        kRGBA_F16_ColorFormat == srcColorFormat ||
10735bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett        kRGBA_U16_BE_ColorFormat == srcColorFormat ||
1074e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett        kRGB_U16_BE_ColorFormat == srcColorFormat ||
1075e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett        kPremul_SkAlphaType == alphaType)
10765bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett    {
107726a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett        return this->applyPipeline(dstColorFormat, dst, srcColorFormat, src, len, alphaType);
107826a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    }
107926a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett
1080c0444615ed76360f680619ad4d1f92cda6181a50msarett    switch (dstColorFormat) {
1081c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_8888_ColorFormat:
1082379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            switch (fDstGamma) {
10838bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
1084379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    return apply_set_src<kRGBA_8888_Linear_DstFormat, kCSM>
1085cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1086379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                             srcColorFormat, fSrcGamma);
10878bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kSRGB_DstGamma:
1088379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    return apply_set_src<kRGBA_8888_SRGB_DstFormat, kCSM>
1089cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1090379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                             srcColorFormat, fSrcGamma);
10918bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case k2Dot2_DstGamma:
1092379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    return apply_set_src<kRGBA_8888_2Dot2_DstFormat, kCSM>
1093cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1094379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                             srcColorFormat, fSrcGamma);
10958bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kTable_DstGamma:
1096379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    return apply_set_src<kRGBA_8888_Table_DstFormat, kCSM>
1097cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables,
1098379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                             srcColorFormat, fSrcGamma);
1099d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1100c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kBGRA_8888_ColorFormat:
1101379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            switch (fDstGamma) {
11028bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
1103379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    return apply_set_src<kBGRA_8888_Linear_DstFormat, kCSM>
1104cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1105379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                             srcColorFormat, fSrcGamma);
11068bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kSRGB_DstGamma:
1107379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    return apply_set_src<kBGRA_8888_SRGB_DstFormat, kCSM>
1108cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1109379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                             srcColorFormat, fSrcGamma);
11108bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case k2Dot2_DstGamma:
1111379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    return apply_set_src<kBGRA_8888_2Dot2_DstFormat, kCSM>
1112cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1113379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                             srcColorFormat, fSrcGamma);
11148bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kTable_DstGamma:
1115379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    return apply_set_src<kBGRA_8888_Table_DstFormat, kCSM>
1116cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables,
1117379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                             srcColorFormat, fSrcGamma);
1118d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1119c0444615ed76360f680619ad4d1f92cda6181a50msarett        case kRGBA_F16_ColorFormat:
1120379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            switch (fDstGamma) {
11218bbcd5aab81dc0742c3367479c0c9d97363b1203msarett                case kLinear_DstGamma:
1122379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    return apply_set_src<kF16_Linear_DstFormat, kCSM>
1123cf7b877d62537672b67449bc96858cc1262be5f8msarett                            (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
1124379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                             srcColorFormat, fSrcGamma);
1125d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett                default:
112631d097e865f266c8398f45114e4c75c0dfdef058msarett                    return false;
1127d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett            }
1128d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett        default:
112926a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett            SkASSERT(false);
113031d097e865f266c8398f45114e4c75c0dfdef058msarett            return false;
1131d1ec89b1aca8f37a460a425259a23275f4d9a81dmsarett    }
11329ce3a543c92a73e6daca420defc042886b3f2019msarett}
11339dc6cf6b8833d36c29a23d2519989b069745fcd5msarett
1134f489886915034093278353d06c6f1973b2e8b7d2Matt Sarettbool SkColorSpaceXform::apply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat,
1135f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                              const void* src, int len, SkAlphaType alphaType) const {
1136f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett    return ((SkColorSpaceXform_Base*) this)->onApply(dstColorFormat, dst, srcColorFormat, src, len,
1137f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett                                                     alphaType);
1138f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett}
1139f489886915034093278353d06c6f1973b2e8b7d2Matt Sarett
11407bbda991af353fbe6b34132132d211d23a3dba8cmsarett///////////////////////////////////////////////////////////////////////////////////////////////////
11417bbda991af353fbe6b34132132d211d23a3dba8cmsarett
1142379938e47bc9edb6edfd21aabefa01aed71dd135Matt Saretttemplate <ColorSpaceMatch kCSM>
1143379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarettbool SkColorSpaceXform_XYZ<kCSM>
114426a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett::applyPipeline(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat,
114526a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                const void* src, int len, SkAlphaType alphaType) const {
114626a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    SkRasterPipeline pipeline;
1147f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett
114826a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    LoadTablesContext loadTables;
114926a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    switch (srcColorFormat) {
115026a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett        case kRGBA_8888_ColorFormat:
1151379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            if (kLinear_SrcGamma == fSrcGamma) {
115226a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                pipeline.append(SkRasterPipeline::load_8888, &src);
115326a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett            } else {
1154379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                loadTables.fSrc = src;
115526a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                loadTables.fR = fSrcGammaTables[0];
115626a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                loadTables.fG = fSrcGammaTables[1];
115726a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                loadTables.fB = fSrcGammaTables[2];
115826a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                pipeline.append(SkRasterPipeline::load_tables, &loadTables);
1159f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            }
1160f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett
116126a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett            break;
116226a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett        case kBGRA_8888_ColorFormat:
1163379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            if (kLinear_SrcGamma == fSrcGamma) {
116426a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                pipeline.append(SkRasterPipeline::load_8888, &src);
116526a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett            } else {
1166379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                loadTables.fSrc = src;
116726a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                loadTables.fR = fSrcGammaTables[2];
116826a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                loadTables.fG = fSrcGammaTables[1];
116926a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                loadTables.fB = fSrcGammaTables[0];
117026a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett                pipeline.append(SkRasterPipeline::load_tables, &loadTables);
1171f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            }
1172f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett
1173f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            pipeline.append(SkRasterPipeline::swap_rb);
117426a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett            break;
1175b1168a7c9a360bf80b447e2e399bdc5721d5152eBrian Osman        case kRGBA_F16_ColorFormat:
1176b1168a7c9a360bf80b447e2e399bdc5721d5152eBrian Osman            if (kLinear_SrcGamma != fSrcGamma) {
1177b1168a7c9a360bf80b447e2e399bdc5721d5152eBrian Osman                return false;
1178b1168a7c9a360bf80b447e2e399bdc5721d5152eBrian Osman            }
1179b1168a7c9a360bf80b447e2e399bdc5721d5152eBrian Osman            pipeline.append(SkRasterPipeline::load_f16, &src);
1180b1168a7c9a360bf80b447e2e399bdc5721d5152eBrian Osman            break;
11814c55027dbf57d0701361b123e36b8fad46c341c3Matt Sarett        case kRGBA_F32_ColorFormat:
11824c55027dbf57d0701361b123e36b8fad46c341c3Matt Sarett            if (kLinear_SrcGamma != fSrcGamma) {
11834c55027dbf57d0701361b123e36b8fad46c341c3Matt Sarett                return false;
11844c55027dbf57d0701361b123e36b8fad46c341c3Matt Sarett            }
11854c55027dbf57d0701361b123e36b8fad46c341c3Matt Sarett            pipeline.append(SkRasterPipeline::load_f32, &src);
11864c55027dbf57d0701361b123e36b8fad46c341c3Matt Sarett            break;
1187379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        case kRGBA_U16_BE_ColorFormat:
1188379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            switch (fSrcGamma) {
1189379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                case kLinear_SrcGamma:
1190379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    pipeline.append(SkRasterPipeline::load_u16_be, &src);
1191379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    break;
1192379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                case kSRGB_SrcGamma:
1193379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    pipeline.append(SkRasterPipeline::load_u16_be, &src);
1194379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    pipeline.append_from_srgb(kUnpremul_SkAlphaType);
1195379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    break;
1196379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                case kTable_SrcGamma:
1197379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    loadTables.fSrc = src;
1198379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    loadTables.fR = fSrcGammaTables[0];
1199379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    loadTables.fG = fSrcGammaTables[1];
1200379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    loadTables.fB = fSrcGammaTables[2];
1201379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    pipeline.append(SkRasterPipeline::load_tables_u16_be, &loadTables);
1202379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett                    break;
1203379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            }
1204379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            break;
12055bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett        case kRGB_U16_BE_ColorFormat:
12065bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett            switch (fSrcGamma) {
12075bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                case kLinear_SrcGamma:
12085bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                    pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src);
12095bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                    break;
12105bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                case kSRGB_SrcGamma:
12115bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                    pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src);
12125bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                    pipeline.append_from_srgb(kUnpremul_SkAlphaType);
12135bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                    break;
12145bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                case kTable_SrcGamma:
12155bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                    loadTables.fSrc = src;
12165bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                    loadTables.fR = fSrcGammaTables[0];
12175bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                    loadTables.fG = fSrcGammaTables[1];
12185bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                    loadTables.fB = fSrcGammaTables[2];
12195bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                    pipeline.append(SkRasterPipeline::load_tables_rgb_u16_be, &loadTables);
12205bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett                    break;
12215bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett            }
12225bee0b6de6b3ad1166d067e6b5046b48b8240a29Matt Sarett            break;
122368185be3389102cb8c979a26cbea72a39ac214caMatt Sarett        default:
122468185be3389102cb8c979a26cbea72a39ac214caMatt Sarett            return false;
1225f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett    }
1226f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett
122726a0543579cf7473de2099ce0d056ac8aba83811Matt Sarett    if (kNone_ColorSpaceMatch == kCSM) {
1228f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett        pipeline.append(SkRasterPipeline::matrix_3x4, fSrcToDst);
1229f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett
12307b2d1f683f59eb41c3d9c4011a1177489288a749Matt Sarett        if (kRGBA_8888_ColorFormat == dstColorFormat ||
12317b2d1f683f59eb41c3d9c4011a1177489288a749Matt Sarett            kBGRA_8888_ColorFormat == dstColorFormat ||
12327b2d1f683f59eb41c3d9c4011a1177489288a749Matt Sarett            kBGR_565_ColorFormat == dstColorFormat)
12337b2d1f683f59eb41c3d9c4011a1177489288a749Matt Sarett        {
12345e15961fa77281540a80ac0d036fefe071c11574Mike Klein            bool need_clamp_0, need_clamp_1;
12355e15961fa77281540a80ac0d036fefe071c11574Mike Klein            analyze_3x4_matrix(fSrcToDst, &need_clamp_0, &need_clamp_1);
12365e15961fa77281540a80ac0d036fefe071c11574Mike Klein
12375e15961fa77281540a80ac0d036fefe071c11574Mike Klein            if (need_clamp_0) { pipeline.append(SkRasterPipeline::clamp_0); }
12385e15961fa77281540a80ac0d036fefe071c11574Mike Klein            if (need_clamp_1) { pipeline.append(SkRasterPipeline::clamp_1); }
12395e15961fa77281540a80ac0d036fefe071c11574Mike Klein        }
1240f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett    }
1241f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett
1242cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett    if (kPremul_SkAlphaType == alphaType && SkTransferFunctionBehavior::kRespect == fPremulBehavior)
1243cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett    {
1244f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett        pipeline.append(SkRasterPipeline::premul);
1245f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett    }
1246f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett
1247e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett    TablesContext tables;
1248379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett    switch (fDstGamma) {
1249f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett        case kSRGB_DstGamma:
1250f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            pipeline.append(SkRasterPipeline::to_srgb);
1251f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            break;
1252f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett        case k2Dot2_DstGamma:
1253f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            pipeline.append(SkRasterPipeline::to_2dot2);
1254f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            break;
1255e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett        case kTable_DstGamma:
1256e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett            tables.fR = fDstGammaTables[0];
1257e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett            tables.fG = fDstGammaTables[1];
1258e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett            tables.fB = fDstGammaTables[2];
1259e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett            tables.fCount = SkColorSpaceXform_Base::kDstGammaTableSize;
1260e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett            pipeline.append(SkRasterPipeline::byte_tables_rgb, &tables);
1261f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett        default:
1262f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            break;
1263f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett    }
1264f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett
1265cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett    if (kPremul_SkAlphaType == alphaType && SkTransferFunctionBehavior::kIgnore == fPremulBehavior)
1266cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett    {
1267e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett        pipeline.append(SkRasterPipeline::premul);
1268e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett    }
1269e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett
1270f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett    switch (dstColorFormat) {
1271f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett        case kRGBA_8888_ColorFormat:
1272e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett             pipeline.append(SkRasterPipeline::store_8888, &dst);
1273f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            break;
1274f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett        case kBGRA_8888_ColorFormat:
1275e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett            pipeline.append(SkRasterPipeline::swap_rb);
1276e522f4c455d0d5dbe813f38d16c0d4cd46fa5deeMatt Sarett            pipeline.append(SkRasterPipeline::store_8888, &dst);
1277f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            break;
1278f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett        case kRGBA_F16_ColorFormat:
1279cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett            if (kLinear_DstGamma != fDstGamma) {
1280f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett                return false;
1281f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            }
1282f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            pipeline.append(SkRasterPipeline::store_f16, &dst);
1283f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            break;
1284f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett        case kRGBA_F32_ColorFormat:
1285cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett            if (kLinear_DstGamma != fDstGamma) {
1286f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett                return false;
1287f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            }
1288f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            pipeline.append(SkRasterPipeline::store_f32, &dst);
1289f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett            break;
129068185be3389102cb8c979a26cbea72a39ac214caMatt Sarett        case kBGR_565_ColorFormat:
129168185be3389102cb8c979a26cbea72a39ac214caMatt Sarett            if (kOpaque_SkAlphaType != alphaType) {
129268185be3389102cb8c979a26cbea72a39ac214caMatt Sarett                return false;
129368185be3389102cb8c979a26cbea72a39ac214caMatt Sarett            }
129468185be3389102cb8c979a26cbea72a39ac214caMatt Sarett            pipeline.append(SkRasterPipeline::store_565, &dst);
129568185be3389102cb8c979a26cbea72a39ac214caMatt Sarett            break;
1296379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett        default:
1297379938e47bc9edb6edfd21aabefa01aed71dd135Matt Sarett            return false;
1298f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett    }
1299f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett
1300319ba3d3a177498095c31696e0aec8b3af25f663Mike Klein    pipeline.run(0, len);
1301f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett    return true;
1302f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett}
1303f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett
1304f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett///////////////////////////////////////////////////////////////////////////////////////////////////
1305f6878baba8c7cd347e185361bac2eabaef863bfaMatt Sarett
13069488833428e83c93a7e6002f4d056084fb57112fraftiasstd::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space) {
1307cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett    return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ<kNone_ColorSpaceMatch>
1308cf3f2347c8933596aeba873d4ece597a9339392fMatt Sarett            (space, SkMatrix::I(), space, SkTransferFunctionBehavior::kRespect));
13099dc6cf6b8833d36c29a23d2519989b069745fcd5msarett}
1310