Line data Source code
1 : /*
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 "SkPM4fPriv.h"
9 : #include "SkUtils.h"
10 : #include "SkXfermodePriv.h"
11 : #include "Sk4x4f.h"
12 :
13 0 : static SkPM4f rgba_to_pmcolor_order(const SkPM4f& x) {
14 : #ifdef SK_PMCOLOR_IS_BGRA
15 0 : return {{ x.fVec[2], x.fVec[1], x.fVec[0], x.fVec[3] }};
16 : #else
17 : return x;
18 : #endif
19 : }
20 :
21 : enum DstType {
22 : kLinear_Dst,
23 : kSRGB_Dst,
24 : };
25 :
26 0 : static Sk4f scale_by_coverage(const Sk4f& x4, uint8_t coverage) {
27 0 : return x4 * Sk4f(coverage * (1/255.0f));
28 : }
29 :
30 0 : static Sk4f lerp(const Sk4f& src, const Sk4f& dst, uint8_t srcCoverage) {
31 0 : return dst + (src - dst) * Sk4f(srcCoverage * (1/255.0f));
32 : }
33 :
34 0 : template <DstType D> Sk4f load_dst(SkPMColor dstC) {
35 0 : return (D == kSRGB_Dst) ? Sk4f_fromS32(dstC) : Sk4f_fromL32(dstC);
36 : }
37 :
38 0 : template <DstType D> uint32_t store_dst(const Sk4f& x4) {
39 0 : return (D == kSRGB_Dst) ? Sk4f_toS32(x4) : Sk4f_toL32(x4);
40 : }
41 :
42 0 : static Sk4x4f load_4_srgb(const void* vptr) {
43 0 : auto ptr = (const uint32_t*)vptr;
44 :
45 0 : Sk4x4f rgba;
46 :
47 0 : rgba.r = { sk_linear_from_srgb[(ptr[0] >> 0) & 0xff],
48 0 : sk_linear_from_srgb[(ptr[1] >> 0) & 0xff],
49 0 : sk_linear_from_srgb[(ptr[2] >> 0) & 0xff],
50 0 : sk_linear_from_srgb[(ptr[3] >> 0) & 0xff] };
51 :
52 0 : rgba.g = { sk_linear_from_srgb[(ptr[0] >> 8) & 0xff],
53 0 : sk_linear_from_srgb[(ptr[1] >> 8) & 0xff],
54 0 : sk_linear_from_srgb[(ptr[2] >> 8) & 0xff],
55 0 : sk_linear_from_srgb[(ptr[3] >> 8) & 0xff] };
56 :
57 0 : rgba.b = { sk_linear_from_srgb[(ptr[0] >> 16) & 0xff],
58 0 : sk_linear_from_srgb[(ptr[1] >> 16) & 0xff],
59 0 : sk_linear_from_srgb[(ptr[2] >> 16) & 0xff],
60 0 : sk_linear_from_srgb[(ptr[3] >> 16) & 0xff] };
61 :
62 0 : rgba.a = SkNx_cast<float>((Sk4i::Load(ptr) >> 24) & 0xff) * (1/255.0f);
63 :
64 0 : return rgba;
65 : }
66 :
67 0 : static void store_4_srgb(void* ptr, const Sk4x4f& p) {
68 0 : ( sk_linear_to_srgb(p.r) << 0
69 0 : | sk_linear_to_srgb(p.g) << 8
70 0 : | sk_linear_to_srgb(p.b) << 16
71 0 : | Sk4f_round(255.0f*p.a) << 24).store(ptr);
72 0 : }
73 :
74 : ///////////////////////////////////////////////////////////////////////////////////////////////////
75 :
76 0 : template <DstType D> void general_1(SkBlendMode mode, uint32_t dst[],
77 : const SkPM4f* src, int count, const SkAlpha aa[]) {
78 0 : const SkPM4f s = rgba_to_pmcolor_order(*src);
79 0 : SkXfermodeProc4f proc = SkXfermode::GetProc4f(mode);
80 : SkPM4f d;
81 0 : if (aa) {
82 0 : for (int i = 0; i < count; ++i) {
83 0 : Sk4f d4 = load_dst<D>(dst[i]);
84 : d4.store(d.fVec);
85 0 : Sk4f r4 = Sk4f::Load(proc(s, d).fVec);
86 0 : dst[i] = store_dst<D>(lerp(r4, d4, aa[i]));
87 : }
88 : } else {
89 0 : for (int i = 0; i < count; ++i) {
90 0 : load_dst<D>(dst[i]).store(d.fVec);
91 0 : Sk4f r4 = Sk4f::Load(proc(s, d).fVec);
92 0 : dst[i] = store_dst<D>(r4);
93 : }
94 : }
95 0 : }
96 :
97 0 : template <DstType D> void general_n(SkBlendMode mode, uint32_t dst[],
98 : const SkPM4f src[], int count, const SkAlpha aa[]) {
99 0 : SkXfermodeProc4f proc = SkXfermode::GetProc4f(mode);
100 : SkPM4f d;
101 0 : if (aa) {
102 0 : for (int i = 0; i < count; ++i) {
103 0 : Sk4f d4 = load_dst<D>(dst[i]);
104 : d4.store(d.fVec);
105 0 : Sk4f r4 = Sk4f::Load(proc(rgba_to_pmcolor_order(src[i]), d).fVec);
106 0 : dst[i] = store_dst<D>(lerp(r4, d4, aa[i]));
107 : }
108 : } else {
109 0 : for (int i = 0; i < count; ++i) {
110 0 : load_dst<D>(dst[i]).store(d.fVec);
111 0 : Sk4f r4 = Sk4f::Load(proc(rgba_to_pmcolor_order(src[i]), d).fVec);
112 0 : dst[i] = store_dst<D>(r4);
113 : }
114 : }
115 0 : }
116 :
117 : const SkXfermode::D32Proc gProcs_General[] = {
118 : general_n<kLinear_Dst>, general_n<kLinear_Dst>,
119 : general_1<kLinear_Dst>, general_1<kLinear_Dst>,
120 : general_n<kSRGB_Dst>, general_n<kSRGB_Dst>,
121 : general_1<kSRGB_Dst>, general_1<kSRGB_Dst>,
122 : };
123 :
124 : ///////////////////////////////////////////////////////////////////////////////////////////////////
125 :
126 0 : static void clear_linear(SkBlendMode, uint32_t dst[], const SkPM4f[], int count,
127 : const SkAlpha aa[]) {
128 0 : if (aa) {
129 0 : for (int i = 0; i < count; ++i) {
130 0 : unsigned a = aa[i];
131 0 : if (a) {
132 0 : SkPMColor dstC = dst[i];
133 0 : SkPMColor C = 0;
134 0 : if (0xFF != a) {
135 0 : C = SkFourByteInterp(C, dstC, a);
136 : }
137 0 : dst[i] = C;
138 : }
139 : }
140 : } else {
141 0 : sk_memset32(dst, 0, count);
142 : }
143 0 : }
144 :
145 0 : static void clear_srgb(SkBlendMode, uint32_t dst[], const SkPM4f[], int count, const SkAlpha aa[]) {
146 0 : if (aa) {
147 0 : for (int i = 0; i < count; ++i) {
148 0 : if (aa[i]) {
149 0 : Sk4f d = Sk4f_fromS32(dst[i]) * Sk4f((255 - aa[i]) * (1/255.0f));
150 0 : dst[i] = Sk4f_toS32(d);
151 : }
152 : }
153 : } else {
154 0 : sk_memset32(dst, 0, count);
155 : }
156 0 : }
157 :
158 : const SkXfermode::D32Proc gProcs_Clear[] = {
159 : clear_linear, clear_linear,
160 : clear_linear, clear_linear,
161 : clear_srgb, clear_srgb,
162 : clear_srgb, clear_srgb,
163 : };
164 :
165 : ///////////////////////////////////////////////////////////////////////////////////////////////////
166 :
167 0 : template <DstType D> void src_n(SkBlendMode, uint32_t dst[], const SkPM4f src[], int count,
168 : const SkAlpha aa[]) {
169 0 : for (int i = 0; i < count; ++i) {
170 0 : unsigned a = 0xFF;
171 0 : if (aa) {
172 0 : a = aa[i];
173 0 : if (0 == a) {
174 0 : continue;
175 : }
176 : }
177 0 : Sk4f r4 = src[i].to4f_pmorder();
178 0 : if (a != 0xFF) {
179 0 : Sk4f d4 = load_dst<D>(dst[i]);
180 0 : r4 = lerp(r4, d4, a);
181 : }
182 0 : dst[i] = store_dst<D>(r4);
183 : }
184 0 : }
185 :
186 0 : static Sk4f lerp(const Sk4f& src, const Sk4f& dst, const Sk4f& src_scale) {
187 0 : return dst + (src - dst) * src_scale;
188 : }
189 :
190 0 : template <DstType D> void src_1(SkBlendMode, uint32_t dst[], const SkPM4f* src, int count,
191 : const SkAlpha aa[]) {
192 0 : const Sk4f s4 = src->to4f_pmorder();
193 :
194 0 : if (aa) {
195 0 : SkPMColor srcColor = store_dst<D>(s4);
196 0 : while (count-- > 0) {
197 0 : SkAlpha cover = *aa++;
198 0 : switch (cover) {
199 : case 0xFF: {
200 0 : *dst++ = srcColor;
201 0 : break;
202 : }
203 : case 0x00: {
204 0 : dst++;
205 0 : break;
206 : }
207 : default: {
208 0 : Sk4f d4 = load_dst<D>(*dst);
209 0 : *dst++ = store_dst<D>(lerp(s4, d4, cover));
210 : }
211 : }
212 : }
213 : } else {
214 0 : sk_memset32(dst, store_dst<D>(s4), count);
215 : }
216 0 : }
217 :
218 : const SkXfermode::D32Proc gProcs_Src[] = {
219 : src_n<kLinear_Dst>, src_n<kLinear_Dst>,
220 : src_1<kLinear_Dst>, src_1<kLinear_Dst>,
221 : src_n<kSRGB_Dst>, src_n<kSRGB_Dst>,
222 : src_1<kSRGB_Dst>, src_1<kSRGB_Dst>,
223 : };
224 :
225 : ///////////////////////////////////////////////////////////////////////////////////////////////////
226 :
227 0 : static void dst(SkBlendMode, uint32_t dst[], const SkPM4f[], int count, const SkAlpha aa[]) {}
228 :
229 : const SkXfermode::D32Proc gProcs_Dst[] = {
230 : dst, dst, dst, dst, dst, dst, dst, dst,
231 : };
232 :
233 : ///////////////////////////////////////////////////////////////////////////////////////////////////
234 :
235 :
236 0 : template <DstType D> void srcover_n(SkBlendMode, uint32_t dst[], const SkPM4f src[], int count,
237 : const SkAlpha aa[]) {
238 0 : if (aa) {
239 0 : for (int i = 0; i < count; ++i) {
240 0 : unsigned a = aa[i];
241 0 : if (0 == a) {
242 0 : continue;
243 : }
244 0 : Sk4f s4 = src[i].to4f_pmorder();
245 0 : Sk4f d4 = load_dst<D>(dst[i]);
246 0 : if (a != 0xFF) {
247 0 : s4 = scale_by_coverage(s4, a);
248 : }
249 0 : Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4));
250 0 : dst[i] = store_dst<D>(r4);
251 : }
252 : } else {
253 0 : while (count >= 4 && D == kSRGB_Dst) {
254 0 : auto d = load_4_srgb(dst);
255 0 : auto s = Sk4x4f::Transpose(src->fVec);
256 : #if defined(SK_PMCOLOR_IS_BGRA)
257 0 : SkTSwap(s.r, s.b);
258 : #endif
259 0 : auto invSA = 1.0f - s.a;
260 0 : auto r = s.r + d.r * invSA,
261 0 : g = s.g + d.g * invSA,
262 0 : b = s.b + d.b * invSA,
263 0 : a = s.a + d.a * invSA;
264 0 : store_4_srgb(dst, Sk4x4f{r,g,b,a});
265 0 : count -= 4;
266 0 : dst += 4;
267 0 : src += 4;
268 : }
269 0 : for (int i = 0; i < count; ++i) {
270 0 : Sk4f s4 = src[i].to4f_pmorder();
271 0 : Sk4f d4 = load_dst<D>(dst[i]);
272 0 : Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4));
273 0 : dst[i] = store_dst<D>(r4);
274 : }
275 : }
276 0 : }
277 :
278 0 : static void srcover_linear_dst_1(SkBlendMode, uint32_t dst[], const SkPM4f* src, int count,
279 : const SkAlpha aa[]) {
280 0 : const Sk4f s4 = src->to4f_pmorder();
281 0 : const Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
282 :
283 0 : if (aa) {
284 0 : for (int i = 0; i < count; ++i) {
285 0 : unsigned a = aa[i];
286 0 : if (0 == a) {
287 0 : continue;
288 : }
289 0 : Sk4f d4 = Sk4f_fromL32(dst[i]);
290 : Sk4f r4;
291 0 : if (a != 0xFF) {
292 0 : Sk4f s4_aa = scale_by_coverage(s4, a);
293 0 : r4 = s4_aa + d4 * Sk4f(1 - get_alpha(s4_aa));
294 : } else {
295 0 : r4 = s4 + d4 * dst_scale;
296 : }
297 0 : dst[i] = Sk4f_toL32(r4);
298 : }
299 : } else {
300 0 : for (int i = 0; i < count; ++i) {
301 0 : Sk4f d4 = Sk4f_fromL32(dst[i]);
302 0 : dst[i] = Sk4f_toL32(s4 + d4 * dst_scale);
303 : }
304 : }
305 0 : }
306 :
307 0 : static void srcover_srgb_dst_1(SkBlendMode, uint32_t dst[], const SkPM4f* src, int count,
308 : const SkAlpha aa[]) {
309 0 : Sk4f s4 = src->to4f_pmorder();
310 0 : Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
311 :
312 0 : if (aa) {
313 0 : for (int i = 0; i < count; ++i) {
314 0 : unsigned a = aa[i];
315 0 : if (0 == a) {
316 0 : continue;
317 : }
318 :
319 0 : Sk4f d4 = Sk4f_fromS32(dst[i]);
320 : Sk4f r4;
321 0 : if (a != 0xFF) {
322 0 : const Sk4f s4_aa = scale_by_coverage(s4, a);
323 0 : r4 = s4_aa + d4 * Sk4f(1 - get_alpha(s4_aa));
324 : } else {
325 0 : r4 = s4 + d4 * dst_scale;
326 : }
327 0 : dst[i] = Sk4f_toS32(r4);
328 : }
329 : } else {
330 0 : while (count >= 4) {
331 0 : auto d = load_4_srgb(dst);
332 0 : auto s = Sk4x4f{{ src->r() }, { src->g() }, { src->b() }, { src->a() }};
333 : #if defined(SK_PMCOLOR_IS_BGRA)
334 0 : SkTSwap(s.r, s.b);
335 : #endif
336 0 : auto invSA = 1.0f - s.a;
337 0 : auto r = s.r + d.r * invSA,
338 0 : g = s.g + d.g * invSA,
339 0 : b = s.b + d.b * invSA,
340 0 : a = s.a + d.a * invSA;
341 0 : store_4_srgb(dst, Sk4x4f{r,g,b,a});
342 0 : count -= 4;
343 0 : dst += 4;
344 : }
345 0 : for (int i = 0; i < count; ++i) {
346 0 : Sk4f d4 = Sk4f_fromS32(dst[i]);
347 0 : dst[i] = Sk4f_toS32(s4 + d4 * dst_scale);
348 : }
349 : }
350 0 : }
351 :
352 : const SkXfermode::D32Proc gProcs_SrcOver[] = {
353 : srcover_n<kLinear_Dst>, src_n<kLinear_Dst>,
354 : srcover_linear_dst_1, src_1<kLinear_Dst>,
355 :
356 : srcover_n<kSRGB_Dst>, src_n<kSRGB_Dst>,
357 : srcover_srgb_dst_1, src_1<kSRGB_Dst>,
358 : };
359 :
360 : ///////////////////////////////////////////////////////////////////////////////////////////////////
361 :
362 0 : SkXfermode::D32Proc SkXfermode::GetD32Proc(SkBlendMode mode, uint32_t flags) {
363 0 : SkASSERT(0 == (flags & ~7));
364 0 : flags &= 7;
365 :
366 0 : switch (mode) {
367 0 : case SkBlendMode::kClear: return gProcs_Clear[flags];
368 0 : case SkBlendMode::kSrc: return gProcs_Src[flags];
369 0 : case SkBlendMode::kDst: return gProcs_Dst[flags];
370 0 : case SkBlendMode::kSrcOver: return gProcs_SrcOver[flags];
371 : default:
372 0 : break;
373 : }
374 0 : return gProcs_General[flags];
375 : }
376 :
377 : ///////////////////////////////////////////////////////////////////////////////////////////////////
378 : #include "SkColorPriv.h"
379 :
380 0 : static Sk4f lcd16_to_unit_4f(uint16_t rgb) {
381 : #ifdef SK_PMCOLOR_IS_RGBA
382 : Sk4i rgbi = Sk4i(SkGetPackedR16(rgb), SkGetPackedG16(rgb), SkGetPackedB16(rgb), 0);
383 : #else
384 0 : Sk4i rgbi = Sk4i(SkGetPackedB16(rgb), SkGetPackedG16(rgb), SkGetPackedR16(rgb), 0);
385 : #endif
386 0 : return SkNx_cast<float>(rgbi) * Sk4f(1.0f/31, 1.0f/63, 1.0f/31, 0);
387 : }
388 :
389 : template <DstType D>
390 0 : void src_1_lcd(uint32_t dst[], const SkPM4f* src, int count, const uint16_t lcd[]) {
391 0 : const Sk4f s4 = src->to4f_pmorder();
392 :
393 0 : for (int i = 0; i < count; ++i) {
394 0 : uint16_t rgb = lcd[i];
395 0 : if (0 == rgb) {
396 0 : continue;
397 : }
398 0 : Sk4f d4 = load_dst<D>(dst[i]);
399 0 : dst[i] = store_dst<D>(lerp(s4, d4, lcd16_to_unit_4f(rgb))) | (SK_A32_MASK << SK_A32_SHIFT);
400 : }
401 0 : }
402 :
403 : template <DstType D>
404 0 : void src_n_lcd(uint32_t dst[], const SkPM4f src[], int count, const uint16_t lcd[]) {
405 0 : for (int i = 0; i < count; ++i) {
406 0 : uint16_t rgb = lcd[i];
407 0 : if (0 == rgb) {
408 0 : continue;
409 : }
410 0 : Sk4f s4 = src[i].to4f_pmorder();
411 0 : Sk4f d4 = load_dst<D>(dst[i]);
412 0 : dst[i] = store_dst<D>(lerp(s4, d4, lcd16_to_unit_4f(rgb))) | (SK_A32_MASK << SK_A32_SHIFT);
413 : }
414 0 : }
415 :
416 : template <DstType D>
417 0 : void srcover_1_lcd(uint32_t dst[], const SkPM4f* src, int count, const uint16_t lcd[]) {
418 0 : const Sk4f s4 = src->to4f_pmorder();
419 0 : Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
420 :
421 0 : for (int i = 0; i < count; ++i) {
422 0 : uint16_t rgb = lcd[i];
423 0 : if (0 == rgb) {
424 0 : continue;
425 : }
426 0 : Sk4f d4 = load_dst<D>(dst[i]);
427 0 : Sk4f r4 = s4 + d4 * dst_scale;
428 0 : r4 = lerp(r4, d4, lcd16_to_unit_4f(rgb));
429 0 : dst[i] = store_dst<D>(r4) | (SK_A32_MASK << SK_A32_SHIFT);
430 : }
431 0 : }
432 :
433 : template <DstType D>
434 0 : void srcover_n_lcd(uint32_t dst[], const SkPM4f src[], int count, const uint16_t lcd[]) {
435 0 : for (int i = 0; i < count; ++i) {
436 0 : uint16_t rgb = lcd[i];
437 0 : if (0 == rgb) {
438 0 : continue;
439 : }
440 0 : Sk4f s4 = src[i].to4f_pmorder();
441 0 : Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
442 0 : Sk4f d4 = load_dst<D>(dst[i]);
443 0 : Sk4f r4 = s4 + d4 * dst_scale;
444 0 : r4 = lerp(r4, d4, lcd16_to_unit_4f(rgb));
445 0 : dst[i] = store_dst<D>(r4) | (SK_A32_MASK << SK_A32_SHIFT);
446 : }
447 0 : }
448 :
449 0 : SkXfermode::LCD32Proc SkXfermode::GetLCD32Proc(uint32_t flags) {
450 0 : SkASSERT((flags & ~7) == 0);
451 0 : flags &= 7;
452 :
453 : const LCD32Proc procs[] = {
454 : srcover_n_lcd<kLinear_Dst>, src_n_lcd<kLinear_Dst>,
455 : srcover_1_lcd<kLinear_Dst>, src_1_lcd<kLinear_Dst>,
456 :
457 : srcover_n_lcd<kSRGB_Dst>, src_n_lcd<kSRGB_Dst>,
458 : srcover_1_lcd<kSRGB_Dst>, src_1_lcd<kSRGB_Dst>,
459 0 : };
460 0 : return procs[flags];
461 : }
|