blob: dccb92ee9ab706634c7a6ba8172109bc2104b365 [file] [log] [blame]
msarett9876ac52016-06-01 14:47:18 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkColorPriv.h"
raftias94888332016-10-18 10:02:51 -07009#include "SkColorSpace_A2B.h"
msarett9876ac52016-06-01 14:47:18 -070010#include "SkColorSpace_Base.h"
raftias94888332016-10-18 10:02:51 -070011#include "SkColorSpace_XYZ.h"
msarett200877e2016-08-15 08:10:44 -070012#include "SkColorSpacePriv.h"
raftias25636012016-11-11 15:27:39 -080013#include "SkColorSpaceXform_A2B.h"
msarett31d097e82016-10-11 12:15:03 -070014#include "SkColorSpaceXform_Base.h"
raftias25636012016-11-11 15:27:39 -080015#include "SkColorSpaceXformPriv.h"
msarett200877e2016-08-15 08:10:44 -070016#include "SkHalf.h"
17#include "SkOpts.h"
Mike Klein5e159612016-12-01 16:39:21 -050018#include "SkPM4fPriv.h"
Matt Sarettf6878ba2016-12-01 14:46:12 -050019#include "SkRasterPipeline.h"
mtkleinac41bac2016-07-08 06:33:16 -070020#include "SkSRGB.h"
msarett9876ac52016-06-01 14:47:18 -070021
msarett6006f672016-07-11 05:49:17 -070022static constexpr float sk_linear_from_2dot2[256] = {
msarettb3906762016-06-22 14:07:48 -070023 0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.000056921765712193f,
24 0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.000367136269815943f,
25 0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.000992374304074325f,
26 0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.001963416213396470f,
27 0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.003302703032003640f,
28 0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.005028203456855540f,
29 0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.007155037004573030f,
30 0.007751027397660610f, 0.008373117745148580f, 0.009021491898012130f, 0.009696328701658230f,
31 0.010397802292555300f, 0.011126082368383200f, 0.011881334434813700f, 0.012663720031582100f,
32 0.013473396940142600f, 0.014310519374884100f, 0.015175238159625200f, 0.016067700890886900f,
33 0.016988052089250000f, 0.017936433339950200f, 0.018912983423721500f, 0.019917838438785700f,
34 0.020951131914781100f, 0.022012994919336500f, 0.023103556157921400f, 0.024222942067534200f,
35 0.025371276904734600f, 0.026548682828472900f, 0.027755279978126000f, 0.028991186547107800f,
36 0.030256518852388700f, 0.031551391400226400f, 0.032875916948383800f, 0.034230206565082000f,
37 0.035614369684918800f, 0.037028514161960200f, 0.038472746320194600f, 0.039947171001525600f,
38 0.041451891611462500f, 0.042987010162657100f, 0.044552627316421400f, 0.046148842422351000f,
39 0.047775753556170600f, 0.049433457555908000f, 0.051122050056493400f, 0.052841625522879000f,
40 0.054592277281760300f, 0.056374097551979800f, 0.058187177473685400f, 0.060031607136313200f,
41 0.061907475605455800f, 0.063814870948677200f, 0.065753880260330100f, 0.067724589685424300f,
42 0.069727084442598800f, 0.071761448846239100f, 0.073827766327784600f, 0.075926119456264800f,
43 0.078056589958101900f, 0.080219258736215100f, 0.082414205888459200f, 0.084641510725429500f,
44 0.086901251787660300f, 0.089193506862247800f, 0.091518352998919500f, 0.093875866525577800f,
45 0.096266123063339700f, 0.098689197541094500f, 0.101145164209600000f, 0.103634096655137000f,
46 0.106156067812744000f, 0.108711149979039000f, 0.111299414824660000f, 0.113920933406333000f,
47 0.116575776178572000f, 0.119264013005047000f, 0.121985713169619000f, 0.124740945387051000f,
48 0.127529777813422000f, 0.130352278056244000f, 0.133208513184300000f, 0.136098549737202000f,
49 0.139022453734703000f, 0.141980290685736000f, 0.144972125597231000f, 0.147998022982685000f,
50 0.151058046870511000f, 0.154152260812165000f, 0.157280727890073000f, 0.160443510725344000f,
51 0.163640671485290000f, 0.166872271890766000f, 0.170138373223312000f, 0.173439036332135000f,
52 0.176774321640903000f, 0.180144289154390000f, 0.183548998464951000f, 0.186988508758844000f,
53 0.190462878822409000f, 0.193972167048093000f, 0.197516431440340000f, 0.201095729621346000f,
54 0.204710118836677000f, 0.208359655960767000f, 0.212044397502288000f, 0.215764399609395000f,
55 0.219519718074868000f, 0.223310408341127000f, 0.227136525505149000f, 0.230998124323267000f,
56 0.234895259215880000f, 0.238827984272048000f, 0.242796353254002000f, 0.246800419601550000f,
57 0.250840236436400000f, 0.254915856566385000f, 0.259027332489606000f, 0.263174716398492000f,
58 0.267358060183772000f, 0.271577415438375000f, 0.275832833461245000f, 0.280124365261085000f,
59 0.284452061560024000f, 0.288815972797219000f, 0.293216149132375000f, 0.297652640449211000f,
60 0.302125496358853000f, 0.306634766203158000f, 0.311180499057984000f, 0.315762743736397000f,
61 0.320381548791810000f, 0.325036962521076000f, 0.329729032967515000f, 0.334457807923889000f,
62 0.339223334935327000f, 0.344025661302187000f, 0.348864834082879000f, 0.353740900096629000f,
63 0.358653905926199000f, 0.363603897920553000f, 0.368590922197487000f, 0.373615024646202000f,
64 0.378676250929840000f, 0.383774646487975000f, 0.388910256539059000f, 0.394083126082829000f,
65 0.399293299902674000f, 0.404540822567962000f, 0.409825738436323000f, 0.415148091655907000f,
66 0.420507926167587000f, 0.425905285707146000f, 0.431340213807410000f, 0.436812753800359000f,
67 0.442322948819202000f, 0.447870841800410000f, 0.453456475485731000f, 0.459079892424160000f,
68 0.464741134973889000f, 0.470440245304218000f, 0.476177265397440000f, 0.481952237050698000f,
69 0.487765201877811000f, 0.493616201311074000f, 0.499505276603030000f, 0.505432468828216000f,
70 0.511397818884880000f, 0.517401367496673000f, 0.523443155214325000f, 0.529523222417277000f,
71 0.535641609315311000f, 0.541798355950137000f, 0.547993502196972000f, 0.554227087766085000f,
72 0.560499152204328000f, 0.566809734896638000f, 0.573158875067523000f, 0.579546611782525000f,
73 0.585972983949661000f, 0.592438030320847000f, 0.598941789493296000f, 0.605484299910907000f,
74 0.612065599865624000f, 0.618685727498780000f, 0.625344720802427000f, 0.632042617620641000f,
75 0.638779455650817000f, 0.645555272444935000f, 0.652370105410821000f, 0.659223991813387000f,
76 0.666116968775851000f, 0.673049073280942000f, 0.680020342172095000f, 0.687030812154625000f,
77 0.694080519796882000f, 0.701169501531402000f, 0.708297793656032000f, 0.715465432335048000f,
78 0.722672453600255000f, 0.729918893352071000f, 0.737204787360605000f, 0.744530171266715000f,
79 0.751895080583051000f, 0.759299550695091000f, 0.766743616862161000f, 0.774227314218442000f,
80 0.781750677773962000f, 0.789313742415586000f, 0.796916542907978000f, 0.804559113894567000f,
81 0.812241489898490000f, 0.819963705323528000f, 0.827725794455034000f, 0.835527791460841000f,
82 0.843369730392169000f, 0.851251645184515000f, 0.859173569658532000f, 0.867135537520905000f,
83 0.875137582365205000f, 0.883179737672745000f, 0.891262036813419000f, 0.899384513046529000f,
84 0.907547199521614000f, 0.915750129279253000f, 0.923993335251873000f, 0.932276850264543000f,
85 0.940600707035753000f, 0.948964938178195000f, 0.957369576199527000f, 0.965814653503130000f,
86 0.974300202388861000f, 0.982826255053791000f, 0.991392843592940000f, 1.000000000000000000f,
87};
88
msarett6006f672016-07-11 05:49:17 -070089///////////////////////////////////////////////////////////////////////////////////////////////////
90
msarett15ee3de2016-08-02 11:30:30 -070091static void build_table_linear_from_gamma(float* outTable, float exponent) {
92 for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
93 *outTable++ = powf(x, exponent);
94 }
95}
96
msarett15ee3de2016-08-02 11:30:30 -070097// outTable is always 256 entries, inTable may be larger or smaller.
98static void build_table_linear_from_gamma(float* outTable, const float* inTable,
99 int inTableSize) {
100 if (256 == inTableSize) {
101 memcpy(outTable, inTable, sizeof(float) * 256);
102 return;
103 }
104
105 for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
106 *outTable++ = interp_lut(x, inTable, inTableSize);
107 }
108}
109
Matt Sarettaa34f7e2016-11-09 18:14:47 -0500110
msarett15ee3de2016-08-02 11:30:30 -0700111static void build_table_linear_from_gamma(float* outTable, float g, float a, float b, float c,
112 float d, float e, float f) {
Matt Sarett24107172016-12-19 14:33:35 -0500113 // Y = (aX + b)^g + e for X >= d
114 // Y = cX + f otherwise
msarett15ee3de2016-08-02 11:30:30 -0700115 for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
116 if (x >= d) {
Matt Sarett24107172016-12-19 14:33:35 -0500117 *outTable++ = clamp_0_1(powf(a * x + b, g) + e);
msarett15ee3de2016-08-02 11:30:30 -0700118 } else {
Matt Sarett24107172016-12-19 14:33:35 -0500119 *outTable++ = clamp_0_1(c * x + f);
msarett15ee3de2016-08-02 11:30:30 -0700120 }
121 }
122}
123
124///////////////////////////////////////////////////////////////////////////////////////////////////
125
Matt Sarettf4898862016-10-16 10:20:41 -0400126static const int kDstGammaTableSize = SkColorSpaceXform_Base::kDstGammaTableSize;
msarett3418c0e2016-07-25 18:23:18 -0700127
msarett1b93bd12016-07-21 07:11:26 -0700128static void build_table_linear_to_gamma(uint8_t* outTable, float exponent) {
msarettb3906762016-06-22 14:07:48 -0700129 float toGammaExp = 1.0f / exponent;
130
msarett3418c0e2016-07-25 18:23:18 -0700131 for (int i = 0; i < kDstGammaTableSize; i++) {
132 float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
msarettb3906762016-06-22 14:07:48 -0700133 outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp));
134 }
msarettdc27a642016-06-06 12:02:31 -0700135}
136
msarett1b93bd12016-07-21 07:11:26 -0700137static void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable,
msarettb3906762016-06-22 14:07:48 -0700138 int inTableSize) {
raftias197e3112016-12-01 15:31:29 -0500139 invert_table_gamma(nullptr, outTable, kDstGammaTableSize, inTable, inTableSize);
msarettb3906762016-06-22 14:07:48 -0700140}
141
142static float inverse_parametric(float x, float g, float a, float b, float c, float d, float e,
143 float f) {
144 // We need to take the inverse of the following piecewise function.
145 // Y = (aX + b)^g + c for X >= d
146 // Y = eX + f otherwise
147
148 // Assume that the gamma function is continuous, or this won't make much sense anyway.
149 // Plug in |d| to the first equation to calculate the new piecewise interval.
150 // Then simply use the inverse of the original functions.
Matt Sarett24107172016-12-19 14:33:35 -0500151 float interval = c * d + f;
msarettb3906762016-06-22 14:07:48 -0700152 if (x < interval) {
Matt Sarett24107172016-12-19 14:33:35 -0500153 // X = (Y - F) / C
154 if (0.0f == c) {
msarettb3906762016-06-22 14:07:48 -0700155 // The gamma curve for this segment is constant, so the inverse is undefined.
156 // Since this is the lower segment, guess zero.
157 return 0.0f;
158 }
159
Matt Sarett24107172016-12-19 14:33:35 -0500160 return (x - f) / c;
msarettb3906762016-06-22 14:07:48 -0700161 }
162
Matt Sarett24107172016-12-19 14:33:35 -0500163 // X = ((Y - E)^(1 / G) - B) / A
msarettb3906762016-06-22 14:07:48 -0700164 if (0.0f == a || 0.0f == g) {
165 // The gamma curve for this segment is constant, so the inverse is undefined.
166 // Since this is the upper segment, guess one.
167 return 1.0f;
168 }
169
Matt Sarett24107172016-12-19 14:33:35 -0500170 return (powf(x - e, 1.0f / g) - b) / a;
msarettb3906762016-06-22 14:07:48 -0700171}
172
msarett1b93bd12016-07-21 07:11:26 -0700173static void build_table_linear_to_gamma(uint8_t* outTable, float g, float a,
msarettb3906762016-06-22 14:07:48 -0700174 float b, float c, float d, float e, float f) {
msarett3418c0e2016-07-25 18:23:18 -0700175 for (int i = 0; i < kDstGammaTableSize; i++) {
176 float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
msarettb3906762016-06-22 14:07:48 -0700177 float y = inverse_parametric(x, g, a, b, c, d, e, f);
178 outTable[i] = clamp_normalized_float_to_byte(y);
179 }
180}
181
msarett6006f672016-07-11 05:49:17 -0700182///////////////////////////////////////////////////////////////////////////////////////////////////
183
msarett1b93bd12016-07-21 07:11:26 -0700184template <typename T>
185struct GammaFns {
186 const T* fSRGBTable;
187 const T* f2Dot2Table;
msarett1b93bd12016-07-21 07:11:26 -0700188 void (*fBuildFromValue)(T*, float);
189 void (*fBuildFromTable)(T*, const float*, int);
190 void (*fBuildFromParam)(T*, float, float, float, float, float, float, float);
191};
192
193static const GammaFns<float> kToLinear {
194 sk_linear_from_srgb,
195 sk_linear_from_2dot2,
196 &build_table_linear_from_gamma,
197 &build_table_linear_from_gamma,
198 &build_table_linear_from_gamma,
199};
200
201static const GammaFns<uint8_t> kFromLinear {
msarett55bcc8e2016-09-09 07:48:05 -0700202 nullptr,
203 nullptr,
msarett1b93bd12016-07-21 07:11:26 -0700204 &build_table_linear_to_gamma,
205 &build_table_linear_to_gamma,
206 &build_table_linear_to_gamma,
207};
208
209// Build tables to transform src gamma to linear.
210template <typename T>
211static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, int gammaTableSize,
raftias94888332016-10-18 10:02:51 -0700212 const SkColorSpace_XYZ* space, const GammaFns<T>& fns,
Matt Sarettf4898862016-10-16 10:20:41 -0400213 bool gammasAreMatching)
msarett4be0e7c2016-09-22 07:02:24 -0700214{
raftias94888332016-10-18 10:02:51 -0700215 switch (space->gammaNamed()) {
msarett600c7372016-09-07 12:03:53 -0700216 case kSRGB_SkGammaNamed:
msarett1b93bd12016-07-21 07:11:26 -0700217 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRGBTable;
218 break;
msarett600c7372016-09-07 12:03:53 -0700219 case k2Dot2Curve_SkGammaNamed:
msarett1b93bd12016-07-21 07:11:26 -0700220 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Dot2Table;
221 break;
msarett600c7372016-09-07 12:03:53 -0700222 case kLinear_SkGammaNamed:
msarett8bbcd5a2016-09-14 07:06:08 -0700223 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = nullptr;
msarett1b93bd12016-07-21 07:11:26 -0700224 break;
225 default: {
raftias94888332016-10-18 10:02:51 -0700226 const SkGammas* gammas = space->gammas();
msarett1b93bd12016-07-21 07:11:26 -0700227 SkASSERT(gammas);
228
msarett7bbda992016-09-14 11:02:04 -0700229 auto build_table = [=](int i) {
msarett1b93bd12016-07-21 07:11:26 -0700230 if (gammas->isNamed(i)) {
231 switch (gammas->data(i).fNamed) {
msarett600c7372016-09-07 12:03:53 -0700232 case kSRGB_SkGammaNamed:
msarett55bcc8e2016-09-09 07:48:05 -0700233 (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], 2.4f,
Matt Sarett24107172016-12-19 14:33:35 -0500234 (1.0f / 1.055f), (0.055f / 1.055f),
235 (1.0f / 12.92f), 0.04045f, 0.0f, 0.0f);
msarett55bcc8e2016-09-09 07:48:05 -0700236 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
msarett1b93bd12016-07-21 07:11:26 -0700237 break;
msarett600c7372016-09-07 12:03:53 -0700238 case k2Dot2Curve_SkGammaNamed:
msarett55bcc8e2016-09-09 07:48:05 -0700239 (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 2.2f);
240 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
msarett1b93bd12016-07-21 07:11:26 -0700241 break;
msarett600c7372016-09-07 12:03:53 -0700242 case kLinear_SkGammaNamed:
msarett1b93bd12016-07-21 07:11:26 -0700243 (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 1.0f);
244 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
245 break;
246 default:
247 SkASSERT(false);
248 break;
249 }
250 } else if (gammas->isValue(i)) {
251 (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize],
252 gammas->data(i).fValue);
253 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
254 } else if (gammas->isTable(i)) {
255 (*fns.fBuildFromTable)(&gammaTableStorage[i * gammaTableSize], gammas->table(i),
256 gammas->data(i).fTable.fSize);
257 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
258 } else {
259 SkASSERT(gammas->isParametric(i));
Matt Sarettdf44fc52016-10-11 16:57:50 -0400260 const SkColorSpaceTransferFn& params = gammas->params(i);
msarett1b93bd12016-07-21 07:11:26 -0700261 (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG,
262 params.fA, params.fB, params.fC, params.fD, params.fE,
263 params.fF);
264 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
265 }
msarett7bbda992016-09-14 11:02:04 -0700266 };
267
268 if (gammasAreMatching) {
269 build_table(0);
270 outGammaTables[1] = outGammaTables[0];
271 outGammaTables[2] = outGammaTables[0];
272 } else {
273 build_table(0);
274 build_table(1);
275 build_table(2);
msarett1b93bd12016-07-21 07:11:26 -0700276 }
msarett7bbda992016-09-14 11:02:04 -0700277
278 break;
msarett1b93bd12016-07-21 07:11:26 -0700279 }
280 }
281}
282
Matt Sarettf4898862016-10-16 10:20:41 -0400283void SkColorSpaceXform_Base::BuildDstGammaTables(const uint8_t* dstGammaTables[3],
raftias94888332016-10-18 10:02:51 -0700284 uint8_t* dstStorage,
285 const SkColorSpace_XYZ* space,
Matt Sarettf4898862016-10-16 10:20:41 -0400286 bool gammasAreMatching) {
287 build_gamma_tables(dstGammaTables, dstStorage, kDstGammaTableSize, space, kFromLinear,
288 gammasAreMatching);
289}
290
msarett1b93bd12016-07-21 07:11:26 -0700291///////////////////////////////////////////////////////////////////////////////////////////////////
292
msarett4be0e7c2016-09-22 07:02:24 -0700293std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace,
294 SkColorSpace* dstSpace) {
msarett6006f672016-07-11 05:49:17 -0700295 if (!srcSpace || !dstSpace) {
296 // Invalid input
297 return nullptr;
298 }
299
raftias94888332016-10-18 10:02:51 -0700300 if (SkColorSpace_Base::Type::kA2B == as_CSB(dstSpace)->type()) {
raftias25636012016-11-11 15:27:39 -0800301 SkCSXformPrintf("A2B destinations not supported\n");
raftias94888332016-10-18 10:02:51 -0700302 return nullptr;
303 }
304
305 if (SkColorSpace_Base::Type::kA2B == as_CSB(srcSpace)->type()) {
raftias25636012016-11-11 15:27:39 -0800306 SkColorSpace_A2B* src = static_cast<SkColorSpace_A2B*>(srcSpace);
307 SkColorSpace_XYZ* dst = static_cast<SkColorSpace_XYZ*>(dstSpace);
308 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_A2B(src, dst));
raftias94888332016-10-18 10:02:51 -0700309 }
310 SkColorSpace_XYZ* srcSpaceXYZ = static_cast<SkColorSpace_XYZ*>(srcSpace);
311 SkColorSpace_XYZ* dstSpaceXYZ = static_cast<SkColorSpace_XYZ*>(dstSpace);
312
msarett200877e2016-08-15 08:10:44 -0700313 ColorSpaceMatch csm = kNone_ColorSpaceMatch;
msarett6006f672016-07-11 05:49:17 -0700314 SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor);
msarett4be0e7c2016-09-22 07:02:24 -0700315 if (SkColorSpace::Equals(srcSpace, dstSpace)) {
msarett200877e2016-08-15 08:10:44 -0700316 srcToDst.setIdentity();
317 csm = kFull_ColorSpaceMatch;
brianosman971cd492016-09-08 10:10:11 -0700318 } else {
Brian Osmanbbf251b2016-10-19 14:56:07 -0400319 if (srcSpaceXYZ->toXYZD50Hash() == dstSpaceXYZ->toXYZD50Hash()) {
320 SkASSERT(*srcSpaceXYZ->toXYZD50() == *dstSpaceXYZ->toXYZD50() && "Hash collision");
brianosman971cd492016-09-08 10:10:11 -0700321 srcToDst.setIdentity();
322 csm = kGamut_ColorSpaceMatch;
Brian Osmanbbf251b2016-10-19 14:56:07 -0400323 } else {
324 srcToDst.setConcat(*dstSpaceXYZ->fromXYZD50(), *srcSpaceXYZ->toXYZD50());
brianosman971cd492016-09-08 10:10:11 -0700325 }
msarett6006f672016-07-11 05:49:17 -0700326 }
327
msarett200877e2016-08-15 08:10:44 -0700328 switch (csm) {
329 case kNone_ColorSpaceMatch:
Matt Sarett379938e2017-01-12 18:34:29 -0500330 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
331 <kNone_ColorSpaceMatch>(srcSpaceXYZ, srcToDst, dstSpaceXYZ));
msarett200877e2016-08-15 08:10:44 -0700332 case kGamut_ColorSpaceMatch:
Matt Sarett379938e2017-01-12 18:34:29 -0500333 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
334 <kGamut_ColorSpaceMatch>(srcSpaceXYZ, srcToDst, dstSpaceXYZ));
msarett200877e2016-08-15 08:10:44 -0700335 case kFull_ColorSpaceMatch:
Matt Sarett379938e2017-01-12 18:34:29 -0500336 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
337 <kFull_ColorSpaceMatch>(srcSpaceXYZ, srcToDst, dstSpaceXYZ));
msarett3418c0e2016-07-25 18:23:18 -0700338 default:
msarett200877e2016-08-15 08:10:44 -0700339 SkASSERT(false);
340 return nullptr;
msarett6006f672016-07-11 05:49:17 -0700341 }
msarett6006f672016-07-11 05:49:17 -0700342}
343
344///////////////////////////////////////////////////////////////////////////////////////////////////
345
Matt Sarettdf303a62016-10-24 11:38:08 -0400346#define AI SK_ALWAYS_INLINE
347
Matt Sarett26a05432017-01-04 16:54:55 -0500348static AI void load_matrix(const float matrix[13],
Matt Sarettdf303a62016-10-24 11:38:08 -0400349 Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& rTgTbT) {
Matt Sarett26a05432017-01-04 16:54:55 -0500350 rXgXbX = Sk4f::Load(matrix + 0);
351 rYgYbY = Sk4f::Load(matrix + 3);
352 rZgZbZ = Sk4f::Load(matrix + 6);
353 rTgTbT = Sk4f::Load(matrix + 9);
msarett200877e2016-08-15 08:10:44 -0700354}
355
msarettcf7b8772016-09-22 12:37:04 -0700356enum Order {
357 kRGBA_Order,
358 kBGRA_Order,
359};
360
Matt Sarettdf303a62016-10-24 11:38:08 -0400361static AI void set_rb_shifts(Order kOrder, int* kRShift, int* kBShift) {
msarettcf7b8772016-09-22 12:37:04 -0700362 if (kRGBA_Order == kOrder) {
363 *kRShift = 0;
364 *kBShift = 16;
365 } else {
366 *kRShift = 16;
367 *kBShift = 0;
368 }
369}
370
371template <Order kOrder>
Matt Sarettdf303a62016-10-24 11:38:08 -0400372static AI void load_rgb_from_tables(const uint32_t* src,
373 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
374 const float* const srcTables[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700375 int kRShift, kGShift = 8, kBShift;
376 set_rb_shifts(kOrder, &kRShift, &kBShift);
377 r = { srcTables[0][(src[0] >> kRShift) & 0xFF],
378 srcTables[0][(src[1] >> kRShift) & 0xFF],
379 srcTables[0][(src[2] >> kRShift) & 0xFF],
380 srcTables[0][(src[3] >> kRShift) & 0xFF], };
381 g = { srcTables[1][(src[0] >> kGShift) & 0xFF],
382 srcTables[1][(src[1] >> kGShift) & 0xFF],
383 srcTables[1][(src[2] >> kGShift) & 0xFF],
384 srcTables[1][(src[3] >> kGShift) & 0xFF], };
385 b = { srcTables[2][(src[0] >> kBShift) & 0xFF],
386 srcTables[2][(src[1] >> kBShift) & 0xFF],
387 srcTables[2][(src[2] >> kBShift) & 0xFF],
388 srcTables[2][(src[3] >> kBShift) & 0xFF], };
msarett200877e2016-08-15 08:10:44 -0700389 a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
390}
391
msarettcf7b8772016-09-22 12:37:04 -0700392template <Order kOrder>
Matt Sarettdf303a62016-10-24 11:38:08 -0400393static AI void load_rgba_from_tables(const uint32_t* src,
394 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
395 const float* const srcTables[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700396 int kRShift, kGShift = 8, kBShift;
397 set_rb_shifts(kOrder, &kRShift, &kBShift);
398 r = { srcTables[0][(src[0] >> kRShift) & 0xFF],
399 srcTables[0][(src[1] >> kRShift) & 0xFF],
400 srcTables[0][(src[2] >> kRShift) & 0xFF],
401 srcTables[0][(src[3] >> kRShift) & 0xFF], };
msarett5414be02016-09-22 13:23:56 -0700402 g = { srcTables[1][(src[0] >> kGShift) & 0xFF],
msarettcf7b8772016-09-22 12:37:04 -0700403 srcTables[1][(src[1] >> kGShift) & 0xFF],
404 srcTables[1][(src[2] >> kGShift) & 0xFF],
405 srcTables[1][(src[3] >> kGShift) & 0xFF], };
406 b = { srcTables[2][(src[0] >> kBShift) & 0xFF],
407 srcTables[2][(src[1] >> kBShift) & 0xFF],
408 srcTables[2][(src[2] >> kBShift) & 0xFF],
409 srcTables[2][(src[3] >> kBShift) & 0xFF], };
msarett200877e2016-08-15 08:10:44 -0700410 a = (1.0f / 255.0f) * SkNx_cast<float>(Sk4u::Load(src) >> 24);
411}
412
msarettcf7b8772016-09-22 12:37:04 -0700413template <Order kOrder>
raftias25636012016-11-11 15:27:39 -0800414static AI void load_rgb_linear(const uint32_t* src, Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
Matt Sarettdf303a62016-10-24 11:38:08 -0400415 const float* const[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700416 int kRShift, kGShift = 8, kBShift;
417 set_rb_shifts(kOrder, &kRShift, &kBShift);
418 r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kRShift) & 0xFF);
419 g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kGShift) & 0xFF);
420 b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kBShift) & 0xFF);
msarettbe362772016-09-14 11:53:49 -0700421 a = 0.0f; // Don't let the compiler complain that |a| is uninitialized.
msarett8bbcd5a2016-09-14 07:06:08 -0700422}
423
msarettcf7b8772016-09-22 12:37:04 -0700424template <Order kOrder>
raftias25636012016-11-11 15:27:39 -0800425static AI void load_rgba_linear(const uint32_t* src, Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
Matt Sarettdf303a62016-10-24 11:38:08 -0400426 const float* const[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700427 int kRShift, kGShift = 8, kBShift;
428 set_rb_shifts(kOrder, &kRShift, &kBShift);
429 r = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kRShift) & 0xFF);
430 g = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kGShift) & 0xFF);
431 b = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> kBShift) & 0xFF);
432 a = (1.0f / 255.0f) * SkNx_cast<float>((Sk4u::Load(src) >> 24));
msarett8bbcd5a2016-09-14 07:06:08 -0700433}
434
msarettcf7b8772016-09-22 12:37:04 -0700435template <Order kOrder>
Matt Sarettdf303a62016-10-24 11:38:08 -0400436static AI void load_rgb_from_tables_1(const uint32_t* src,
437 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
438 const float* const srcTables[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700439 int kRShift, kGShift = 8, kBShift;
440 set_rb_shifts(kOrder, &kRShift, &kBShift);
441 r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]);
442 g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]);
443 b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]);
Matt Saretta9f64de2016-10-21 09:25:54 -0400444 a = 0.0f; // Don't let MSAN complain that |a| is uninitialized.
msarett200877e2016-08-15 08:10:44 -0700445}
446
msarettcf7b8772016-09-22 12:37:04 -0700447template <Order kOrder>
Matt Sarettdf303a62016-10-24 11:38:08 -0400448static AI void load_rgba_from_tables_1(const uint32_t* src,
449 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
450 const float* const srcTables[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700451 int kRShift, kGShift = 8, kBShift;
452 set_rb_shifts(kOrder, &kRShift, &kBShift);
453 r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]);
454 g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]);
455 b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]);
msarett200877e2016-08-15 08:10:44 -0700456 a = (1.0f / 255.0f) * Sk4f(*src >> 24);
457}
458
msarettcf7b8772016-09-22 12:37:04 -0700459template <Order kOrder>
Matt Sarettdf303a62016-10-24 11:38:08 -0400460static AI void load_rgb_linear_1(const uint32_t* src,
461 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
462 const float* const srcTables[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700463 int kRShift, kGShift = 8, kBShift;
464 set_rb_shifts(kOrder, &kRShift, &kBShift);
465 r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF));
466 g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF));
467 b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF));
Matt Saretta9f64de2016-10-21 09:25:54 -0400468 a = 0.0f; // Don't let MSAN complain that |a| is uninitialized.
msarett8bbcd5a2016-09-14 07:06:08 -0700469}
470
msarettcf7b8772016-09-22 12:37:04 -0700471template <Order kOrder>
Matt Sarettdf303a62016-10-24 11:38:08 -0400472static AI void load_rgba_linear_1(const uint32_t* src,
473 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a,
474 const float* const srcTables[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700475 int kRShift, kGShift = 8, kBShift;
476 set_rb_shifts(kOrder, &kRShift, &kBShift);
477 r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF));
478 g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF));
479 b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF));
480 a = Sk4f((1.0f / 255.0f) * ((*src >> 24)));
msarett8bbcd5a2016-09-14 07:06:08 -0700481}
482
Matt Sarettdf303a62016-10-24 11:38:08 -0400483static AI void transform_gamut(const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a,
484 const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
485 Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) {
msarett200877e2016-08-15 08:10:44 -0700486 dr = rXgXbX[0]*r + rYgYbY[0]*g + rZgZbZ[0]*b;
487 dg = rXgXbX[1]*r + rYgYbY[1]*g + rZgZbZ[1]*b;
488 db = rXgXbX[2]*r + rYgYbY[2]*g + rZgZbZ[2]*b;
489 da = a;
490}
491
Matt Sarettdf303a62016-10-24 11:38:08 -0400492static AI void transform_gamut_1(const Sk4f& r, const Sk4f& g, const Sk4f& b,
493 const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ,
494 Sk4f& rgba) {
msarett200877e2016-08-15 08:10:44 -0700495 rgba = rXgXbX*r + rYgYbY*g + rZgZbZ*b;
496}
497
Matt Sarettdf303a62016-10-24 11:38:08 -0400498static AI void translate_gamut(const Sk4f& rTgTbT, Sk4f& dr, Sk4f& dg, Sk4f& db) {
msarett200877e2016-08-15 08:10:44 -0700499 dr = dr + rTgTbT[0];
500 dg = dg + rTgTbT[1];
501 db = db + rTgTbT[2];
502}
503
Matt Sarettdf303a62016-10-24 11:38:08 -0400504static AI void translate_gamut_1(const Sk4f& rTgTbT, Sk4f& rgba) {
msarett200877e2016-08-15 08:10:44 -0700505 rgba = rgba + rTgTbT;
506}
507
Matt Sarettabf8ba32016-12-01 17:02:07 -0500508static AI void premultiply(Sk4f& dr, Sk4f& dg, Sk4f& db, const Sk4f& da, bool kClamp) {
509 if (kClamp) {
Matt Sarett8b4b56a2016-12-04 16:08:14 -0500510 dr = Sk4f::Min(dr, 1.0f);
511 dg = Sk4f::Min(dg, 1.0f);
512 db = Sk4f::Min(db, 1.0f);
Matt Sarettabf8ba32016-12-01 17:02:07 -0500513 }
514
msarett200877e2016-08-15 08:10:44 -0700515 dr = da * dr;
516 dg = da * dg;
517 db = da * db;
518}
519
Matt Sarettabf8ba32016-12-01 17:02:07 -0500520static AI void premultiply_1(const Sk4f& a, Sk4f& rgba, bool kClamp) {
521 if (kClamp) {
Matt Sarett8b4b56a2016-12-04 16:08:14 -0500522 rgba = Sk4f::Min(rgba, 1.0f);
Matt Sarettabf8ba32016-12-01 17:02:07 -0500523 }
524
msarett200877e2016-08-15 08:10:44 -0700525 rgba = a * rgba;
526}
527
msarettcf7b8772016-09-22 12:37:04 -0700528template <Order kOrder>
raftias25636012016-11-11 15:27:39 -0800529static AI void store_srgb(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
Matt Sarettdf303a62016-10-24 11:38:08 -0400530 const uint8_t* const[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700531 int kRShift, kGShift = 8, kBShift;
532 set_rb_shifts(kOrder, &kRShift, &kBShift);
msarett200877e2016-08-15 08:10:44 -0700533 dr = sk_linear_to_srgb_needs_trunc(dr);
534 dg = sk_linear_to_srgb_needs_trunc(dg);
535 db = sk_linear_to_srgb_needs_trunc(db);
536
Matt Sarett17e49402016-12-01 20:28:35 +0000537 dr = sk_clamp_0_255(dr);
538 dg = sk_clamp_0_255(dg);
539 db = sk_clamp_0_255(db);
540
msarett200877e2016-08-15 08:10:44 -0700541 Sk4i da = Sk4i::Load(src) & 0xFF000000;
542
543 Sk4i rgba = (SkNx_cast<int>(dr) << kRShift)
544 | (SkNx_cast<int>(dg) << kGShift)
545 | (SkNx_cast<int>(db) << kBShift)
546 | (da );
547 rgba.store(dst);
548}
549
msarettcf7b8772016-09-22 12:37:04 -0700550template <Order kOrder>
Matt Sarettdf303a62016-10-24 11:38:08 -0400551static AI void store_srgb_1(void* dst, const uint32_t* src,
552 Sk4f& rgba, const Sk4f&,
553 const uint8_t* const[3]) {
Matt Sarett17e49402016-12-01 20:28:35 +0000554 rgba = sk_clamp_0_255(sk_linear_to_srgb_needs_trunc(rgba));
msarett200877e2016-08-15 08:10:44 -0700555
556 uint32_t tmp;
557 SkNx_cast<uint8_t>(SkNx_cast<int32_t>(rgba)).store(&tmp);
558 tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
msarettcf7b8772016-09-22 12:37:04 -0700559 if (kBGRA_Order == kOrder) {
msarett200877e2016-08-15 08:10:44 -0700560 tmp = SkSwizzle_RB(tmp);
561 }
562
563 *(uint32_t*)dst = tmp;
564}
565
Matt Sarettdf303a62016-10-24 11:38:08 -0400566static AI Sk4f linear_to_2dot2(const Sk4f& x) {
msarett200877e2016-08-15 08:10:44 -0700567 // x^(29/64) is a very good approximation of the true value, x^(1/2.2).
568 auto x2 = x.rsqrt(), // x^(-1/2)
569 x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(), // x^(-1/32)
570 x64 = x32.rsqrt(); // x^(+1/64)
571
572 // 29 = 32 - 2 - 1
573 return 255.0f * x2.invert() * x32 * x64.invert();
574}
575
msarettcf7b8772016-09-22 12:37:04 -0700576template <Order kOrder>
raftias25636012016-11-11 15:27:39 -0800577static AI void store_2dot2(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
Matt Sarettdf303a62016-10-24 11:38:08 -0400578 const uint8_t* const[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700579 int kRShift, kGShift = 8, kBShift;
580 set_rb_shifts(kOrder, &kRShift, &kBShift);
msarett200877e2016-08-15 08:10:44 -0700581 dr = linear_to_2dot2(dr);
582 dg = linear_to_2dot2(dg);
583 db = linear_to_2dot2(db);
584
Matt Sarett17e49402016-12-01 20:28:35 +0000585 dr = sk_clamp_0_255(dr);
586 dg = sk_clamp_0_255(dg);
587 db = sk_clamp_0_255(db);
588
msarett200877e2016-08-15 08:10:44 -0700589 Sk4i da = Sk4i::Load(src) & 0xFF000000;
590
591 Sk4i rgba = (Sk4f_round(dr) << kRShift)
592 | (Sk4f_round(dg) << kGShift)
593 | (Sk4f_round(db) << kBShift)
594 | (da );
595 rgba.store(dst);
596}
597
msarettcf7b8772016-09-22 12:37:04 -0700598template <Order kOrder>
Matt Sarettdf303a62016-10-24 11:38:08 -0400599static AI void store_2dot2_1(void* dst, const uint32_t* src,
600 Sk4f& rgba, const Sk4f&,
601 const uint8_t* const[3]) {
Matt Sarett17e49402016-12-01 20:28:35 +0000602 rgba = sk_clamp_0_255(linear_to_2dot2(rgba));
msarett200877e2016-08-15 08:10:44 -0700603
604 uint32_t tmp;
605 SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
606 tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
msarettcf7b8772016-09-22 12:37:04 -0700607 if (kBGRA_Order == kOrder) {
msarett200877e2016-08-15 08:10:44 -0700608 tmp = SkSwizzle_RB(tmp);
609 }
610
611 *(uint32_t*)dst = tmp;
612}
613
msarettcf7b8772016-09-22 12:37:04 -0700614template <Order kOrder>
raftias25636012016-11-11 15:27:39 -0800615static AI void store_linear(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
Matt Sarettdf303a62016-10-24 11:38:08 -0400616 const uint8_t* const[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700617 int kRShift, kGShift = 8, kBShift;
618 set_rb_shifts(kOrder, &kRShift, &kBShift);
Matt Sarett17e49402016-12-01 20:28:35 +0000619 dr = sk_clamp_0_255(255.0f * dr);
620 dg = sk_clamp_0_255(255.0f * dg);
621 db = sk_clamp_0_255(255.0f * db);
msarett8bbcd5a2016-09-14 07:06:08 -0700622
623 Sk4i da = Sk4i::Load(src) & 0xFF000000;
624
625 Sk4i rgba = (Sk4f_round(dr) << kRShift)
626 | (Sk4f_round(dg) << kGShift)
627 | (Sk4f_round(db) << kBShift)
628 | (da );
629 rgba.store(dst);
630}
631
msarettcf7b8772016-09-22 12:37:04 -0700632template <Order kOrder>
Matt Sarettdf303a62016-10-24 11:38:08 -0400633static AI void store_linear_1(void* dst, const uint32_t* src,
634 Sk4f& rgba, const Sk4f&,
635 const uint8_t* const[3]) {
Matt Sarett17e49402016-12-01 20:28:35 +0000636 rgba = sk_clamp_0_255(255.0f * rgba);
msarett8bbcd5a2016-09-14 07:06:08 -0700637
638 uint32_t tmp;
639 SkNx_cast<uint8_t>(Sk4f_round(rgba)).store(&tmp);
640 tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF);
msarettcf7b8772016-09-22 12:37:04 -0700641 if (kBGRA_Order == kOrder) {
msarett8bbcd5a2016-09-14 07:06:08 -0700642 tmp = SkSwizzle_RB(tmp);
643 }
644
645 *(uint32_t*)dst = tmp;
646}
647
msarettcf7b8772016-09-22 12:37:04 -0700648template <Order kOrder>
raftias25636012016-11-11 15:27:39 -0800649static AI void store_f16(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da,
650 const uint8_t* const[3]) {
Mike Klein33cbfd72016-10-06 11:09:27 -0400651 Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr),
652 SkFloatToHalf_finite_ftz(dg),
653 SkFloatToHalf_finite_ftz(db),
654 SkFloatToHalf_finite_ftz(da));
msarett200877e2016-08-15 08:10:44 -0700655}
656
msarettcf7b8772016-09-22 12:37:04 -0700657template <Order kOrder>
Matt Sarettdf303a62016-10-24 11:38:08 -0400658static AI void store_f16_1(void* dst, const uint32_t* src,
659 Sk4f& rgba, const Sk4f& a,
660 const uint8_t* const[3]) {
msarett200877e2016-08-15 08:10:44 -0700661 rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]);
mtklein8ae991e2016-08-22 13:20:18 -0700662 SkFloatToHalf_finite_ftz(rgba).store((uint64_t*) dst);
msarett200877e2016-08-15 08:10:44 -0700663}
664
msarettcf7b8772016-09-22 12:37:04 -0700665template <Order kOrder>
raftias25636012016-11-11 15:27:39 -0800666static AI void store_f16_opaque(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db,
667 Sk4f&, const uint8_t* const[3]) {
Mike Klein33cbfd72016-10-06 11:09:27 -0400668 Sk4h::Store4(dst, SkFloatToHalf_finite_ftz(dr),
669 SkFloatToHalf_finite_ftz(dg),
670 SkFloatToHalf_finite_ftz(db),
671 SK_Half1);
msarett200877e2016-08-15 08:10:44 -0700672}
673
msarettcf7b8772016-09-22 12:37:04 -0700674template <Order kOrder>
Matt Sarettdf303a62016-10-24 11:38:08 -0400675static AI void store_f16_1_opaque(void* dst, const uint32_t* src,
676 Sk4f& rgba, const Sk4f&,
677 const uint8_t* const[3]) {
msarett200877e2016-08-15 08:10:44 -0700678 uint64_t tmp;
mtklein8ae991e2016-08-22 13:20:18 -0700679 SkFloatToHalf_finite_ftz(rgba).store(&tmp);
Matt Sarette9801552017-01-09 09:14:28 -0500680 tmp &= 0x0000FFFFFFFFFFFF;
msarett200877e2016-08-15 08:10:44 -0700681 tmp |= static_cast<uint64_t>(SK_Half1) << 48;
682 *((uint64_t*) dst) = tmp;
683}
684
msarettcf7b8772016-09-22 12:37:04 -0700685template <Order kOrder>
raftias25636012016-11-11 15:27:39 -0800686static AI void store_generic(void* dst, const uint32_t* src, Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&,
687 const uint8_t* const dstTables[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700688 int kRShift, kGShift = 8, kBShift;
689 set_rb_shifts(kOrder, &kRShift, &kBShift);
Matt Sarett17e49402016-12-01 20:28:35 +0000690 dr = Sk4f::Min(Sk4f::Max(1023.0f * dr, 0.0f), 1023.0f);
691 dg = Sk4f::Min(Sk4f::Max(1023.0f * dg, 0.0f), 1023.0f);
692 db = Sk4f::Min(Sk4f::Max(1023.0f * db, 0.0f), 1023.0f);
msarett200877e2016-08-15 08:10:44 -0700693
694 Sk4i ir = Sk4f_round(dr);
695 Sk4i ig = Sk4f_round(dg);
696 Sk4i ib = Sk4f_round(db);
697
698 Sk4i da = Sk4i::Load(src) & 0xFF000000;
699
700 uint32_t* dst32 = (uint32_t*) dst;
701 dst32[0] = dstTables[0][ir[0]] << kRShift
702 | dstTables[1][ig[0]] << kGShift
703 | dstTables[2][ib[0]] << kBShift
704 | da[0];
705 dst32[1] = dstTables[0][ir[1]] << kRShift
706 | dstTables[1][ig[1]] << kGShift
707 | dstTables[2][ib[1]] << kBShift
708 | da[1];
709 dst32[2] = dstTables[0][ir[2]] << kRShift
710 | dstTables[1][ig[2]] << kGShift
711 | dstTables[2][ib[2]] << kBShift
712 | da[2];
713 dst32[3] = dstTables[0][ir[3]] << kRShift
714 | dstTables[1][ig[3]] << kGShift
715 | dstTables[2][ib[3]] << kBShift
716 | da[3];
717}
718
msarettcf7b8772016-09-22 12:37:04 -0700719template <Order kOrder>
Matt Sarettdf303a62016-10-24 11:38:08 -0400720static AI void store_generic_1(void* dst, const uint32_t* src,
721 Sk4f& rgba, const Sk4f&,
722 const uint8_t* const dstTables[3]) {
msarettcf7b8772016-09-22 12:37:04 -0700723 int kRShift, kGShift = 8, kBShift;
724 set_rb_shifts(kOrder, &kRShift, &kBShift);
Matt Sarett17e49402016-12-01 20:28:35 +0000725 rgba = Sk4f::Min(Sk4f::Max(1023.0f * rgba, 0.0f), 1023.0f);
msarett200877e2016-08-15 08:10:44 -0700726
727 Sk4i indices = Sk4f_round(rgba);
728
msarett9dc6cf62016-08-23 17:53:06 -0700729 *((uint32_t*) dst) = dstTables[0][indices[0]] << kRShift
730 | dstTables[1][indices[1]] << kGShift
731 | dstTables[2][indices[2]] << kBShift
msarett200877e2016-08-15 08:10:44 -0700732 | (*src & 0xFF000000);
733}
734
msarettcf7b8772016-09-22 12:37:04 -0700735typedef decltype(load_rgb_from_tables<kRGBA_Order> )* LoadFn;
736typedef decltype(load_rgb_from_tables_1<kRGBA_Order>)* Load1Fn;
737typedef decltype(store_generic<kRGBA_Order> )* StoreFn;
738typedef decltype(store_generic_1<kRGBA_Order> )* Store1Fn;
msarett200877e2016-08-15 08:10:44 -0700739
msarett8bbcd5a2016-09-14 07:06:08 -0700740enum SrcFormat {
741 kRGBA_8888_Linear_SrcFormat,
742 kRGBA_8888_Table_SrcFormat,
msarettcf7b8772016-09-22 12:37:04 -0700743 kBGRA_8888_Linear_SrcFormat,
744 kBGRA_8888_Table_SrcFormat,
msarett8bbcd5a2016-09-14 07:06:08 -0700745};
746
747enum DstFormat {
msarettcf7b8772016-09-22 12:37:04 -0700748 kRGBA_8888_Linear_DstFormat,
749 kRGBA_8888_SRGB_DstFormat,
750 kRGBA_8888_2Dot2_DstFormat,
751 kRGBA_8888_Table_DstFormat,
752 kBGRA_8888_Linear_DstFormat,
753 kBGRA_8888_SRGB_DstFormat,
754 kBGRA_8888_2Dot2_DstFormat,
755 kBGRA_8888_Table_DstFormat,
msarett8bbcd5a2016-09-14 07:06:08 -0700756 kF16_Linear_DstFormat,
757};
758
759template <SrcFormat kSrc,
760 DstFormat kDst,
761 SkAlphaType kAlphaType,
msarettcf7b8772016-09-22 12:37:04 -0700762 ColorSpaceMatch kCSM>
Matt Sarett59346462016-10-24 16:51:45 -0400763static void color_xform_RGBA(void* dst, const void* vsrc, int len,
Matt Sarett26a05432017-01-04 16:54:55 -0500764 const float* const srcTables[3], const float matrix[13],
Matt Sarett59346462016-10-24 16:51:45 -0400765 const uint8_t* const dstTables[3]) {
msarett8bbcd5a2016-09-14 07:06:08 -0700766 LoadFn load;
767 Load1Fn load_1;
Matt Sarettabf8ba32016-12-01 17:02:07 -0500768 const bool kLoadAlpha = (kPremul_SkAlphaType == kAlphaType) ||
Matt Sarette9801552017-01-09 09:14:28 -0500769 (kF16_Linear_DstFormat == kDst && kOpaque_SkAlphaType != kAlphaType);
msarett8bbcd5a2016-09-14 07:06:08 -0700770 switch (kSrc) {
771 case kRGBA_8888_Linear_SrcFormat:
Matt Sarettabf8ba32016-12-01 17:02:07 -0500772 if (kLoadAlpha) {
msarettcf7b8772016-09-22 12:37:04 -0700773 load = load_rgba_linear<kRGBA_Order>;
774 load_1 = load_rgba_linear_1<kRGBA_Order>;
msarett8bbcd5a2016-09-14 07:06:08 -0700775 } else {
msarettcf7b8772016-09-22 12:37:04 -0700776 load = load_rgb_linear<kRGBA_Order>;
777 load_1 = load_rgb_linear_1<kRGBA_Order>;
msarett8bbcd5a2016-09-14 07:06:08 -0700778 }
779 break;
780 case kRGBA_8888_Table_SrcFormat:
Matt Sarettabf8ba32016-12-01 17:02:07 -0500781 if (kLoadAlpha) {
msarettcf7b8772016-09-22 12:37:04 -0700782 load = load_rgba_from_tables<kRGBA_Order>;
783 load_1 = load_rgba_from_tables_1<kRGBA_Order>;
msarett8bbcd5a2016-09-14 07:06:08 -0700784 } else {
msarettcf7b8772016-09-22 12:37:04 -0700785 load = load_rgb_from_tables<kRGBA_Order>;
786 load_1 = load_rgb_from_tables_1<kRGBA_Order>;
787 }
788 break;
789 case kBGRA_8888_Linear_SrcFormat:
Matt Sarettabf8ba32016-12-01 17:02:07 -0500790 if (kLoadAlpha) {
msarettcf7b8772016-09-22 12:37:04 -0700791 load = load_rgba_linear<kBGRA_Order>;
792 load_1 = load_rgba_linear_1<kBGRA_Order>;
793 } else {
794 load = load_rgb_linear<kBGRA_Order>;
795 load_1 = load_rgb_linear_1<kBGRA_Order>;
796 }
797 break;
798 case kBGRA_8888_Table_SrcFormat:
Matt Sarettabf8ba32016-12-01 17:02:07 -0500799 if (kLoadAlpha) {
msarettcf7b8772016-09-22 12:37:04 -0700800 load = load_rgba_from_tables<kBGRA_Order>;
801 load_1 = load_rgba_from_tables_1<kBGRA_Order>;
802 } else {
803 load = load_rgb_from_tables<kBGRA_Order>;
804 load_1 = load_rgb_from_tables_1<kBGRA_Order>;
msarett8bbcd5a2016-09-14 07:06:08 -0700805 }
806 break;
807 }
808
809 StoreFn store;
810 Store1Fn store_1;
811 size_t sizeOfDstPixel;
812 switch (kDst) {
msarettcf7b8772016-09-22 12:37:04 -0700813 case kRGBA_8888_Linear_DstFormat:
814 store = store_linear<kRGBA_Order>;
815 store_1 = store_linear_1<kRGBA_Order>;
msarett8bbcd5a2016-09-14 07:06:08 -0700816 sizeOfDstPixel = 4;
817 break;
msarettcf7b8772016-09-22 12:37:04 -0700818 case kRGBA_8888_SRGB_DstFormat:
819 store = store_srgb<kRGBA_Order>;
820 store_1 = store_srgb_1<kRGBA_Order>;
msarett8bbcd5a2016-09-14 07:06:08 -0700821 sizeOfDstPixel = 4;
822 break;
msarettcf7b8772016-09-22 12:37:04 -0700823 case kRGBA_8888_2Dot2_DstFormat:
824 store = store_2dot2<kRGBA_Order>;
825 store_1 = store_2dot2_1<kRGBA_Order>;
msarett8bbcd5a2016-09-14 07:06:08 -0700826 sizeOfDstPixel = 4;
827 break;
msarettcf7b8772016-09-22 12:37:04 -0700828 case kRGBA_8888_Table_DstFormat:
829 store = store_generic<kRGBA_Order>;
830 store_1 = store_generic_1<kRGBA_Order>;
831 sizeOfDstPixel = 4;
832 break;
833 case kBGRA_8888_Linear_DstFormat:
834 store = store_linear<kBGRA_Order>;
835 store_1 = store_linear_1<kBGRA_Order>;
836 sizeOfDstPixel = 4;
837 break;
838 case kBGRA_8888_SRGB_DstFormat:
839 store = store_srgb<kBGRA_Order>;
840 store_1 = store_srgb_1<kBGRA_Order>;
841 sizeOfDstPixel = 4;
842 break;
843 case kBGRA_8888_2Dot2_DstFormat:
844 store = store_2dot2<kBGRA_Order>;
845 store_1 = store_2dot2_1<kBGRA_Order>;
846 sizeOfDstPixel = 4;
847 break;
848 case kBGRA_8888_Table_DstFormat:
849 store = store_generic<kBGRA_Order>;
850 store_1 = store_generic_1<kBGRA_Order>;
msarett8bbcd5a2016-09-14 07:06:08 -0700851 sizeOfDstPixel = 4;
852 break;
853 case kF16_Linear_DstFormat:
msarettcf7b8772016-09-22 12:37:04 -0700854 store = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_opaque<kRGBA_Order> :
855 store_f16<kRGBA_Order>;
856 store_1 = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_1_opaque<kRGBA_Order> :
857 store_f16_1<kRGBA_Order>;
msarett8bbcd5a2016-09-14 07:06:08 -0700858 sizeOfDstPixel = 8;
859 break;
860 }
861
Matt Sarettabf8ba32016-12-01 17:02:07 -0500862 // We always clamp before converting to 8888 outputs (because we have to).
863 // In these cases, we also need a clamp before the premul step to make sure
864 // R, G, B are not logically greater than A.
865 const bool kClamp = kRGBA_8888_Linear_DstFormat == kDst ||
866 kRGBA_8888_SRGB_DstFormat == kDst ||
867 kRGBA_8888_2Dot2_DstFormat == kDst ||
868 kRGBA_8888_Table_DstFormat == kDst;
869
Matt Sarettd478a992016-10-14 13:04:55 -0400870 const uint32_t* src = (const uint32_t*) vsrc;
871 Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT;
872 load_matrix(matrix, rXgXbX, rYgYbY, rZgZbZ, rTgTbT);
873
874 if (len >= 4) {
875 // Naively this would be a loop of load-transform-store, but we found it faster to
876 // move the N+1th load ahead of the Nth store. We don't bother doing this for N<4.
877 Sk4f r, g, b, a;
878 load(src, r, g, b, a, srcTables);
879 src += 4;
880 len -= 4;
881
882 Sk4f dr, dg, db, da;
883 while (len >= 4) {
884 if (kNone_ColorSpaceMatch == kCSM) {
885 transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
886 translate_gamut(rTgTbT, dr, dg, db);
887 } else {
888 dr = r;
889 dg = g;
890 db = b;
891 da = a;
892 }
893
894 if (kPremul_SkAlphaType == kAlphaType) {
Matt Sarettabf8ba32016-12-01 17:02:07 -0500895 premultiply(dr, dg, db, da, kClamp);
Matt Sarettd478a992016-10-14 13:04:55 -0400896 }
897
898 load(src, r, g, b, a, srcTables);
899
900 store(dst, src - 4, dr, dg, db, da, dstTables);
901 dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
902 src += 4;
903 len -= 4;
904 }
905
906 if (kNone_ColorSpaceMatch == kCSM) {
907 transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da);
908 translate_gamut(rTgTbT, dr, dg, db);
909 } else {
910 dr = r;
911 dg = g;
912 db = b;
913 da = a;
914 }
915
916 if (kPremul_SkAlphaType == kAlphaType) {
Matt Sarettabf8ba32016-12-01 17:02:07 -0500917 premultiply(dr, dg, db, da, kClamp);
Matt Sarettd478a992016-10-14 13:04:55 -0400918 }
919
920 store(dst, src - 4, dr, dg, db, da, dstTables);
921 dst = SkTAddOffset<void>(dst, 4 * sizeOfDstPixel);
922 }
923
924 while (len > 0) {
925 Sk4f r, g, b, a;
926 load_1(src, r, g, b, a, srcTables);
927
928 Sk4f rgba;
929 if (kNone_ColorSpaceMatch == kCSM) {
930 transform_gamut_1(r, g, b, rXgXbX, rYgYbY, rZgZbZ, rgba);
931 translate_gamut_1(rTgTbT, rgba);
932 } else {
933 rgba = Sk4f(r[0], g[0], b[0], a[0]);
934 }
935
936 if (kPremul_SkAlphaType == kAlphaType) {
Matt Sarettabf8ba32016-12-01 17:02:07 -0500937 premultiply_1(a, rgba, kClamp);
Matt Sarettd478a992016-10-14 13:04:55 -0400938 }
939
940 store_1(dst, src, rgba, a, dstTables);
941
942 src += 1;
943 len -= 1;
944 dst = SkTAddOffset<void>(dst, sizeOfDstPixel);
945 }
msarett8bbcd5a2016-09-14 07:06:08 -0700946}
947
msarett3418c0e2016-07-25 18:23:18 -0700948///////////////////////////////////////////////////////////////////////////////////////////////////
949
raftias25636012016-11-11 15:27:39 -0800950static AI int num_tables(SkColorSpace_XYZ* space) {
raftias94888332016-10-18 10:02:51 -0700951 switch (space->gammaNamed()) {
msarett7bbda992016-09-14 11:02:04 -0700952 case kSRGB_SkGammaNamed:
953 case k2Dot2Curve_SkGammaNamed:
954 case kLinear_SkGammaNamed:
955 return 0;
956 default: {
raftias94888332016-10-18 10:02:51 -0700957 const SkGammas* gammas = space->gammas();
msarett7bbda992016-09-14 11:02:04 -0700958 SkASSERT(gammas);
959
960 bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) &&
961 (gammas->data(0) == gammas->data(1)) &&
962 (gammas->type(0) == gammas->type(2)) &&
963 (gammas->data(0) == gammas->data(2));
964
965 // It's likely that each component will have the same gamma. In this case,
966 // we only need to build one table.
967 return gammasAreMatching ? 1 : 3;
968 }
969 }
970}
971
Matt Sarett379938e2017-01-12 18:34:29 -0500972template <ColorSpaceMatch kCSM>
973SkColorSpaceXform_XYZ<kCSM>
raftias94888332016-10-18 10:02:51 -0700974::SkColorSpaceXform_XYZ(SkColorSpace_XYZ* srcSpace, const SkMatrix44& srcToDst,
975 SkColorSpace_XYZ* dstSpace)
msarett3418c0e2016-07-25 18:23:18 -0700976{
Matt Sarett26a05432017-01-04 16:54:55 -0500977 fSrcToDst[ 0] = srcToDst.get(0, 0);
978 fSrcToDst[ 1] = srcToDst.get(1, 0);
979 fSrcToDst[ 2] = srcToDst.get(2, 0);
980 fSrcToDst[ 3] = srcToDst.get(0, 1);
981 fSrcToDst[ 4] = srcToDst.get(1, 1);
982 fSrcToDst[ 5] = srcToDst.get(2, 1);
983 fSrcToDst[ 6] = srcToDst.get(0, 2);
984 fSrcToDst[ 7] = srcToDst.get(1, 2);
985 fSrcToDst[ 8] = srcToDst.get(2, 2);
986 fSrcToDst[ 9] = srcToDst.get(0, 3);
987 fSrcToDst[10] = srcToDst.get(1, 3);
988 fSrcToDst[11] = srcToDst.get(2, 3);
989 fSrcToDst[12] = 0.0f;
msarett7bbda992016-09-14 11:02:04 -0700990
msarett4be0e7c2016-09-22 07:02:24 -0700991 const int numSrcTables = num_tables(srcSpace);
Matt Sarettf4898862016-10-16 10:20:41 -0400992 const size_t srcEntries = numSrcTables * 256;
msarett7bbda992016-09-14 11:02:04 -0700993 const bool srcGammasAreMatching = (1 >= numSrcTables);
Matt Sarettf4898862016-10-16 10:20:41 -0400994 fSrcStorage.reset(srcEntries);
995 build_gamma_tables(fSrcGammaTables, fSrcStorage.get(), 256, srcSpace, kToLinear,
996 srcGammasAreMatching);
997
998 const int numDstTables = num_tables(dstSpace);
raftias94888332016-10-18 10:02:51 -0700999 dstSpace->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTables);
Matt Sarett379938e2017-01-12 18:34:29 -05001000
1001 if (srcSpace->gammaIsLinear()) {
1002 fSrcGamma = kLinear_SrcGamma;
1003 } else if (kSRGB_SkGammaNamed == srcSpace->gammaNamed()) {
1004 fSrcGamma = kSRGB_SrcGamma;
1005 } else {
1006 fSrcGamma = kTable_SrcGamma;
1007 }
1008
1009 switch (dstSpace->gammaNamed()) {
1010 case kSRGB_SkGammaNamed:
1011 fDstGamma = kSRGB_DstGamma;
1012 break;
1013 case k2Dot2Curve_SkGammaNamed:
1014 fDstGamma = k2Dot2_DstGamma;
1015 break;
1016 case kLinear_SkGammaNamed:
1017 fDstGamma = kLinear_DstGamma;
1018 break;
1019 default:
1020 fDstGamma = kTable_DstGamma;
1021 break;
1022 }
msarett3418c0e2016-07-25 18:23:18 -07001023}
1024
msarett7bbda992016-09-14 11:02:04 -07001025///////////////////////////////////////////////////////////////////////////////////////////////////
1026
msarettcf7b8772016-09-22 12:37:04 -07001027template <SrcFormat kSrc, DstFormat kDst, ColorSpaceMatch kCSM>
Matt Sarettdf303a62016-10-24 11:38:08 -04001028static AI bool apply_set_alpha(void* dst, const void* src, int len, SkAlphaType alphaType,
Matt Sarett26a05432017-01-04 16:54:55 -05001029 const float* const srcTables[3], const float matrix[13],
Matt Sarettdf303a62016-10-24 11:38:08 -04001030 const uint8_t* const dstTables[3]) {
msarett8bbcd5a2016-09-14 07:06:08 -07001031 switch (alphaType) {
1032 case kOpaque_SkAlphaType:
msarett31d097e82016-10-11 12:15:03 -07001033 color_xform_RGBA<kSrc, kDst, kOpaque_SkAlphaType, kCSM>
msarett8bbcd5a2016-09-14 07:06:08 -07001034 (dst, src, len, srcTables, matrix, dstTables);
msarett31d097e82016-10-11 12:15:03 -07001035 return true;
msarett8bbcd5a2016-09-14 07:06:08 -07001036 case kPremul_SkAlphaType:
msarett31d097e82016-10-11 12:15:03 -07001037 color_xform_RGBA<kSrc, kDst, kPremul_SkAlphaType, kCSM>
msarett8bbcd5a2016-09-14 07:06:08 -07001038 (dst, src, len, srcTables, matrix, dstTables);
msarett31d097e82016-10-11 12:15:03 -07001039 return true;
msarett8bbcd5a2016-09-14 07:06:08 -07001040 case kUnpremul_SkAlphaType:
msarett31d097e82016-10-11 12:15:03 -07001041 color_xform_RGBA<kSrc, kDst, kUnpremul_SkAlphaType, kCSM>
msarett8bbcd5a2016-09-14 07:06:08 -07001042 (dst, src, len, srcTables, matrix, dstTables);
msarett31d097e82016-10-11 12:15:03 -07001043 return true;
msarett8bbcd5a2016-09-14 07:06:08 -07001044 default:
msarett31d097e82016-10-11 12:15:03 -07001045 return false;
msarett8bbcd5a2016-09-14 07:06:08 -07001046 }
1047}
1048
Matt Sarett379938e2017-01-12 18:34:29 -05001049template <DstFormat kDst, ColorSpaceMatch kCSM>
Matt Sarettdf303a62016-10-24 11:38:08 -04001050static AI bool apply_set_src(void* dst, const void* src, int len, SkAlphaType alphaType,
Matt Sarett26a05432017-01-04 16:54:55 -05001051 const float* const srcTables[3], const float matrix[13],
Matt Sarettdf303a62016-10-24 11:38:08 -04001052 const uint8_t* const dstTables[3],
Matt Sarett379938e2017-01-12 18:34:29 -05001053 SkColorSpaceXform::ColorFormat srcColorFormat,
1054 SrcGamma srcGamma) {
msarettcf7b8772016-09-22 12:37:04 -07001055 switch (srcColorFormat) {
1056 case SkColorSpaceXform::kRGBA_8888_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -05001057 switch (srcGamma) {
msarettcf7b8772016-09-22 12:37:04 -07001058 case kLinear_SrcGamma:
1059 return apply_set_alpha<kRGBA_8888_Linear_SrcFormat, kDst, kCSM>
1060 (dst, src, len, alphaType, nullptr, matrix, dstTables);
Matt Sarett379938e2017-01-12 18:34:29 -05001061 default:
msarettcf7b8772016-09-22 12:37:04 -07001062 return apply_set_alpha<kRGBA_8888_Table_SrcFormat, kDst, kCSM>
1063 (dst, src, len, alphaType, srcTables, matrix, dstTables);
1064 }
1065 case SkColorSpaceXform::kBGRA_8888_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -05001066 switch (srcGamma) {
msarettcf7b8772016-09-22 12:37:04 -07001067 case kLinear_SrcGamma:
1068 return apply_set_alpha<kBGRA_8888_Linear_SrcFormat, kDst, kCSM>
1069 (dst, src, len, alphaType, nullptr, matrix, dstTables);
Matt Sarett379938e2017-01-12 18:34:29 -05001070 default:
msarettcf7b8772016-09-22 12:37:04 -07001071 return apply_set_alpha<kBGRA_8888_Table_SrcFormat, kDst, kCSM>
1072 (dst, src, len, alphaType, srcTables, matrix, dstTables);
1073 }
1074 default:
msarett31d097e82016-10-11 12:15:03 -07001075 return false;
msarett8bbcd5a2016-09-14 07:06:08 -07001076 }
1077}
1078
Matt Sarettdf303a62016-10-24 11:38:08 -04001079#undef AI
1080
Matt Sarett379938e2017-01-12 18:34:29 -05001081template <ColorSpaceMatch kCSM>
1082bool SkColorSpaceXform_XYZ<kCSM>
msarett31d097e82016-10-11 12:15:03 -07001083::onApply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat, const void* src,
1084 int len, SkAlphaType alphaType) const
msarett3418c0e2016-07-25 18:23:18 -07001085{
msarett200877e2016-08-15 08:10:44 -07001086 if (kFull_ColorSpaceMatch == kCSM) {
Matt Sarettabf8ba32016-12-01 17:02:07 -05001087 if (kPremul_SkAlphaType != alphaType) {
1088 if ((kRGBA_8888_ColorFormat == dstColorFormat &&
1089 kRGBA_8888_ColorFormat == srcColorFormat) ||
1090 (kBGRA_8888_ColorFormat == dstColorFormat &&
1091 kBGRA_8888_ColorFormat == srcColorFormat))
1092 {
1093 memcpy(dst, src, len * sizeof(uint32_t));
1094 return true;
1095 }
1096 if ((kRGBA_8888_ColorFormat == dstColorFormat &&
1097 kBGRA_8888_ColorFormat == srcColorFormat) ||
1098 (kBGRA_8888_ColorFormat == dstColorFormat &&
1099 kRGBA_8888_ColorFormat == srcColorFormat))
1100 {
1101 SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len);
1102 return true;
1103 }
msarett200877e2016-08-15 08:10:44 -07001104 }
1105 }
1106
Matt Sarett7a090c42017-01-17 12:22:48 -05001107 if (kRGBA_F32_ColorFormat == dstColorFormat ||
1108 kRGBA_U16_BE_ColorFormat == srcColorFormat ||
1109 kRGB_U16_BE_ColorFormat == srcColorFormat)
1110 {
Matt Sarett26a05432017-01-04 16:54:55 -05001111 return this->applyPipeline(dstColorFormat, dst, srcColorFormat, src, len, alphaType);
1112 }
1113
msarettc0444612016-09-16 11:45:58 -07001114 switch (dstColorFormat) {
1115 case kRGBA_8888_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -05001116 switch (fDstGamma) {
msarett8bbcd5a2016-09-14 07:06:08 -07001117 case kLinear_DstGamma:
Matt Sarett379938e2017-01-12 18:34:29 -05001118 return apply_set_src<kRGBA_8888_Linear_DstFormat, kCSM>
msarettcf7b8772016-09-22 12:37:04 -07001119 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
Matt Sarett379938e2017-01-12 18:34:29 -05001120 srcColorFormat, fSrcGamma);
msarett8bbcd5a2016-09-14 07:06:08 -07001121 case kSRGB_DstGamma:
Matt Sarett379938e2017-01-12 18:34:29 -05001122 return apply_set_src<kRGBA_8888_SRGB_DstFormat, kCSM>
msarettcf7b8772016-09-22 12:37:04 -07001123 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
Matt Sarett379938e2017-01-12 18:34:29 -05001124 srcColorFormat, fSrcGamma);
msarett8bbcd5a2016-09-14 07:06:08 -07001125 case k2Dot2_DstGamma:
Matt Sarett379938e2017-01-12 18:34:29 -05001126 return apply_set_src<kRGBA_8888_2Dot2_DstFormat, kCSM>
msarettcf7b8772016-09-22 12:37:04 -07001127 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
Matt Sarett379938e2017-01-12 18:34:29 -05001128 srcColorFormat, fSrcGamma);
msarett8bbcd5a2016-09-14 07:06:08 -07001129 case kTable_DstGamma:
Matt Sarett379938e2017-01-12 18:34:29 -05001130 return apply_set_src<kRGBA_8888_Table_DstFormat, kCSM>
msarettcf7b8772016-09-22 12:37:04 -07001131 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables,
Matt Sarett379938e2017-01-12 18:34:29 -05001132 srcColorFormat, fSrcGamma);
msarettd1ec89b2016-08-03 12:59:27 -07001133 }
msarettc0444612016-09-16 11:45:58 -07001134 case kBGRA_8888_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -05001135 switch (fDstGamma) {
msarett8bbcd5a2016-09-14 07:06:08 -07001136 case kLinear_DstGamma:
Matt Sarett379938e2017-01-12 18:34:29 -05001137 return apply_set_src<kBGRA_8888_Linear_DstFormat, kCSM>
msarettcf7b8772016-09-22 12:37:04 -07001138 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
Matt Sarett379938e2017-01-12 18:34:29 -05001139 srcColorFormat, fSrcGamma);
msarett8bbcd5a2016-09-14 07:06:08 -07001140 case kSRGB_DstGamma:
Matt Sarett379938e2017-01-12 18:34:29 -05001141 return apply_set_src<kBGRA_8888_SRGB_DstFormat, kCSM>
msarettcf7b8772016-09-22 12:37:04 -07001142 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
Matt Sarett379938e2017-01-12 18:34:29 -05001143 srcColorFormat, fSrcGamma);
msarett8bbcd5a2016-09-14 07:06:08 -07001144 case k2Dot2_DstGamma:
Matt Sarett379938e2017-01-12 18:34:29 -05001145 return apply_set_src<kBGRA_8888_2Dot2_DstFormat, kCSM>
msarettcf7b8772016-09-22 12:37:04 -07001146 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
Matt Sarett379938e2017-01-12 18:34:29 -05001147 srcColorFormat, fSrcGamma);
msarett8bbcd5a2016-09-14 07:06:08 -07001148 case kTable_DstGamma:
Matt Sarett379938e2017-01-12 18:34:29 -05001149 return apply_set_src<kBGRA_8888_Table_DstFormat, kCSM>
msarettcf7b8772016-09-22 12:37:04 -07001150 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables,
Matt Sarett379938e2017-01-12 18:34:29 -05001151 srcColorFormat, fSrcGamma);
msarettd1ec89b2016-08-03 12:59:27 -07001152 }
msarettc0444612016-09-16 11:45:58 -07001153 case kRGBA_F16_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -05001154 switch (fDstGamma) {
msarett8bbcd5a2016-09-14 07:06:08 -07001155 case kLinear_DstGamma:
Matt Sarett379938e2017-01-12 18:34:29 -05001156 return apply_set_src<kF16_Linear_DstFormat, kCSM>
msarettcf7b8772016-09-22 12:37:04 -07001157 (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr,
Matt Sarett379938e2017-01-12 18:34:29 -05001158 srcColorFormat, fSrcGamma);
msarettd1ec89b2016-08-03 12:59:27 -07001159 default:
msarett31d097e82016-10-11 12:15:03 -07001160 return false;
msarettd1ec89b2016-08-03 12:59:27 -07001161 }
1162 default:
Matt Sarett26a05432017-01-04 16:54:55 -05001163 SkASSERT(false);
msarett31d097e82016-10-11 12:15:03 -07001164 return false;
msarettd1ec89b2016-08-03 12:59:27 -07001165 }
msarett9ce3a542016-07-15 13:54:38 -07001166}
msarett9dc6cf62016-08-23 17:53:06 -07001167
Matt Sarettf4898862016-10-16 10:20:41 -04001168bool SkColorSpaceXform::apply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat,
1169 const void* src, int len, SkAlphaType alphaType) const {
1170 return ((SkColorSpaceXform_Base*) this)->onApply(dstColorFormat, dst, srcColorFormat, src, len,
1171 alphaType);
1172}
1173
msarett7bbda992016-09-14 11:02:04 -07001174///////////////////////////////////////////////////////////////////////////////////////////////////
1175
Matt Sarett379938e2017-01-12 18:34:29 -05001176template <ColorSpaceMatch kCSM>
1177bool SkColorSpaceXform_XYZ<kCSM>
Matt Sarett26a05432017-01-04 16:54:55 -05001178::applyPipeline(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat,
1179 const void* src, int len, SkAlphaType alphaType) const {
Matt Sarettf6878ba2016-12-01 14:46:12 -05001180 SkRasterPipeline pipeline;
1181
1182 LoadTablesContext loadTables;
Matt Sarett26a05432017-01-04 16:54:55 -05001183 switch (srcColorFormat) {
1184 case kRGBA_8888_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -05001185 if (kLinear_SrcGamma == fSrcGamma) {
Matt Sarett26a05432017-01-04 16:54:55 -05001186 pipeline.append(SkRasterPipeline::load_8888, &src);
1187 } else {
Matt Sarett379938e2017-01-12 18:34:29 -05001188 loadTables.fSrc = src;
Matt Sarett26a05432017-01-04 16:54:55 -05001189 loadTables.fR = fSrcGammaTables[0];
1190 loadTables.fG = fSrcGammaTables[1];
1191 loadTables.fB = fSrcGammaTables[2];
1192 pipeline.append(SkRasterPipeline::load_tables, &loadTables);
1193 }
1194
1195 break;
1196 case kBGRA_8888_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -05001197 if (kLinear_SrcGamma == fSrcGamma) {
Matt Sarett26a05432017-01-04 16:54:55 -05001198 pipeline.append(SkRasterPipeline::load_8888, &src);
1199 } else {
Matt Sarett379938e2017-01-12 18:34:29 -05001200 loadTables.fSrc = src;
Matt Sarett26a05432017-01-04 16:54:55 -05001201 loadTables.fR = fSrcGammaTables[2];
1202 loadTables.fG = fSrcGammaTables[1];
1203 loadTables.fB = fSrcGammaTables[0];
1204 pipeline.append(SkRasterPipeline::load_tables, &loadTables);
1205 }
1206
Matt Sarettf6878ba2016-12-01 14:46:12 -05001207 pipeline.append(SkRasterPipeline::swap_rb);
Matt Sarett26a05432017-01-04 16:54:55 -05001208 break;
Matt Sarett379938e2017-01-12 18:34:29 -05001209 case kRGBA_U16_BE_ColorFormat:
1210 switch (fSrcGamma) {
1211 case kLinear_SrcGamma:
1212 pipeline.append(SkRasterPipeline::load_u16_be, &src);
1213 break;
1214 case kSRGB_SrcGamma:
1215 pipeline.append(SkRasterPipeline::load_u16_be, &src);
1216 pipeline.append_from_srgb(kUnpremul_SkAlphaType);
1217 break;
1218 case kTable_SrcGamma:
1219 loadTables.fSrc = src;
1220 loadTables.fR = fSrcGammaTables[0];
1221 loadTables.fG = fSrcGammaTables[1];
1222 loadTables.fB = fSrcGammaTables[2];
1223 pipeline.append(SkRasterPipeline::load_tables_u16_be, &loadTables);
1224 break;
1225 }
1226 break;
Matt Sarett7a090c42017-01-17 12:22:48 -05001227 case kRGB_U16_BE_ColorFormat:
1228 switch (fSrcGamma) {
1229 case kLinear_SrcGamma:
1230 pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src);
1231 break;
1232 case kSRGB_SrcGamma:
1233 pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src);
1234 pipeline.append_from_srgb(kUnpremul_SkAlphaType);
1235 break;
1236 case kTable_SrcGamma:
1237 loadTables.fSrc = src;
1238 loadTables.fR = fSrcGammaTables[0];
1239 loadTables.fG = fSrcGammaTables[1];
1240 loadTables.fB = fSrcGammaTables[2];
1241 pipeline.append(SkRasterPipeline::load_tables_rgb_u16_be, &loadTables);
1242 break;
1243 }
1244 break;
Matt Sarett26a05432017-01-04 16:54:55 -05001245 default:
1246 return false;
Matt Sarettf6878ba2016-12-01 14:46:12 -05001247 }
1248
Matt Sarett26a05432017-01-04 16:54:55 -05001249 if (kNone_ColorSpaceMatch == kCSM) {
Matt Sarettf6878ba2016-12-01 14:46:12 -05001250 pipeline.append(SkRasterPipeline::matrix_3x4, fSrcToDst);
Matt Sarettf6878ba2016-12-01 14:46:12 -05001251
Mike Klein5e159612016-12-01 16:39:21 -05001252 if (kRGBA_8888_ColorFormat == dstColorFormat || kBGRA_8888_ColorFormat == dstColorFormat) {
1253 bool need_clamp_0, need_clamp_1;
1254 analyze_3x4_matrix(fSrcToDst, &need_clamp_0, &need_clamp_1);
1255
1256 if (need_clamp_0) { pipeline.append(SkRasterPipeline::clamp_0); }
1257 if (need_clamp_1) { pipeline.append(SkRasterPipeline::clamp_1); }
1258 }
Matt Sarettf6878ba2016-12-01 14:46:12 -05001259 }
1260
1261 if (kPremul_SkAlphaType == alphaType) {
1262 pipeline.append(SkRasterPipeline::premul);
1263 }
1264
1265 StoreTablesContext storeTables;
Matt Sarett379938e2017-01-12 18:34:29 -05001266 switch (fDstGamma) {
Matt Sarettf6878ba2016-12-01 14:46:12 -05001267 case kSRGB_DstGamma:
1268 pipeline.append(SkRasterPipeline::to_srgb);
1269 break;
1270 case k2Dot2_DstGamma:
1271 pipeline.append(SkRasterPipeline::to_2dot2);
1272 break;
1273 default:
1274 break;
1275 }
1276
1277 switch (dstColorFormat) {
1278 case kRGBA_8888_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -05001279 if (kTable_DstGamma == fDstGamma) {
Matt Sarettf6878ba2016-12-01 14:46:12 -05001280 storeTables.fDst = (uint32_t*) dst;
1281 storeTables.fR = fDstGammaTables[0];
1282 storeTables.fG = fDstGammaTables[1];
1283 storeTables.fB = fDstGammaTables[2];
1284 storeTables.fCount = SkColorSpaceXform_Base::kDstGammaTableSize;
1285 pipeline.append(SkRasterPipeline::store_tables, &storeTables);
1286 } else {
1287 pipeline.append(SkRasterPipeline::store_8888, &dst);
1288 }
1289 break;
1290 case kBGRA_8888_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -05001291 if (kTable_DstGamma == fDstGamma) {
Matt Sarettf6878ba2016-12-01 14:46:12 -05001292 storeTables.fDst = (uint32_t*) dst;
1293 storeTables.fR = fDstGammaTables[2];
1294 storeTables.fG = fDstGammaTables[1];
1295 storeTables.fB = fDstGammaTables[0];
1296 storeTables.fCount = SkColorSpaceXform_Base::kDstGammaTableSize;
1297 pipeline.append(SkRasterPipeline::swap_rb);
1298 pipeline.append(SkRasterPipeline::store_tables, &storeTables);
1299 } else {
1300 pipeline.append(SkRasterPipeline::swap_rb);
1301 pipeline.append(SkRasterPipeline::store_8888, &dst);
1302 }
1303 break;
1304 case kRGBA_F16_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -05001305 if (kLinear_DstGamma != fDstGamma) {
Matt Sarettf6878ba2016-12-01 14:46:12 -05001306 return false;
1307 }
1308 pipeline.append(SkRasterPipeline::store_f16, &dst);
1309 break;
1310 case kRGBA_F32_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -05001311 if (kLinear_DstGamma != fDstGamma) {
Matt Sarettf6878ba2016-12-01 14:46:12 -05001312 return false;
1313 }
1314 pipeline.append(SkRasterPipeline::store_f32, &dst);
1315 break;
Matt Sarett379938e2017-01-12 18:34:29 -05001316 default:
1317 return false;
Matt Sarettf6878ba2016-12-01 14:46:12 -05001318 }
1319
1320 pipeline.run(0, 0, len);
1321 return true;
1322}
1323
1324///////////////////////////////////////////////////////////////////////////////////////////////////
1325
raftias94888332016-10-18 10:02:51 -07001326std::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space) {
Matt Sarett26a05432017-01-04 16:54:55 -05001327 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
Matt Sarett379938e2017-01-12 18:34:29 -05001328 <kNone_ColorSpaceMatch>(space, SkMatrix::I(), space));
msarett9dc6cf62016-08-23 17:53:06 -07001329}