OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkPM4fPriv.h" | 8 #include "SkPM4fPriv.h" |
9 #include "SkUtils.h" | 9 #include "SkUtils.h" |
10 #include "SkXfermode.h" | 10 #include "SkXfermode.h" |
(...skipping 29 matching lines...) Expand all Loading... |
40 } | 40 } |
41 | 41 |
42 template <DstType D> uint32_t store_dst(const Sk4f& x4) { | 42 template <DstType D> uint32_t store_dst(const Sk4f& x4) { |
43 return (D == kSRGB_Dst) ? Sk4f_toS32(x4) : Sk4f_toL32(x4); | 43 return (D == kSRGB_Dst) ? Sk4f_toS32(x4) : Sk4f_toL32(x4); |
44 } | 44 } |
45 | 45 |
46 static Sk4f linear_unit_to_srgb_255f(const Sk4f& l4) { | 46 static Sk4f linear_unit_to_srgb_255f(const Sk4f& l4) { |
47 return linear_to_srgb(l4) * Sk4f(255) + Sk4f(0.5f); | 47 return linear_to_srgb(l4) * Sk4f(255) + Sk4f(0.5f); |
48 } | 48 } |
49 | 49 |
| 50 // Load 4 interlaced 8888 sRGB pixels as an Sk4x4f, transposed and converted to
float. |
| 51 static Sk4x4f load_4_srgb(const void* ptr) { |
| 52 auto p = Sk4x4f::Transpose((const uint8_t*)ptr); |
| 53 |
| 54 // Scale to [0,1]. |
| 55 p.r *= 1/255.0f; |
| 56 p.g *= 1/255.0f; |
| 57 p.b *= 1/255.0f; |
| 58 p.a *= 1/255.0f; |
| 59 |
| 60 // Apply approximate sRGB gamma correction to convert to linear (as if gamma
were 2). |
| 61 p.r *= p.r; |
| 62 p.g *= p.g; |
| 63 p.b *= p.b; |
| 64 |
| 65 return p; |
| 66 } |
| 67 |
| 68 // Store an Sk4x4f back to 4 interlaced 8888 sRGB pixels. |
| 69 static void store_4_srgb(void* ptr, const Sk4x4f& p) { |
| 70 // Convert back to sRGB and [0,255], again approximating sRGB as gamma == 2. |
| 71 auto r = p.r.sqrt() * 255.0f + 0.5f, |
| 72 g = p.g.sqrt() * 255.0f + 0.5f, |
| 73 b = p.b.sqrt() * 255.0f + 0.5f, |
| 74 a = p.a * 255.0f + 0.5f; |
| 75 Sk4x4f{r,g,b,a}.transpose((uint8_t*)ptr); |
| 76 } |
| 77 |
50 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 78 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
51 | 79 |
52 template <DstType D> void general_1(const SkXfermode* xfer, uint32_t dst[], | 80 template <DstType D> void general_1(const SkXfermode* xfer, uint32_t dst[], |
53 const SkPM4f* src, int count, const SkAlpha
aa[]) { | 81 const SkPM4f* src, int count, const SkAlpha
aa[]) { |
54 const SkPM4f s = rgba_to_pmcolor_order(*src); | 82 const SkPM4f s = rgba_to_pmcolor_order(*src); |
55 SkXfermodeProc4f proc = xfer->getProc4f(); | 83 SkXfermodeProc4f proc = xfer->getProc4f(); |
56 SkPM4f d; | 84 SkPM4f d; |
57 if (aa) { | 85 if (aa) { |
58 for (int i = 0; i < count; ++i) { | 86 for (int i = 0; i < count; ++i) { |
59 Sk4f d4 = load_dst<D>(dst[i]); | 87 Sk4f d4 = load_dst<D>(dst[i]); |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
228 | 256 |
229 static void dst(const SkXfermode*, uint32_t dst[], const SkPM4f[], int count, co
nst SkAlpha aa[]) {} | 257 static void dst(const SkXfermode*, uint32_t dst[], const SkPM4f[], int count, co
nst SkAlpha aa[]) {} |
230 | 258 |
231 const SkXfermode::D32Proc gProcs_Dst[] = { | 259 const SkXfermode::D32Proc gProcs_Dst[] = { |
232 dst, dst, dst, dst, dst, dst, dst, dst, | 260 dst, dst, dst, dst, dst, dst, dst, dst, |
233 }; | 261 }; |
234 | 262 |
235 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 263 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
236 | 264 |
237 | 265 |
238 static void srcover_n_srgb_bw(uint32_t dst[], const SkPM4f src[], int count) { | |
239 while (count >= 4) { | |
240 // Load 4 sRGB RGBA/BGRA 8888 dst pixels. | |
241 // We'll write most of this as if they're RGBA, and just swizzle the src
pixels to match. | |
242 auto d = Sk4x4f::Transpose((const uint8_t*)dst); | |
243 | |
244 // Scale to [0,1]. | |
245 d.r *= 1/255.0f; | |
246 d.g *= 1/255.0f; | |
247 d.b *= 1/255.0f; | |
248 d.a *= 1/255.0f; | |
249 | |
250 // Apply approximate sRGB gamma correction to convert to linear (as if g
amma were 2). | |
251 d.r *= d.r; | |
252 d.g *= d.g; | |
253 d.b *= d.b; | |
254 | |
255 // Load 4 linear float src pixels. | |
256 auto s = Sk4x4f::Transpose(src->fVec); | |
257 | |
258 // Match color order with destination, if necessary. | |
259 #if defined(SK_PMCOLOR_IS_BGRA) | |
260 SkTSwap(s.r, s.b); | |
261 #endif | |
262 | |
263 // Now, the meat of what we wanted to do... perform the srcover blend. | |
264 auto invSA = 1.0f - s.a; | |
265 auto r = s.r + d.r * invSA, | |
266 g = s.g + d.g * invSA, | |
267 b = s.b + d.b * invSA, | |
268 a = s.a + d.a * invSA; | |
269 | |
270 // Convert back to sRGB and [0,255], again approximating sRGB as gamma =
= 2. | |
271 r = r.sqrt() * 255.0f + 0.5f; | |
272 g = g.sqrt() * 255.0f + 0.5f; | |
273 b = b.sqrt() * 255.0f + 0.5f; | |
274 a = a * 255.0f + 0.5f; | |
275 | |
276 Sk4x4f{r,g,b,a}.transpose((uint8_t*)dst); | |
277 | |
278 count -= 4; | |
279 dst += 4; | |
280 src += 4; | |
281 } | |
282 | |
283 // This should look just like the non-specialized case in srcover_n. | |
284 for (int i = 0; i < count; ++i) { | |
285 Sk4f s4 = src[i].to4f_pmorder(); | |
286 Sk4f d4 = load_dst<kSRGB_Dst>(dst[i]); | |
287 Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4)); | |
288 dst[i] = store_dst<kSRGB_Dst>(r4); | |
289 } | |
290 } | |
291 | |
292 template <DstType D> void srcover_n(const SkXfermode*, uint32_t dst[], | 266 template <DstType D> void srcover_n(const SkXfermode*, uint32_t dst[], |
293 const SkPM4f src[], int count, const SkAlpha
aa[]) { | 267 const SkPM4f src[], int count, const SkAlpha
aa[]) { |
294 if (aa) { | 268 if (aa) { |
295 for (int i = 0; i < count; ++i) { | 269 for (int i = 0; i < count; ++i) { |
296 unsigned a = aa[i]; | 270 unsigned a = aa[i]; |
297 if (0 == a) { | 271 if (0 == a) { |
298 continue; | 272 continue; |
299 } | 273 } |
300 Sk4f s4 = src[i].to4f_pmorder(); | 274 Sk4f s4 = src[i].to4f_pmorder(); |
301 Sk4f d4 = load_dst<D>(dst[i]); | 275 Sk4f d4 = load_dst<D>(dst[i]); |
302 if (a != 0xFF) { | 276 if (a != 0xFF) { |
303 s4 = scale_by_coverage(s4, a); | 277 s4 = scale_by_coverage(s4, a); |
304 } | 278 } |
305 Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4)); | 279 Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4)); |
306 dst[i] = store_dst<D>(r4); | 280 dst[i] = store_dst<D>(r4); |
307 } | 281 } |
308 } else { | 282 } else { |
309 if (D == kSRGB_Dst) { | 283 while (count >= 4 && D == kSRGB_Dst) { |
310 srcover_n_srgb_bw(dst, src, count); | 284 auto d = load_4_srgb(dst); |
311 } else { | 285 |
312 for (int i = 0; i < count; ++i) { | 286 auto s = Sk4x4f::Transpose(src->fVec); |
313 Sk4f s4 = src[i].to4f_pmorder(); | 287 #if defined(SK_PMCOLOR_IS_BGRA) |
314 Sk4f d4 = load_dst<D>(dst[i]); | 288 SkTSwap(s.r, s.b); |
315 Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4)); | 289 #endif |
316 dst[i] = store_dst<D>(r4); | 290 |
317 } | 291 auto invSA = 1.0f - s.a; |
| 292 auto r = s.r + d.r * invSA, |
| 293 g = s.g + d.g * invSA, |
| 294 b = s.b + d.b * invSA, |
| 295 a = s.a + d.a * invSA; |
| 296 |
| 297 store_4_srgb(dst, Sk4x4f{r,g,b,a}); |
| 298 count -= 4; |
| 299 dst += 4; |
| 300 src += 4; |
| 301 } |
| 302 for (int i = 0; i < count; ++i) { |
| 303 Sk4f s4 = src[i].to4f_pmorder(); |
| 304 Sk4f d4 = load_dst<D>(dst[i]); |
| 305 Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4)); |
| 306 dst[i] = store_dst<D>(r4); |
318 } | 307 } |
319 } | 308 } |
320 } | 309 } |
321 | 310 |
322 static void srcover_linear_dst_1(const SkXfermode*, uint32_t dst[], | 311 static void srcover_linear_dst_1(const SkXfermode*, uint32_t dst[], |
323 const SkPM4f* src, int count, const SkAlpha aa[
]) { | 312 const SkPM4f* src, int count, const SkAlpha aa[
]) { |
324 const Sk4f s4 = src->to4f_pmorder(); | 313 const Sk4f s4 = src->to4f_pmorder(); |
325 const Sk4f dst_scale = Sk4f(1 - get_alpha(s4)); | 314 const Sk4f dst_scale = Sk4f(1 - get_alpha(s4)); |
326 | 315 |
327 if (aa) { | 316 if (aa) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 if (a != 0xFF) { | 367 if (a != 0xFF) { |
379 const Sk4f s4_aa = scale_by_coverage(s4, a); | 368 const Sk4f s4_aa = scale_by_coverage(s4, a); |
380 r4 = s4_aa + d4 * Sk4f(1 - get_alpha(s4_aa)); | 369 r4 = s4_aa + d4 * Sk4f(1 - get_alpha(s4_aa)); |
381 } else { | 370 } else { |
382 r4 = s4 + d4 * dst_scale; | 371 r4 = s4 + d4 * dst_scale; |
383 } | 372 } |
384 dst[i] = to_4b(linear_unit_to_srgb_255f(r4)); | 373 dst[i] = to_4b(linear_unit_to_srgb_255f(r4)); |
385 } | 374 } |
386 } else { | 375 } else { |
387 while (count >= 4) { | 376 while (count >= 4) { |
388 Sk4f d0 = srgb_4b_to_linear_unit(dst[0]); | 377 auto d = load_4_srgb(dst); |
389 Sk4f d1 = srgb_4b_to_linear_unit(dst[1]); | 378 |
390 Sk4f d2 = srgb_4b_to_linear_unit(dst[2]); | 379 auto s = Sk4x4f{{ src->r() }, { src->g() }, { src->b() }, { src->a()
}}; |
391 Sk4f d3 = srgb_4b_to_linear_unit(dst[3]); | 380 #if defined(SK_PMCOLOR_IS_BGRA) |
392 Sk4f_ToBytes((uint8_t*)dst, | 381 SkTSwap(s.r, s.b); |
393 linear_unit_to_srgb_255f(s4 + d0 * dst_scale), | 382 #endif |
394 linear_unit_to_srgb_255f(s4 + d1 * dst_scale), | 383 |
395 linear_unit_to_srgb_255f(s4 + d2 * dst_scale), | 384 auto invSA = 1.0f - s.a; |
396 linear_unit_to_srgb_255f(s4 + d3 * dst_scale)); | 385 auto r = s.r + d.r * invSA, |
| 386 g = s.g + d.g * invSA, |
| 387 b = s.b + d.b * invSA, |
| 388 a = s.a + d.a * invSA; |
| 389 |
| 390 store_4_srgb(dst, Sk4x4f{r,g,b,a}); |
| 391 count -= 4; |
397 dst += 4; | 392 dst += 4; |
398 count -= 4; | |
399 } | 393 } |
400 for (int i = 0; i < count; ++i) { | 394 for (int i = 0; i < count; ++i) { |
401 Sk4f d4 = srgb_4b_to_linear_unit(dst[i]); | 395 Sk4f d4 = srgb_4b_to_linear_unit(dst[i]); |
402 dst[i] = to_4b(linear_unit_to_srgb_255f(s4 + d4 * dst_scale)); | 396 dst[i] = to_4b(linear_unit_to_srgb_255f(s4 + d4 * dst_scale)); |
403 } | 397 } |
404 } | 398 } |
405 } | 399 } |
406 | 400 |
407 const SkXfermode::D32Proc gProcs_SrcOver[] = { | 401 const SkXfermode::D32Proc gProcs_SrcOver[] = { |
408 srcover_n<kLinear_Dst>, src_n<kLinear_Dst>, | 402 srcover_n<kLinear_Dst>, src_n<kLinear_Dst>, |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
532 | 526 |
533 const LCD32Proc procs[] = { | 527 const LCD32Proc procs[] = { |
534 srcover_n_lcd<kSRGB_Dst>, src_n_lcd<kSRGB_Dst>, | 528 srcover_n_lcd<kSRGB_Dst>, src_n_lcd<kSRGB_Dst>, |
535 srcover_1_lcd<kSRGB_Dst>, src_1_lcd<kSRGB_Dst>, | 529 srcover_1_lcd<kSRGB_Dst>, src_1_lcd<kSRGB_Dst>, |
536 | 530 |
537 srcover_n_lcd<kLinear_Dst>, src_n_lcd<kLinear_Dst>, | 531 srcover_n_lcd<kLinear_Dst>, src_n_lcd<kLinear_Dst>, |
538 srcover_1_lcd<kLinear_Dst>, src_1_lcd<kLinear_Dst>, | 532 srcover_1_lcd<kLinear_Dst>, src_1_lcd<kLinear_Dst>, |
539 }; | 533 }; |
540 return procs[flags]; | 534 return procs[flags]; |
541 } | 535 } |
OLD | NEW |