blob: 2c14c802831e51950b799054ee73e67b5021a3a0 [file] [log] [blame]
msaretta9e878c2016-06-08 14:43:53 -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#ifndef SkColorXform_opts_DEFINED
9#define SkColorXform_opts_DEFINED
10
mtklein64f061a2016-06-17 12:09:16 -070011#include "SkNx.h"
msaretta9e878c2016-06-08 14:43:53 -070012#include "SkColorPriv.h"
13
14namespace SK_OPTS_NS {
15
msarettdea03402016-06-16 10:50:55 -070016extern const float linear_from_srgb[256] = {
17 0.000000000000000000f, 0.000303526983548838f, 0.000607053967097675f, 0.000910580950646513f,
18 0.001214107934195350f, 0.001517634917744190f, 0.001821161901293030f, 0.002124688884841860f,
19 0.002428215868390700f, 0.002731742851939540f, 0.003034518678424960f, 0.003346535763899160f,
20 0.003676507324047440f, 0.004024717018496310f, 0.004391442037410290f, 0.004776953480693730f,
21 0.005181516702338390f, 0.005605391624202720f, 0.006048833022857060f, 0.006512090792594470f,
22 0.006995410187265390f, 0.007499032043226180f, 0.008023192985384990f, 0.008568125618069310f,
23 0.009134058702220790f, 0.009721217320237850f, 0.010329823029626900f, 0.010960094006488200f,
24 0.011612245179743900f, 0.012286488356915900f, 0.012983032342173000f, 0.013702083047289700f,
25 0.014443843596092500f, 0.015208514422912700f, 0.015996293365509600f, 0.016807375752887400f,
26 0.017641954488384100f, 0.018500220128379700f, 0.019382360956935700f, 0.020288563056652400f,
27 0.021219010376003600f, 0.022173884793387400f, 0.023153366178110400f, 0.024157632448504800f,
28 0.025186859627361600f, 0.026241221894849900f, 0.027320891639074900f, 0.028426039504420800f,
29 0.029556834437808800f, 0.030713443732993600f, 0.031896033073011500f, 0.033104766570885100f,
30 0.034339806808682200f, 0.035601314875020300f, 0.036889450401100000f, 0.038204371595346500f,
31 0.039546235276732800f, 0.040915196906853200f, 0.042311410620809700f, 0.043735029256973500f,
32 0.045186204385675500f, 0.046665086336880100f, 0.048171824226889400f, 0.049706565984127200f,
33 0.051269458374043200f, 0.052860647023180200f, 0.054480276442442400f, 0.056128490049600100f,
34 0.057805430191067200f, 0.059511238162981200f, 0.061246054231617600f, 0.063010017653167700f,
35 0.064803266692905800f, 0.066625938643772900f, 0.068478169844400200f, 0.070360095696595900f,
36 0.072271850682317500f, 0.074213568380149600f, 0.076185381481307900f, 0.078187421805186300f,
37 0.080219820314468300f, 0.082282707129814800f, 0.084376211544148800f, 0.086500462036549800f,
38 0.088655586285772900f, 0.090841711183407700f, 0.093058962846687500f, 0.095307466630964700f,
39 0.097587347141862500f, 0.099898728247113900f, 0.102241733088101000f, 0.104616484091104000f,
40 0.107023102978268000f, 0.109461710778299000f, 0.111932427836906000f, 0.114435373826974000f,
41 0.116970667758511000f, 0.119538427988346000f, 0.122138772229602000f, 0.124771817560950000f,
42 0.127437680435647000f, 0.130136476690364000f, 0.132868321553818000f, 0.135633329655206000f,
43 0.138431615032452000f, 0.141263291140272000f, 0.144128470858058000f, 0.147027266497595000f,
44 0.149959789810609000f, 0.152926151996150000f, 0.155926463707827000f, 0.158960835060880000f,
45 0.162029375639111000f, 0.165132194501668000f, 0.168269400189691000f, 0.171441100732823000f,
46 0.174647403655585000f, 0.177888415983629000f, 0.181164244249860000f, 0.184474994500441000f,
47 0.187820772300678000f, 0.191201682740791000f, 0.194617830441576000f, 0.198069319559949000f,
48 0.201556253794397000f, 0.205078736390317000f, 0.208636870145256000f, 0.212230757414055000f,
49 0.215860500113899000f, 0.219526199729269000f, 0.223227957316809000f, 0.226965873510098000f,
50 0.230740048524349000f, 0.234550582161005000f, 0.238397573812271000f, 0.242281122465555000f,
51 0.246201326707835000f, 0.250158284729953000f, 0.254152094330827000f, 0.258182852921596000f,
52 0.262250657529696000f, 0.266355604802862000f, 0.270497791013066000f, 0.274677312060385000f,
53 0.278894263476810000f, 0.283148740429992000f, 0.287440837726918000f, 0.291770649817536000f,
54 0.296138270798321000f, 0.300543794415777000f, 0.304987314069886000f, 0.309468922817509000f,
55 0.313988713375718000f, 0.318546778125092000f, 0.323143209112951000f, 0.327778098056542000f,
56 0.332451536346179000f, 0.337163615048330000f, 0.341914424908661000f, 0.346704056355030000f,
57 0.351532599500439000f, 0.356400144145944000f, 0.361306779783510000f, 0.366252595598840000f,
58 0.371237680474149000f, 0.376262122990906000f, 0.381326011432530000f, 0.386429433787049000f,
59 0.391572477749723000f, 0.396755230725627000f, 0.401977779832196000f, 0.407240211901737000f,
60 0.412542613483904000f, 0.417885070848138000f, 0.423267669986072000f, 0.428690496613907000f,
61 0.434153636174749000f, 0.439657173840919000f, 0.445201194516228000f, 0.450785782838223000f,
62 0.456411023180405000f, 0.462076999654407000f, 0.467783796112159000f, 0.473531496148010000f,
63 0.479320183100827000f, 0.485149940056070000f, 0.491020849847836000f, 0.496932995060870000f,
64 0.502886458032569000f, 0.508881320854934000f, 0.514917665376521000f, 0.520995573204354000f,
65 0.527115125705813000f, 0.533276404010505000f, 0.539479489012107000f, 0.545724461370187000f,
66 0.552011401512000000f, 0.558340389634268000f, 0.564711505704929000f, 0.571124829464873000f,
67 0.577580440429651000f, 0.584078417891164000f, 0.590618840919337000f, 0.597201788363763000f,
68 0.603827338855338000f, 0.610495570807865000f, 0.617206562419651000f, 0.623960391675076000f,
69 0.630757136346147000f, 0.637596873994033000f, 0.644479681970582000f, 0.651405637419824000f,
70 0.658374817279448000f, 0.665387298282272000f, 0.672443156957688000f, 0.679542469633094000f,
71 0.686685312435314000f, 0.693871761291990000f, 0.701101891932973000f, 0.708375779891687000f,
72 0.715693500506481000f, 0.723055128921969000f, 0.730460740090354000f, 0.737910408772731000f,
73 0.745404209540387000f, 0.752942216776078000f, 0.760524504675292000f, 0.768151147247507000f,
74 0.775822218317423000f, 0.783537791526194000f, 0.791297940332630000f, 0.799102738014409000f,
75 0.806952257669252000f, 0.814846572216101000f, 0.822785754396284000f, 0.830769876774655000f,
76 0.838799011740740000f, 0.846873231509858000f, 0.854992608124234000f, 0.863157213454102000f,
77 0.871367119198797000f, 0.879622396887832000f, 0.887923117881966000f, 0.896269353374266000f,
78 0.904661174391149000f, 0.913098651793419000f, 0.921581856277295000f, 0.930110858375424000f,
79 0.938685728457888000f, 0.947306536733200000f, 0.955973353249286000f, 0.964686247894465000f,
80 0.973445290398413000f, 0.982250550333117000f, 0.991102097113830000f, 1.000000000000000000f,
81};
msaretta9e878c2016-06-08 14:43:53 -070082
msarettdea03402016-06-16 10:50:55 -070083extern const float linear_from_2dot2[256] = {
84 0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.000056921765712193f,
85 0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.000367136269815943f,
86 0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.000992374304074325f,
87 0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.001963416213396470f,
88 0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.003302703032003640f,
89 0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.005028203456855540f,
90 0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.007155037004573030f,
91 0.007751027397660610f, 0.008373117745148580f, 0.009021491898012130f, 0.009696328701658230f,
92 0.010397802292555300f, 0.011126082368383200f, 0.011881334434813700f, 0.012663720031582100f,
93 0.013473396940142600f, 0.014310519374884100f, 0.015175238159625200f, 0.016067700890886900f,
94 0.016988052089250000f, 0.017936433339950200f, 0.018912983423721500f, 0.019917838438785700f,
95 0.020951131914781100f, 0.022012994919336500f, 0.023103556157921400f, 0.024222942067534200f,
96 0.025371276904734600f, 0.026548682828472900f, 0.027755279978126000f, 0.028991186547107800f,
97 0.030256518852388700f, 0.031551391400226400f, 0.032875916948383800f, 0.034230206565082000f,
98 0.035614369684918800f, 0.037028514161960200f, 0.038472746320194600f, 0.039947171001525600f,
99 0.041451891611462500f, 0.042987010162657100f, 0.044552627316421400f, 0.046148842422351000f,
100 0.047775753556170600f, 0.049433457555908000f, 0.051122050056493400f, 0.052841625522879000f,
101 0.054592277281760300f, 0.056374097551979800f, 0.058187177473685400f, 0.060031607136313200f,
102 0.061907475605455800f, 0.063814870948677200f, 0.065753880260330100f, 0.067724589685424300f,
103 0.069727084442598800f, 0.071761448846239100f, 0.073827766327784600f, 0.075926119456264800f,
104 0.078056589958101900f, 0.080219258736215100f, 0.082414205888459200f, 0.084641510725429500f,
105 0.086901251787660300f, 0.089193506862247800f, 0.091518352998919500f, 0.093875866525577800f,
106 0.096266123063339700f, 0.098689197541094500f, 0.101145164209600000f, 0.103634096655137000f,
107 0.106156067812744000f, 0.108711149979039000f, 0.111299414824660000f, 0.113920933406333000f,
108 0.116575776178572000f, 0.119264013005047000f, 0.121985713169619000f, 0.124740945387051000f,
109 0.127529777813422000f, 0.130352278056244000f, 0.133208513184300000f, 0.136098549737202000f,
110 0.139022453734703000f, 0.141980290685736000f, 0.144972125597231000f, 0.147998022982685000f,
111 0.151058046870511000f, 0.154152260812165000f, 0.157280727890073000f, 0.160443510725344000f,
112 0.163640671485290000f, 0.166872271890766000f, 0.170138373223312000f, 0.173439036332135000f,
113 0.176774321640903000f, 0.180144289154390000f, 0.183548998464951000f, 0.186988508758844000f,
114 0.190462878822409000f, 0.193972167048093000f, 0.197516431440340000f, 0.201095729621346000f,
115 0.204710118836677000f, 0.208359655960767000f, 0.212044397502288000f, 0.215764399609395000f,
116 0.219519718074868000f, 0.223310408341127000f, 0.227136525505149000f, 0.230998124323267000f,
117 0.234895259215880000f, 0.238827984272048000f, 0.242796353254002000f, 0.246800419601550000f,
118 0.250840236436400000f, 0.254915856566385000f, 0.259027332489606000f, 0.263174716398492000f,
119 0.267358060183772000f, 0.271577415438375000f, 0.275832833461245000f, 0.280124365261085000f,
120 0.284452061560024000f, 0.288815972797219000f, 0.293216149132375000f, 0.297652640449211000f,
121 0.302125496358853000f, 0.306634766203158000f, 0.311180499057984000f, 0.315762743736397000f,
122 0.320381548791810000f, 0.325036962521076000f, 0.329729032967515000f, 0.334457807923889000f,
123 0.339223334935327000f, 0.344025661302187000f, 0.348864834082879000f, 0.353740900096629000f,
124 0.358653905926199000f, 0.363603897920553000f, 0.368590922197487000f, 0.373615024646202000f,
125 0.378676250929840000f, 0.383774646487975000f, 0.388910256539059000f, 0.394083126082829000f,
126 0.399293299902674000f, 0.404540822567962000f, 0.409825738436323000f, 0.415148091655907000f,
127 0.420507926167587000f, 0.425905285707146000f, 0.431340213807410000f, 0.436812753800359000f,
128 0.442322948819202000f, 0.447870841800410000f, 0.453456475485731000f, 0.459079892424160000f,
129 0.464741134973889000f, 0.470440245304218000f, 0.476177265397440000f, 0.481952237050698000f,
130 0.487765201877811000f, 0.493616201311074000f, 0.499505276603030000f, 0.505432468828216000f,
131 0.511397818884880000f, 0.517401367496673000f, 0.523443155214325000f, 0.529523222417277000f,
132 0.535641609315311000f, 0.541798355950137000f, 0.547993502196972000f, 0.554227087766085000f,
133 0.560499152204328000f, 0.566809734896638000f, 0.573158875067523000f, 0.579546611782525000f,
134 0.585972983949661000f, 0.592438030320847000f, 0.598941789493296000f, 0.605484299910907000f,
135 0.612065599865624000f, 0.618685727498780000f, 0.625344720802427000f, 0.632042617620641000f,
136 0.638779455650817000f, 0.645555272444935000f, 0.652370105410821000f, 0.659223991813387000f,
137 0.666116968775851000f, 0.673049073280942000f, 0.680020342172095000f, 0.687030812154625000f,
138 0.694080519796882000f, 0.701169501531402000f, 0.708297793656032000f, 0.715465432335048000f,
139 0.722672453600255000f, 0.729918893352071000f, 0.737204787360605000f, 0.744530171266715000f,
140 0.751895080583051000f, 0.759299550695091000f, 0.766743616862161000f, 0.774227314218442000f,
141 0.781750677773962000f, 0.789313742415586000f, 0.796916542907978000f, 0.804559113894567000f,
142 0.812241489898490000f, 0.819963705323528000f, 0.827725794455034000f, 0.835527791460841000f,
143 0.843369730392169000f, 0.851251645184515000f, 0.859173569658532000f, 0.867135537520905000f,
144 0.875137582365205000f, 0.883179737672745000f, 0.891262036813419000f, 0.899384513046529000f,
145 0.907547199521614000f, 0.915750129279253000f, 0.923993335251873000f, 0.932276850264543000f,
146 0.940600707035753000f, 0.948964938178195000f, 0.957369576199527000f, 0.965814653503130000f,
147 0.974300202388861000f, 0.982826255053791000f, 0.991392843592940000f, 1.000000000000000000f,
148};
msaretta9e878c2016-06-08 14:43:53 -0700149
mtklein64f061a2016-06-17 12:09:16 -0700150static Sk4f linear_to_2dot2(const Sk4f& x) {
151 // x^(29/64) is a very good approximation of the true value, x^(1/2.2).
152 auto x2 = x.rsqrt(), // x^(-1/2)
153 x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(), // x^(-1/32)
154 x64 = x32.rsqrt(); // x^(+1/64)
msaretta9e878c2016-06-08 14:43:53 -0700155
mtklein64f061a2016-06-17 12:09:16 -0700156 // 29 = 32 - 2 - 1
157 return 255.0f * x2.invert() * x32 * x64.invert();
msarettdea03402016-06-16 10:50:55 -0700158}
159
msarettd2809572016-06-20 06:07:45 -0700160static Sk4f linear_to_srgb(const Sk4f& x) {
161 // Approximation of the sRGB gamma curve (within 1 when scaled to 8-bit pixels).
162 // For 0.00000f <= x < 0.00349f, 12.92 * x
163 // For 0.00349f <= x <= 1.00000f, 0.679*(x.^0.5) + 0.423*x.^(0.25) - 0.101
164 // Note that 0.00349 was selected because it is a point where both functions produce the
165 // same pixel value when rounded.
166 auto rsqrt = x.rsqrt(),
167 sqrt = rsqrt.invert(),
168 ftrt = rsqrt.rsqrt();
169
170 auto hi = (-0.101115084998961f * 255.0f) +
171 (+0.678513029959381f * 255.0f) * sqrt +
172 (+0.422602055039580f * 255.0f) * ftrt;
173
174 auto lo = (12.92f * 255.0f) * x;
175
176 auto mask = (x < 0.00349f);
177 return mask.thenElse(lo, hi);
178}
179
mtklein64f061a2016-06-17 12:09:16 -0700180static Sk4f clamp_0_to_255(const Sk4f& x) {
msarettdea03402016-06-16 10:50:55 -0700181 // The order of the arguments is important here. We want to make sure that NaN
182 // clamps to zero. Note that max(NaN, 0) = 0, while max(0, NaN) = NaN.
mtklein64f061a2016-06-17 12:09:16 -0700183 return Sk4f::Min(Sk4f::Max(x, 0.0f), 255.0f);
msarettdea03402016-06-16 10:50:55 -0700184}
185
msarettd2809572016-06-20 06:07:45 -0700186template <const float (&linear_from_curve)[256], Sk4f (*linear_to_curve)(const Sk4f&)>
msarettdea03402016-06-16 10:50:55 -0700187static void color_xform_RGB1(uint32_t* dst, const uint32_t* src, int len,
188 const float matrix[16]) {
msaretta9e878c2016-06-08 14:43:53 -0700189 // Load transformation matrix.
mtklein64f061a2016-06-17 12:09:16 -0700190 auto rXgXbX = Sk4f::Load(matrix + 0),
191 rYgYbY = Sk4f::Load(matrix + 4),
192 rZgZbZ = Sk4f::Load(matrix + 8);
msaretta9e878c2016-06-08 14:43:53 -0700193
194 while (len >= 4) {
msarettdea03402016-06-16 10:50:55 -0700195 // Convert to linear. The look-up table has perfect accuracy.
mtklein64f061a2016-06-17 12:09:16 -0700196 auto reds = Sk4f{linear_from_curve[(src[0] >> 0) & 0xFF],
197 linear_from_curve[(src[1] >> 0) & 0xFF],
198 linear_from_curve[(src[2] >> 0) & 0xFF],
199 linear_from_curve[(src[3] >> 0) & 0xFF]};
200 auto greens = Sk4f{linear_from_curve[(src[0] >> 8) & 0xFF],
201 linear_from_curve[(src[1] >> 8) & 0xFF],
202 linear_from_curve[(src[2] >> 8) & 0xFF],
203 linear_from_curve[(src[3] >> 8) & 0xFF]};
204 auto blues = Sk4f{linear_from_curve[(src[0] >> 16) & 0xFF],
205 linear_from_curve[(src[1] >> 16) & 0xFF],
206 linear_from_curve[(src[2] >> 16) & 0xFF],
207 linear_from_curve[(src[3] >> 16) & 0xFF]};
msaretta9e878c2016-06-08 14:43:53 -0700208
209 // Apply the transformation matrix to dst gamut.
mtklein64f061a2016-06-17 12:09:16 -0700210 auto dstReds = rXgXbX[0]*reds + rYgYbY[0]*greens + rZgZbZ[0]*blues,
211 dstGreens = rXgXbX[1]*reds + rYgYbY[1]*greens + rZgZbZ[1]*blues,
212 dstBlues = rXgXbX[2]*reds + rYgYbY[2]*greens + rZgZbZ[2]*blues;
msaretta9e878c2016-06-08 14:43:53 -0700213
214 // Convert to dst gamma.
msarettd2809572016-06-20 06:07:45 -0700215 dstReds = linear_to_curve(dstReds);
216 dstGreens = linear_to_curve(dstGreens);
217 dstBlues = linear_to_curve(dstBlues);
msaretta9e878c2016-06-08 14:43:53 -0700218
mtklein64f061a2016-06-17 12:09:16 -0700219 // Clamp floats to byte range.
msarettdea03402016-06-16 10:50:55 -0700220 dstReds = clamp_0_to_255(dstReds);
221 dstGreens = clamp_0_to_255(dstGreens);
222 dstBlues = clamp_0_to_255(dstBlues);
msaretta9e878c2016-06-08 14:43:53 -0700223
224 // Convert to bytes and store to memory.
mtklein64f061a2016-06-17 12:09:16 -0700225 auto rgba = (Sk4i{(int)0xFF000000} )
226 | (SkNx_cast<int>(dstReds) )
227 | (SkNx_cast<int>(dstGreens) << 8)
228 | (SkNx_cast<int>(dstBlues) << 16);
229 rgba.store(dst);
msaretta9e878c2016-06-08 14:43:53 -0700230
231 dst += 4;
232 src += 4;
233 len -= 4;
234 }
235
msarettdea03402016-06-16 10:50:55 -0700236 while (len > 0) {
mtklein64f061a2016-06-17 12:09:16 -0700237 // Splat r,g,b across a register each.
238 auto r = Sk4f{linear_from_curve[(*src >> 0) & 0xFF]},
239 g = Sk4f{linear_from_curve[(*src >> 8) & 0xFF]},
240 b = Sk4f{linear_from_curve[(*src >> 16) & 0xFF]};
msarettdea03402016-06-16 10:50:55 -0700241
mtklein64f061a2016-06-17 12:09:16 -0700242 // Apply transformation matrix to dst gamut.
243 auto dstPixel = rXgXbX*r + rYgYbY*g + rZgZbZ*b;
msarettdea03402016-06-16 10:50:55 -0700244
245 // Convert to dst gamma.
msarettd2809572016-06-20 06:07:45 -0700246 dstPixel = linear_to_curve(dstPixel);
msarettdea03402016-06-16 10:50:55 -0700247
mtklein64f061a2016-06-17 12:09:16 -0700248 // Clamp floats to byte range.
msarettdea03402016-06-16 10:50:55 -0700249 dstPixel = clamp_0_to_255(dstPixel);
250
251 // Convert to bytes and store to memory.
mtklein64f061a2016-06-17 12:09:16 -0700252 uint32_t rgba;
253 SkNx_cast<uint8_t>(dstPixel).store(&rgba);
254 rgba |= 0xFF000000;
255 *dst = rgba;
msarettdea03402016-06-16 10:50:55 -0700256
257 dst += 1;
258 src += 1;
259 len -= 1;
260 }
msaretta9e878c2016-06-08 14:43:53 -0700261}
262
msarettdea03402016-06-16 10:50:55 -0700263static void color_xform_RGB1_srgb_to_2dot2(uint32_t* dst, const uint32_t* src, int len,
264 const float matrix[16]) {
msarettd2809572016-06-20 06:07:45 -0700265 color_xform_RGB1<linear_from_srgb, linear_to_2dot2>(dst, src, len, matrix);
msarettdea03402016-06-16 10:50:55 -0700266}
267
268static void color_xform_RGB1_2dot2_to_2dot2(uint32_t* dst, const uint32_t* src, int len,
269 const float matrix[16]) {
msarettd2809572016-06-20 06:07:45 -0700270 color_xform_RGB1<linear_from_2dot2, linear_to_2dot2>(dst, src, len, matrix);
271}
272
273static void color_xform_RGB1_srgb_to_srgb(uint32_t* dst, const uint32_t* src, int len,
274 const float matrix[16]) {
275 color_xform_RGB1<linear_from_srgb, linear_to_srgb>(dst, src, len, matrix);
276}
277
278static void color_xform_RGB1_2dot2_to_srgb(uint32_t* dst, const uint32_t* src, int len,
279 const float matrix[16]) {
280 color_xform_RGB1<linear_from_2dot2, linear_to_srgb>(dst, src, len, matrix);
msarettdea03402016-06-16 10:50:55 -0700281}
282
mtklein64f061a2016-06-17 12:09:16 -0700283} // namespace SK_OPTS_NS
msaretta9e878c2016-06-08 14:43:53 -0700284
285#endif // SkColorXform_opts_DEFINED