blob: b936aec489ac06ce40e89ee91cd4477c6eaac9d7 [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
Cary Clarka4083c92017-09-15 11:59:23 -04008#include "SkColorData.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"
Mike Klein45c16fa2017-07-18 18:15:13 -040021#include "../jumper/SkJumper.h"
msarett9876ac52016-06-01 14:47:18 -070022
msarett6006f672016-07-11 05:49:17 -070023static constexpr float sk_linear_from_2dot2[256] = {
msarettb3906762016-06-22 14:07:48 -070024 0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.000056921765712193f,
25 0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.000367136269815943f,
26 0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.000992374304074325f,
27 0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.001963416213396470f,
28 0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.003302703032003640f,
29 0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.005028203456855540f,
30 0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.007155037004573030f,
31 0.007751027397660610f, 0.008373117745148580f, 0.009021491898012130f, 0.009696328701658230f,
32 0.010397802292555300f, 0.011126082368383200f, 0.011881334434813700f, 0.012663720031582100f,
33 0.013473396940142600f, 0.014310519374884100f, 0.015175238159625200f, 0.016067700890886900f,
34 0.016988052089250000f, 0.017936433339950200f, 0.018912983423721500f, 0.019917838438785700f,
35 0.020951131914781100f, 0.022012994919336500f, 0.023103556157921400f, 0.024222942067534200f,
36 0.025371276904734600f, 0.026548682828472900f, 0.027755279978126000f, 0.028991186547107800f,
37 0.030256518852388700f, 0.031551391400226400f, 0.032875916948383800f, 0.034230206565082000f,
38 0.035614369684918800f, 0.037028514161960200f, 0.038472746320194600f, 0.039947171001525600f,
39 0.041451891611462500f, 0.042987010162657100f, 0.044552627316421400f, 0.046148842422351000f,
40 0.047775753556170600f, 0.049433457555908000f, 0.051122050056493400f, 0.052841625522879000f,
41 0.054592277281760300f, 0.056374097551979800f, 0.058187177473685400f, 0.060031607136313200f,
42 0.061907475605455800f, 0.063814870948677200f, 0.065753880260330100f, 0.067724589685424300f,
43 0.069727084442598800f, 0.071761448846239100f, 0.073827766327784600f, 0.075926119456264800f,
44 0.078056589958101900f, 0.080219258736215100f, 0.082414205888459200f, 0.084641510725429500f,
45 0.086901251787660300f, 0.089193506862247800f, 0.091518352998919500f, 0.093875866525577800f,
46 0.096266123063339700f, 0.098689197541094500f, 0.101145164209600000f, 0.103634096655137000f,
47 0.106156067812744000f, 0.108711149979039000f, 0.111299414824660000f, 0.113920933406333000f,
48 0.116575776178572000f, 0.119264013005047000f, 0.121985713169619000f, 0.124740945387051000f,
49 0.127529777813422000f, 0.130352278056244000f, 0.133208513184300000f, 0.136098549737202000f,
50 0.139022453734703000f, 0.141980290685736000f, 0.144972125597231000f, 0.147998022982685000f,
51 0.151058046870511000f, 0.154152260812165000f, 0.157280727890073000f, 0.160443510725344000f,
52 0.163640671485290000f, 0.166872271890766000f, 0.170138373223312000f, 0.173439036332135000f,
53 0.176774321640903000f, 0.180144289154390000f, 0.183548998464951000f, 0.186988508758844000f,
54 0.190462878822409000f, 0.193972167048093000f, 0.197516431440340000f, 0.201095729621346000f,
55 0.204710118836677000f, 0.208359655960767000f, 0.212044397502288000f, 0.215764399609395000f,
56 0.219519718074868000f, 0.223310408341127000f, 0.227136525505149000f, 0.230998124323267000f,
57 0.234895259215880000f, 0.238827984272048000f, 0.242796353254002000f, 0.246800419601550000f,
58 0.250840236436400000f, 0.254915856566385000f, 0.259027332489606000f, 0.263174716398492000f,
59 0.267358060183772000f, 0.271577415438375000f, 0.275832833461245000f, 0.280124365261085000f,
60 0.284452061560024000f, 0.288815972797219000f, 0.293216149132375000f, 0.297652640449211000f,
61 0.302125496358853000f, 0.306634766203158000f, 0.311180499057984000f, 0.315762743736397000f,
62 0.320381548791810000f, 0.325036962521076000f, 0.329729032967515000f, 0.334457807923889000f,
63 0.339223334935327000f, 0.344025661302187000f, 0.348864834082879000f, 0.353740900096629000f,
64 0.358653905926199000f, 0.363603897920553000f, 0.368590922197487000f, 0.373615024646202000f,
65 0.378676250929840000f, 0.383774646487975000f, 0.388910256539059000f, 0.394083126082829000f,
66 0.399293299902674000f, 0.404540822567962000f, 0.409825738436323000f, 0.415148091655907000f,
67 0.420507926167587000f, 0.425905285707146000f, 0.431340213807410000f, 0.436812753800359000f,
68 0.442322948819202000f, 0.447870841800410000f, 0.453456475485731000f, 0.459079892424160000f,
69 0.464741134973889000f, 0.470440245304218000f, 0.476177265397440000f, 0.481952237050698000f,
70 0.487765201877811000f, 0.493616201311074000f, 0.499505276603030000f, 0.505432468828216000f,
71 0.511397818884880000f, 0.517401367496673000f, 0.523443155214325000f, 0.529523222417277000f,
72 0.535641609315311000f, 0.541798355950137000f, 0.547993502196972000f, 0.554227087766085000f,
73 0.560499152204328000f, 0.566809734896638000f, 0.573158875067523000f, 0.579546611782525000f,
74 0.585972983949661000f, 0.592438030320847000f, 0.598941789493296000f, 0.605484299910907000f,
75 0.612065599865624000f, 0.618685727498780000f, 0.625344720802427000f, 0.632042617620641000f,
76 0.638779455650817000f, 0.645555272444935000f, 0.652370105410821000f, 0.659223991813387000f,
77 0.666116968775851000f, 0.673049073280942000f, 0.680020342172095000f, 0.687030812154625000f,
78 0.694080519796882000f, 0.701169501531402000f, 0.708297793656032000f, 0.715465432335048000f,
79 0.722672453600255000f, 0.729918893352071000f, 0.737204787360605000f, 0.744530171266715000f,
80 0.751895080583051000f, 0.759299550695091000f, 0.766743616862161000f, 0.774227314218442000f,
81 0.781750677773962000f, 0.789313742415586000f, 0.796916542907978000f, 0.804559113894567000f,
82 0.812241489898490000f, 0.819963705323528000f, 0.827725794455034000f, 0.835527791460841000f,
83 0.843369730392169000f, 0.851251645184515000f, 0.859173569658532000f, 0.867135537520905000f,
84 0.875137582365205000f, 0.883179737672745000f, 0.891262036813419000f, 0.899384513046529000f,
85 0.907547199521614000f, 0.915750129279253000f, 0.923993335251873000f, 0.932276850264543000f,
86 0.940600707035753000f, 0.948964938178195000f, 0.957369576199527000f, 0.965814653503130000f,
87 0.974300202388861000f, 0.982826255053791000f, 0.991392843592940000f, 1.000000000000000000f,
88};
89
msarett6006f672016-07-11 05:49:17 -070090///////////////////////////////////////////////////////////////////////////////////////////////////
91
msarett15ee3de2016-08-02 11:30:30 -070092static void build_table_linear_from_gamma(float* outTable, float exponent) {
93 for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
94 *outTable++ = powf(x, exponent);
95 }
96}
97
msarett15ee3de2016-08-02 11:30:30 -070098// outTable is always 256 entries, inTable may be larger or smaller.
99static void build_table_linear_from_gamma(float* outTable, const float* inTable,
100 int inTableSize) {
101 if (256 == inTableSize) {
102 memcpy(outTable, inTable, sizeof(float) * 256);
103 return;
104 }
105
106 for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
107 *outTable++ = interp_lut(x, inTable, inTableSize);
108 }
109}
110
Matt Sarettaa34f7e2016-11-09 18:14:47 -0500111
msarett15ee3de2016-08-02 11:30:30 -0700112static void build_table_linear_from_gamma(float* outTable, float g, float a, float b, float c,
113 float d, float e, float f) {
Matt Sarett24107172016-12-19 14:33:35 -0500114 // Y = (aX + b)^g + e for X >= d
115 // Y = cX + f otherwise
msarett15ee3de2016-08-02 11:30:30 -0700116 for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) {
117 if (x >= d) {
Matt Sarett24107172016-12-19 14:33:35 -0500118 *outTable++ = clamp_0_1(powf(a * x + b, g) + e);
msarett15ee3de2016-08-02 11:30:30 -0700119 } else {
Matt Sarett24107172016-12-19 14:33:35 -0500120 *outTable++ = clamp_0_1(c * x + f);
msarett15ee3de2016-08-02 11:30:30 -0700121 }
122 }
123}
124
125///////////////////////////////////////////////////////////////////////////////////////////////////
126
Matt Sarettf4898862016-10-16 10:20:41 -0400127static const int kDstGammaTableSize = SkColorSpaceXform_Base::kDstGammaTableSize;
msarett3418c0e2016-07-25 18:23:18 -0700128
msarett1b93bd12016-07-21 07:11:26 -0700129static void build_table_linear_to_gamma(uint8_t* outTable, float exponent) {
msarettb3906762016-06-22 14:07:48 -0700130 float toGammaExp = 1.0f / exponent;
131
msarett3418c0e2016-07-25 18:23:18 -0700132 for (int i = 0; i < kDstGammaTableSize; i++) {
133 float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
msarettb3906762016-06-22 14:07:48 -0700134 outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp));
135 }
msarettdc27a642016-06-06 12:02:31 -0700136}
137
msarett1b93bd12016-07-21 07:11:26 -0700138static void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable,
msarettb3906762016-06-22 14:07:48 -0700139 int inTableSize) {
raftias197e3112016-12-01 15:31:29 -0500140 invert_table_gamma(nullptr, outTable, kDstGammaTableSize, inTable, inTableSize);
msarettb3906762016-06-22 14:07:48 -0700141}
142
143static float inverse_parametric(float x, float g, float a, float b, float c, float d, float e,
144 float f) {
145 // We need to take the inverse of the following piecewise function.
146 // Y = (aX + b)^g + c for X >= d
147 // Y = eX + f otherwise
148
149 // Assume that the gamma function is continuous, or this won't make much sense anyway.
150 // Plug in |d| to the first equation to calculate the new piecewise interval.
151 // Then simply use the inverse of the original functions.
Matt Sarett24107172016-12-19 14:33:35 -0500152 float interval = c * d + f;
msarettb3906762016-06-22 14:07:48 -0700153 if (x < interval) {
Matt Sarett24107172016-12-19 14:33:35 -0500154 // X = (Y - F) / C
155 if (0.0f == c) {
msarettb3906762016-06-22 14:07:48 -0700156 // The gamma curve for this segment is constant, so the inverse is undefined.
157 // Since this is the lower segment, guess zero.
158 return 0.0f;
159 }
160
Matt Sarett24107172016-12-19 14:33:35 -0500161 return (x - f) / c;
msarettb3906762016-06-22 14:07:48 -0700162 }
163
Matt Sarett24107172016-12-19 14:33:35 -0500164 // X = ((Y - E)^(1 / G) - B) / A
msarettb3906762016-06-22 14:07:48 -0700165 if (0.0f == a || 0.0f == g) {
166 // The gamma curve for this segment is constant, so the inverse is undefined.
167 // Since this is the upper segment, guess one.
168 return 1.0f;
169 }
170
Matt Sarett24107172016-12-19 14:33:35 -0500171 return (powf(x - e, 1.0f / g) - b) / a;
msarettb3906762016-06-22 14:07:48 -0700172}
173
msarett1b93bd12016-07-21 07:11:26 -0700174static void build_table_linear_to_gamma(uint8_t* outTable, float g, float a,
msarettb3906762016-06-22 14:07:48 -0700175 float b, float c, float d, float e, float f) {
msarett3418c0e2016-07-25 18:23:18 -0700176 for (int i = 0; i < kDstGammaTableSize; i++) {
177 float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1)));
msarettb3906762016-06-22 14:07:48 -0700178 float y = inverse_parametric(x, g, a, b, c, d, e, f);
179 outTable[i] = clamp_normalized_float_to_byte(y);
180 }
181}
182
msarett6006f672016-07-11 05:49:17 -0700183///////////////////////////////////////////////////////////////////////////////////////////////////
184
msarett1b93bd12016-07-21 07:11:26 -0700185template <typename T>
186struct GammaFns {
187 const T* fSRGBTable;
188 const T* f2Dot2Table;
msarett1b93bd12016-07-21 07:11:26 -0700189 void (*fBuildFromValue)(T*, float);
190 void (*fBuildFromTable)(T*, const float*, int);
191 void (*fBuildFromParam)(T*, float, float, float, float, float, float, float);
192};
193
194static const GammaFns<float> kToLinear {
195 sk_linear_from_srgb,
196 sk_linear_from_2dot2,
197 &build_table_linear_from_gamma,
198 &build_table_linear_from_gamma,
199 &build_table_linear_from_gamma,
200};
201
202static const GammaFns<uint8_t> kFromLinear {
msarett55bcc8e2016-09-09 07:48:05 -0700203 nullptr,
204 nullptr,
msarett1b93bd12016-07-21 07:11:26 -0700205 &build_table_linear_to_gamma,
206 &build_table_linear_to_gamma,
207 &build_table_linear_to_gamma,
208};
209
210// Build tables to transform src gamma to linear.
211template <typename T>
212static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, int gammaTableSize,
raftias94888332016-10-18 10:02:51 -0700213 const SkColorSpace_XYZ* space, const GammaFns<T>& fns,
Matt Sarettf4898862016-10-16 10:20:41 -0400214 bool gammasAreMatching)
msarett4be0e7c2016-09-22 07:02:24 -0700215{
raftias94888332016-10-18 10:02:51 -0700216 switch (space->gammaNamed()) {
msarett600c7372016-09-07 12:03:53 -0700217 case kSRGB_SkGammaNamed:
msarett1b93bd12016-07-21 07:11:26 -0700218 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRGBTable;
219 break;
msarett600c7372016-09-07 12:03:53 -0700220 case k2Dot2Curve_SkGammaNamed:
msarett1b93bd12016-07-21 07:11:26 -0700221 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Dot2Table;
222 break;
msarett600c7372016-09-07 12:03:53 -0700223 case kLinear_SkGammaNamed:
msarett8bbcd5a2016-09-14 07:06:08 -0700224 outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = nullptr;
msarett1b93bd12016-07-21 07:11:26 -0700225 break;
226 default: {
raftias94888332016-10-18 10:02:51 -0700227 const SkGammas* gammas = space->gammas();
msarett1b93bd12016-07-21 07:11:26 -0700228 SkASSERT(gammas);
229
msarett7bbda992016-09-14 11:02:04 -0700230 auto build_table = [=](int i) {
msarett1b93bd12016-07-21 07:11:26 -0700231 if (gammas->isNamed(i)) {
232 switch (gammas->data(i).fNamed) {
msarett600c7372016-09-07 12:03:53 -0700233 case kSRGB_SkGammaNamed:
Hal Canarya8565e52017-06-19 12:43:28 -0400234 (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize],
235 gSRGB_TransferFn.fG,
236 gSRGB_TransferFn.fA,
237 gSRGB_TransferFn.fB,
238 gSRGB_TransferFn.fC,
239 gSRGB_TransferFn.fD,
240 gSRGB_TransferFn.fE,
241 gSRGB_TransferFn.fF);
msarett55bcc8e2016-09-09 07:48:05 -0700242 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
msarett1b93bd12016-07-21 07:11:26 -0700243 break;
msarett600c7372016-09-07 12:03:53 -0700244 case k2Dot2Curve_SkGammaNamed:
msarett55bcc8e2016-09-09 07:48:05 -0700245 (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 2.2f);
246 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
msarett1b93bd12016-07-21 07:11:26 -0700247 break;
msarett600c7372016-09-07 12:03:53 -0700248 case kLinear_SkGammaNamed:
msarett1b93bd12016-07-21 07:11:26 -0700249 (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 1.0f);
250 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
251 break;
252 default:
253 SkASSERT(false);
254 break;
255 }
256 } else if (gammas->isValue(i)) {
257 (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize],
258 gammas->data(i).fValue);
259 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
260 } else if (gammas->isTable(i)) {
261 (*fns.fBuildFromTable)(&gammaTableStorage[i * gammaTableSize], gammas->table(i),
262 gammas->data(i).fTable.fSize);
263 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
264 } else {
265 SkASSERT(gammas->isParametric(i));
Matt Sarettdf44fc52016-10-11 16:57:50 -0400266 const SkColorSpaceTransferFn& params = gammas->params(i);
msarett1b93bd12016-07-21 07:11:26 -0700267 (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG,
268 params.fA, params.fB, params.fC, params.fD, params.fE,
269 params.fF);
270 outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
271 }
msarett7bbda992016-09-14 11:02:04 -0700272 };
273
274 if (gammasAreMatching) {
275 build_table(0);
276 outGammaTables[1] = outGammaTables[0];
277 outGammaTables[2] = outGammaTables[0];
278 } else {
279 build_table(0);
280 build_table(1);
281 build_table(2);
msarett1b93bd12016-07-21 07:11:26 -0700282 }
msarett7bbda992016-09-14 11:02:04 -0700283
284 break;
msarett1b93bd12016-07-21 07:11:26 -0700285 }
286 }
287}
288
Matt Sarettf4898862016-10-16 10:20:41 -0400289void SkColorSpaceXform_Base::BuildDstGammaTables(const uint8_t* dstGammaTables[3],
raftias94888332016-10-18 10:02:51 -0700290 uint8_t* dstStorage,
291 const SkColorSpace_XYZ* space,
Matt Sarettf4898862016-10-16 10:20:41 -0400292 bool gammasAreMatching) {
293 build_gamma_tables(dstGammaTables, dstStorage, kDstGammaTableSize, space, kFromLinear,
294 gammasAreMatching);
295}
296
msarett1b93bd12016-07-21 07:11:26 -0700297///////////////////////////////////////////////////////////////////////////////////////////////////
298
msarett4be0e7c2016-09-22 07:02:24 -0700299std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace,
300 SkColorSpace* dstSpace) {
Matt Sarettcf3f2342017-03-23 15:32:25 -0400301 return SkColorSpaceXform_Base::New(srcSpace, dstSpace, SkTransferFunctionBehavior::kRespect);
302}
303
304std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform_Base::New(SkColorSpace* srcSpace,
305 SkColorSpace* dstSpace, SkTransferFunctionBehavior premulBehavior) {
306
msarett6006f672016-07-11 05:49:17 -0700307 if (!srcSpace || !dstSpace) {
308 // Invalid input
309 return nullptr;
310 }
311
raftias94888332016-10-18 10:02:51 -0700312 if (SkColorSpace_Base::Type::kA2B == as_CSB(dstSpace)->type()) {
raftias25636012016-11-11 15:27:39 -0800313 SkCSXformPrintf("A2B destinations not supported\n");
raftias94888332016-10-18 10:02:51 -0700314 return nullptr;
315 }
316
317 if (SkColorSpace_Base::Type::kA2B == as_CSB(srcSpace)->type()) {
raftias25636012016-11-11 15:27:39 -0800318 SkColorSpace_A2B* src = static_cast<SkColorSpace_A2B*>(srcSpace);
319 SkColorSpace_XYZ* dst = static_cast<SkColorSpace_XYZ*>(dstSpace);
320 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_A2B(src, dst));
raftias94888332016-10-18 10:02:51 -0700321 }
322 SkColorSpace_XYZ* srcSpaceXYZ = static_cast<SkColorSpace_XYZ*>(srcSpace);
323 SkColorSpace_XYZ* dstSpaceXYZ = static_cast<SkColorSpace_XYZ*>(dstSpace);
324
msarett200877e2016-08-15 08:10:44 -0700325 ColorSpaceMatch csm = kNone_ColorSpaceMatch;
msarett6006f672016-07-11 05:49:17 -0700326 SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor);
Matt Sarettf3880932017-03-24 10:06:03 -0400327 if (SkColorSpace::Equals(srcSpace, dstSpace)) {
msarett200877e2016-08-15 08:10:44 -0700328 srcToDst.setIdentity();
329 csm = kFull_ColorSpaceMatch;
brianosman971cd492016-09-08 10:10:11 -0700330 } else {
Brian Osmanbbf251b2016-10-19 14:56:07 -0400331 if (srcSpaceXYZ->toXYZD50Hash() == dstSpaceXYZ->toXYZD50Hash()) {
332 SkASSERT(*srcSpaceXYZ->toXYZD50() == *dstSpaceXYZ->toXYZD50() && "Hash collision");
brianosman971cd492016-09-08 10:10:11 -0700333 srcToDst.setIdentity();
334 csm = kGamut_ColorSpaceMatch;
Brian Osmanbbf251b2016-10-19 14:56:07 -0400335 } else {
336 srcToDst.setConcat(*dstSpaceXYZ->fromXYZD50(), *srcSpaceXYZ->toXYZD50());
brianosman971cd492016-09-08 10:10:11 -0700337 }
msarett6006f672016-07-11 05:49:17 -0700338 }
339
msarett200877e2016-08-15 08:10:44 -0700340 switch (csm) {
341 case kNone_ColorSpaceMatch:
Matt Sarett379938e2017-01-12 18:34:29 -0500342 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
Matt Sarettcf3f2342017-03-23 15:32:25 -0400343 <kNone_ColorSpaceMatch>(srcSpaceXYZ, srcToDst, dstSpaceXYZ, premulBehavior));
msarett200877e2016-08-15 08:10:44 -0700344 case kGamut_ColorSpaceMatch:
Matt Sarett379938e2017-01-12 18:34:29 -0500345 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
Matt Sarettcf3f2342017-03-23 15:32:25 -0400346 <kGamut_ColorSpaceMatch>(srcSpaceXYZ, srcToDst, dstSpaceXYZ, premulBehavior));
msarett200877e2016-08-15 08:10:44 -0700347 case kFull_ColorSpaceMatch:
Matt Sarett379938e2017-01-12 18:34:29 -0500348 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ
Matt Sarettcf3f2342017-03-23 15:32:25 -0400349 <kFull_ColorSpaceMatch>(srcSpaceXYZ, srcToDst, dstSpaceXYZ, premulBehavior));
msarett3418c0e2016-07-25 18:23:18 -0700350 default:
msarett200877e2016-08-15 08:10:44 -0700351 SkASSERT(false);
352 return nullptr;
msarett6006f672016-07-11 05:49:17 -0700353 }
msarett6006f672016-07-11 05:49:17 -0700354}
355
356///////////////////////////////////////////////////////////////////////////////////////////////////
357
Mike Kleine23e55e2017-06-13 17:44:51 -0400358static inline int num_tables(SkColorSpace_XYZ* space) {
raftias94888332016-10-18 10:02:51 -0700359 switch (space->gammaNamed()) {
msarett7bbda992016-09-14 11:02:04 -0700360 case kSRGB_SkGammaNamed:
361 case k2Dot2Curve_SkGammaNamed:
362 case kLinear_SkGammaNamed:
363 return 0;
364 default: {
raftias94888332016-10-18 10:02:51 -0700365 const SkGammas* gammas = space->gammas();
msarett7bbda992016-09-14 11:02:04 -0700366 SkASSERT(gammas);
367
368 bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) &&
369 (gammas->data(0) == gammas->data(1)) &&
370 (gammas->type(0) == gammas->type(2)) &&
371 (gammas->data(0) == gammas->data(2));
372
373 // It's likely that each component will have the same gamma. In this case,
374 // we only need to build one table.
375 return gammasAreMatching ? 1 : 3;
376 }
377 }
378}
379
Matt Sarett379938e2017-01-12 18:34:29 -0500380template <ColorSpaceMatch kCSM>
381SkColorSpaceXform_XYZ<kCSM>
raftias94888332016-10-18 10:02:51 -0700382::SkColorSpaceXform_XYZ(SkColorSpace_XYZ* srcSpace, const SkMatrix44& srcToDst,
Matt Sarettcf3f2342017-03-23 15:32:25 -0400383 SkColorSpace_XYZ* dstSpace, SkTransferFunctionBehavior premulBehavior)
384 : fPremulBehavior(premulBehavior)
msarett3418c0e2016-07-25 18:23:18 -0700385{
Matt Sarett26a05432017-01-04 16:54:55 -0500386 fSrcToDst[ 0] = srcToDst.get(0, 0);
387 fSrcToDst[ 1] = srcToDst.get(1, 0);
388 fSrcToDst[ 2] = srcToDst.get(2, 0);
389 fSrcToDst[ 3] = srcToDst.get(0, 1);
390 fSrcToDst[ 4] = srcToDst.get(1, 1);
391 fSrcToDst[ 5] = srcToDst.get(2, 1);
392 fSrcToDst[ 6] = srcToDst.get(0, 2);
393 fSrcToDst[ 7] = srcToDst.get(1, 2);
394 fSrcToDst[ 8] = srcToDst.get(2, 2);
395 fSrcToDst[ 9] = srcToDst.get(0, 3);
396 fSrcToDst[10] = srcToDst.get(1, 3);
397 fSrcToDst[11] = srcToDst.get(2, 3);
398 fSrcToDst[12] = 0.0f;
msarett7bbda992016-09-14 11:02:04 -0700399
msarett4be0e7c2016-09-22 07:02:24 -0700400 const int numSrcTables = num_tables(srcSpace);
Matt Sarettf4898862016-10-16 10:20:41 -0400401 const size_t srcEntries = numSrcTables * 256;
msarett7bbda992016-09-14 11:02:04 -0700402 const bool srcGammasAreMatching = (1 >= numSrcTables);
Matt Sarettf4898862016-10-16 10:20:41 -0400403 fSrcStorage.reset(srcEntries);
404 build_gamma_tables(fSrcGammaTables, fSrcStorage.get(), 256, srcSpace, kToLinear,
405 srcGammasAreMatching);
406
407 const int numDstTables = num_tables(dstSpace);
raftias94888332016-10-18 10:02:51 -0700408 dstSpace->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTables);
Matt Sarett379938e2017-01-12 18:34:29 -0500409
410 if (srcSpace->gammaIsLinear()) {
411 fSrcGamma = kLinear_SrcGamma;
412 } else if (kSRGB_SkGammaNamed == srcSpace->gammaNamed()) {
413 fSrcGamma = kSRGB_SrcGamma;
414 } else {
415 fSrcGamma = kTable_SrcGamma;
416 }
417
418 switch (dstSpace->gammaNamed()) {
419 case kSRGB_SkGammaNamed:
420 fDstGamma = kSRGB_DstGamma;
421 break;
422 case k2Dot2Curve_SkGammaNamed:
423 fDstGamma = k2Dot2_DstGamma;
424 break;
425 case kLinear_SkGammaNamed:
426 fDstGamma = kLinear_DstGamma;
427 break;
428 default:
429 fDstGamma = kTable_DstGamma;
430 break;
431 }
msarett3418c0e2016-07-25 18:23:18 -0700432}
433
msarett7bbda992016-09-14 11:02:04 -0700434///////////////////////////////////////////////////////////////////////////////////////////////////
435
Mike Klein1f8796d2017-06-15 19:50:33 +0000436template <ColorSpaceMatch kCSM>
Mike Kleine23e55e2017-06-13 17:44:51 -0400437bool SkColorSpaceXform_XYZ<kCSM>::onApply(ColorFormat dstColorFormat, void* dst,
438 ColorFormat srcColorFormat, const void* src,
439 int len, SkAlphaType alphaType) const {
440 if (kFull_ColorSpaceMatch == kCSM && kPremul_SkAlphaType != alphaType) {
441 if ((kRGBA_8888_ColorFormat == dstColorFormat &&
442 kRGBA_8888_ColorFormat == srcColorFormat) ||
443 (kBGRA_8888_ColorFormat == dstColorFormat &&
444 kBGRA_8888_ColorFormat == srcColorFormat))
445 {
446 memcpy(dst, src, len * sizeof(uint32_t));
447 return true;
448 }
449
450 if ((kRGBA_8888_ColorFormat == dstColorFormat &&
451 kBGRA_8888_ColorFormat == srcColorFormat) ||
452 (kBGRA_8888_ColorFormat == dstColorFormat &&
453 kRGBA_8888_ColorFormat == srcColorFormat))
454 {
455 SkOpts::RGBA_to_BGRA((uint32_t*)dst, src, len);
456 return true;
msarett200877e2016-08-15 08:10:44 -0700457 }
458 }
459
Mike Kleine23e55e2017-06-13 17:44:51 -0400460 return this->applyPipeline(dstColorFormat, dst, srcColorFormat, src, len, alphaType);
msarett9ce3a542016-07-15 13:54:38 -0700461}
msarett9dc6cf62016-08-23 17:53:06 -0700462
Matt Sarettf4898862016-10-16 10:20:41 -0400463bool SkColorSpaceXform::apply(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat,
464 const void* src, int len, SkAlphaType alphaType) const {
465 return ((SkColorSpaceXform_Base*) this)->onApply(dstColorFormat, dst, srcColorFormat, src, len,
466 alphaType);
467}
468
Mike Reededf8a762017-05-22 13:41:36 -0400469bool SkColorSpaceXform::Apply(SkColorSpace* dstCS, ColorFormat dstFormat, void* dst,
470 SkColorSpace* srcCS, ColorFormat srcFormat, const void* src,
471 int count, AlphaOp op) {
472 SkAlphaType at;
473 switch (op) {
474 case kPreserve_AlphaOp: at = kUnpremul_SkAlphaType; break;
475 case kPremul_AlphaOp: at = kPremul_SkAlphaType; break;
476 case kSrcIsOpaque_AlphaOp: at = kOpaque_SkAlphaType; break;
477 }
478 return New(srcCS, dstCS)->apply(dstFormat, dst, srcFormat, src, count, at);
479}
480
msarett7bbda992016-09-14 11:02:04 -0700481///////////////////////////////////////////////////////////////////////////////////////////////////
482
Matt Sarett379938e2017-01-12 18:34:29 -0500483template <ColorSpaceMatch kCSM>
484bool SkColorSpaceXform_XYZ<kCSM>
Matt Sarett26a05432017-01-04 16:54:55 -0500485::applyPipeline(ColorFormat dstColorFormat, void* dst, ColorFormat srcColorFormat,
486 const void* src, int len, SkAlphaType alphaType) const {
Mike Kleinb24704d2017-05-24 07:53:00 -0400487 SkRasterPipeline_<256> pipeline;
Matt Sarettf6878ba2016-12-01 14:46:12 -0500488
Mike Klein45c16fa2017-07-18 18:15:13 -0400489 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
490 dst_ctx = { (void*)dst, 0 };
491
Matt Sarettf6878ba2016-12-01 14:46:12 -0500492 LoadTablesContext loadTables;
Matt Sarett26a05432017-01-04 16:54:55 -0500493 switch (srcColorFormat) {
494 case kRGBA_8888_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -0500495 if (kLinear_SrcGamma == fSrcGamma) {
Mike Klein45c16fa2017-07-18 18:15:13 -0400496 pipeline.append(SkRasterPipeline::load_8888, &src_ctx);
Matt Sarett26a05432017-01-04 16:54:55 -0500497 } else {
Matt Sarett379938e2017-01-12 18:34:29 -0500498 loadTables.fSrc = src;
Matt Sarett26a05432017-01-04 16:54:55 -0500499 loadTables.fR = fSrcGammaTables[0];
500 loadTables.fG = fSrcGammaTables[1];
501 loadTables.fB = fSrcGammaTables[2];
502 pipeline.append(SkRasterPipeline::load_tables, &loadTables);
503 }
504
505 break;
506 case kBGRA_8888_ColorFormat:
Matt Sarett379938e2017-01-12 18:34:29 -0500507 if (kLinear_SrcGamma == fSrcGamma) {
Mike Klein45c16fa2017-07-18 18:15:13 -0400508 pipeline.append(SkRasterPipeline::load_bgra, &src_ctx);
Matt Sarett26a05432017-01-04 16:54:55 -0500509 } else {
Matt Sarett379938e2017-01-12 18:34:29 -0500510 loadTables.fSrc = src;
Matt Sarett26a05432017-01-04 16:54:55 -0500511 loadTables.fR = fSrcGammaTables[2];
512 loadTables.fG = fSrcGammaTables[1];
513 loadTables.fB = fSrcGammaTables[0];
514 pipeline.append(SkRasterPipeline::load_tables, &loadTables);
Mike Kleinc2d20762017-06-27 19:53:21 -0400515 pipeline.append(SkRasterPipeline::swap_rb);
Matt Sarett26a05432017-01-04 16:54:55 -0500516 }
517
Matt Sarett26a05432017-01-04 16:54:55 -0500518 break;
Brian Osmanb1168a72017-03-20 14:21:18 -0400519 case kRGBA_F16_ColorFormat:
520 if (kLinear_SrcGamma != fSrcGamma) {
521 return false;
522 }
Mike Klein45c16fa2017-07-18 18:15:13 -0400523 pipeline.append(SkRasterPipeline::load_f16, &src_ctx);
Brian Osmanb1168a72017-03-20 14:21:18 -0400524 break;
Matt Sarett4c550272017-03-20 19:06:18 -0400525 case kRGBA_F32_ColorFormat:
526 if (kLinear_SrcGamma != fSrcGamma) {
527 return false;
528 }
Mike Klein45c16fa2017-07-18 18:15:13 -0400529 pipeline.append(SkRasterPipeline::load_f32, &src_ctx);
Matt Sarett4c550272017-03-20 19:06:18 -0400530 break;
Matt Sarett379938e2017-01-12 18:34:29 -0500531 case kRGBA_U16_BE_ColorFormat:
532 switch (fSrcGamma) {
533 case kLinear_SrcGamma:
Mike Klein45c16fa2017-07-18 18:15:13 -0400534 pipeline.append(SkRasterPipeline::load_u16_be, &src_ctx);
Matt Sarett379938e2017-01-12 18:34:29 -0500535 break;
536 case kSRGB_SrcGamma:
Mike Klein45c16fa2017-07-18 18:15:13 -0400537 pipeline.append(SkRasterPipeline::load_u16_be, &src_ctx);
Matt Sarett379938e2017-01-12 18:34:29 -0500538 pipeline.append_from_srgb(kUnpremul_SkAlphaType);
539 break;
540 case kTable_SrcGamma:
541 loadTables.fSrc = src;
542 loadTables.fR = fSrcGammaTables[0];
543 loadTables.fG = fSrcGammaTables[1];
544 loadTables.fB = fSrcGammaTables[2];
545 pipeline.append(SkRasterPipeline::load_tables_u16_be, &loadTables);
546 break;
547 }
548 break;
Matt Sarett5bee0b62017-01-19 12:04:32 -0500549 case kRGB_U16_BE_ColorFormat:
550 switch (fSrcGamma) {
551 case kLinear_SrcGamma:
Mike Klein45c16fa2017-07-18 18:15:13 -0400552 pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src_ctx);
Matt Sarett5bee0b62017-01-19 12:04:32 -0500553 break;
554 case kSRGB_SrcGamma:
Mike Klein45c16fa2017-07-18 18:15:13 -0400555 pipeline.append(SkRasterPipeline::load_rgb_u16_be, &src_ctx);
Matt Sarett5bee0b62017-01-19 12:04:32 -0500556 pipeline.append_from_srgb(kUnpremul_SkAlphaType);
557 break;
558 case kTable_SrcGamma:
559 loadTables.fSrc = src;
560 loadTables.fR = fSrcGammaTables[0];
561 loadTables.fG = fSrcGammaTables[1];
562 loadTables.fB = fSrcGammaTables[2];
563 pipeline.append(SkRasterPipeline::load_tables_rgb_u16_be, &loadTables);
564 break;
565 }
566 break;
Matt Sarett3725f0a2017-03-28 14:34:20 -0400567 default:
568 return false;
Matt Sarettf6878ba2016-12-01 14:46:12 -0500569 }
570
Matt Sarett26a05432017-01-04 16:54:55 -0500571 if (kNone_ColorSpaceMatch == kCSM) {
Matt Sarettf6878ba2016-12-01 14:46:12 -0500572 pipeline.append(SkRasterPipeline::matrix_3x4, fSrcToDst);
Matt Sarettf6878ba2016-12-01 14:46:12 -0500573
Matt Saretteeb3cb12017-03-29 20:00:18 -0400574 if (kRGBA_F16_ColorFormat != dstColorFormat &&
575 kRGBA_F32_ColorFormat != dstColorFormat)
Matt Sarett8f7a9a92017-03-29 17:12:26 -0400576 {
Mike Klein5e159612016-12-01 16:39:21 -0500577 bool need_clamp_0, need_clamp_1;
578 analyze_3x4_matrix(fSrcToDst, &need_clamp_0, &need_clamp_1);
579
580 if (need_clamp_0) { pipeline.append(SkRasterPipeline::clamp_0); }
581 if (need_clamp_1) { pipeline.append(SkRasterPipeline::clamp_1); }
582 }
Matt Sarettf6878ba2016-12-01 14:46:12 -0500583 }
584
Matt Sarettcf3f2342017-03-23 15:32:25 -0400585 if (kPremul_SkAlphaType == alphaType && SkTransferFunctionBehavior::kRespect == fPremulBehavior)
586 {
Matt Sarettf6878ba2016-12-01 14:46:12 -0500587 pipeline.append(SkRasterPipeline::premul);
588 }
589
Matt Sarette522f4c2017-02-22 13:02:31 -0500590 TablesContext tables;
Mike Kleina07e4302017-08-09 13:51:35 -0400591 float to_2dot2 = 1/2.2f;
Matt Sarett379938e2017-01-12 18:34:29 -0500592 switch (fDstGamma) {
Matt Sarettf6878ba2016-12-01 14:46:12 -0500593 case kSRGB_DstGamma:
594 pipeline.append(SkRasterPipeline::to_srgb);
595 break;
596 case k2Dot2_DstGamma:
Mike Kleina07e4302017-08-09 13:51:35 -0400597 pipeline.append(SkRasterPipeline::gamma, &to_2dot2);
Matt Sarettf6878ba2016-12-01 14:46:12 -0500598 break;
Matt Sarette522f4c2017-02-22 13:02:31 -0500599 case kTable_DstGamma:
600 tables.fR = fDstGammaTables[0];
601 tables.fG = fDstGammaTables[1];
602 tables.fB = fDstGammaTables[2];
603 tables.fCount = SkColorSpaceXform_Base::kDstGammaTableSize;
604 pipeline.append(SkRasterPipeline::byte_tables_rgb, &tables);
Matt Sarettf6878ba2016-12-01 14:46:12 -0500605 default:
606 break;
607 }
608
Matt Sarettcf3f2342017-03-23 15:32:25 -0400609 if (kPremul_SkAlphaType == alphaType && SkTransferFunctionBehavior::kIgnore == fPremulBehavior)
610 {
Matt Sarette522f4c2017-02-22 13:02:31 -0500611 pipeline.append(SkRasterPipeline::premul);
612 }
613
Matt Sarettf6878ba2016-12-01 14:46:12 -0500614 switch (dstColorFormat) {
615 case kRGBA_8888_ColorFormat:
Mike Klein45c16fa2017-07-18 18:15:13 -0400616 pipeline.append(SkRasterPipeline::store_8888, &dst_ctx);
Matt Sarettf6878ba2016-12-01 14:46:12 -0500617 break;
618 case kBGRA_8888_ColorFormat:
Mike Klein45c16fa2017-07-18 18:15:13 -0400619 pipeline.append(SkRasterPipeline::store_bgra, &dst_ctx);
Matt Sarettf6878ba2016-12-01 14:46:12 -0500620 break;
621 case kRGBA_F16_ColorFormat:
Matt Sarettcf3f2342017-03-23 15:32:25 -0400622 if (kLinear_DstGamma != fDstGamma) {
Matt Sarettf6878ba2016-12-01 14:46:12 -0500623 return false;
624 }
Mike Klein45c16fa2017-07-18 18:15:13 -0400625 pipeline.append(SkRasterPipeline::store_f16, &dst_ctx);
Matt Sarettf6878ba2016-12-01 14:46:12 -0500626 break;
627 case kRGBA_F32_ColorFormat:
Matt Sarettcf3f2342017-03-23 15:32:25 -0400628 if (kLinear_DstGamma != fDstGamma) {
Matt Sarettf6878ba2016-12-01 14:46:12 -0500629 return false;
630 }
Mike Klein45c16fa2017-07-18 18:15:13 -0400631 pipeline.append(SkRasterPipeline::store_f32, &dst_ctx);
Matt Sarettf6878ba2016-12-01 14:46:12 -0500632 break;
Matt Sarett3725f0a2017-03-28 14:34:20 -0400633 case kBGR_565_ColorFormat:
634 if (kOpaque_SkAlphaType != alphaType) {
635 return false;
636 }
Mike Klein45c16fa2017-07-18 18:15:13 -0400637 pipeline.append(SkRasterPipeline::store_565, &dst_ctx);
Matt Sarett3725f0a2017-03-28 14:34:20 -0400638 break;
Matt Sarett379938e2017-01-12 18:34:29 -0500639 default:
640 return false;
Matt Sarettf6878ba2016-12-01 14:46:12 -0500641 }
642
Mike Klein45c16fa2017-07-18 18:15:13 -0400643 pipeline.run(0,0, len,1);
Matt Sarettf6878ba2016-12-01 14:46:12 -0500644 return true;
645}
646
647///////////////////////////////////////////////////////////////////////////////////////////////////
648
raftias94888332016-10-18 10:02:51 -0700649std::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space) {
Matt Sarettcf3f2342017-03-23 15:32:25 -0400650 return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ<kNone_ColorSpaceMatch>
651 (space, SkMatrix::I(), space, SkTransferFunctionBehavior::kRespect));
msarett9dc6cf62016-08-23 17:53:06 -0700652}