1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#ifndef Sk4pxXfermode_DEFINED 9cb93a386Sopenharmony_ci#define Sk4pxXfermode_DEFINED 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include "include/private/SkNx.h" 12cb93a386Sopenharmony_ci#include "src/core/Sk4px.h" 13cb93a386Sopenharmony_ci#include "src/core/SkMSAN.h" 14cb93a386Sopenharmony_ci#include "src/core/SkXfermodePriv.h" 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_ci#ifdef SK_FORCE_RASTER_PIPELINE_BLITTER 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_cinamespace SK_OPTS_NS { 19cb93a386Sopenharmony_ci /*not static*/ inline SkXfermode* create_xfermode(SkBlendMode) { return nullptr; } 20cb93a386Sopenharmony_ci} 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ci#else 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_cinamespace { // NOLINT(google-build-namespaces) 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci// Most xfermodes can be done most efficiently 4 pixels at a time in 8 or 16-bit fixed point. 27cb93a386Sopenharmony_ci#define XFERMODE(Xfermode) \ 28cb93a386Sopenharmony_ci struct Xfermode { Sk4px operator()(const Sk4px&, const Sk4px&) const; }; \ 29cb93a386Sopenharmony_ci inline Sk4px Xfermode::operator()(const Sk4px& d, const Sk4px& s) const 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ciXFERMODE(Clear) { return Sk4px::DupPMColor(0); } 32cb93a386Sopenharmony_ciXFERMODE(Src) { return s; } 33cb93a386Sopenharmony_ciXFERMODE(Dst) { return d; } 34cb93a386Sopenharmony_ciXFERMODE(SrcIn) { return s.approxMulDiv255(d.alphas() ); } 35cb93a386Sopenharmony_ciXFERMODE(SrcOut) { return s.approxMulDiv255(d.alphas().inv()); } 36cb93a386Sopenharmony_ciXFERMODE(SrcOver) { return s + d.approxMulDiv255(s.alphas().inv()); } 37cb93a386Sopenharmony_ciXFERMODE(DstIn) { return SrcIn ()(s,d); } 38cb93a386Sopenharmony_ciXFERMODE(DstOut) { return SrcOut ()(s,d); } 39cb93a386Sopenharmony_ciXFERMODE(DstOver) { return SrcOver()(s,d); } 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci// [ S * Da + (1 - Sa) * D] 42cb93a386Sopenharmony_ciXFERMODE(SrcATop) { return (s * d.alphas() + d * s.alphas().inv()).div255(); } 43cb93a386Sopenharmony_ciXFERMODE(DstATop) { return SrcATop()(s,d); } 44cb93a386Sopenharmony_ci//[ S * (1 - Da) + (1 - Sa) * D ] 45cb93a386Sopenharmony_ciXFERMODE(Xor) { return (s * d.alphas().inv() + d * s.alphas().inv()).div255(); } 46cb93a386Sopenharmony_ci// [S + D ] 47cb93a386Sopenharmony_ciXFERMODE(Plus) { return s.saturatedAdd(d); } 48cb93a386Sopenharmony_ci// [S * D ] 49cb93a386Sopenharmony_ciXFERMODE(Modulate) { return s.approxMulDiv255(d); } 50cb93a386Sopenharmony_ci// [S + D - S * D] 51cb93a386Sopenharmony_ciXFERMODE(Screen) { 52cb93a386Sopenharmony_ci // Doing the math as S + (1-S)*D or S + (D - S*D) means the add and subtract can be done 53cb93a386Sopenharmony_ci // in 8-bit space without overflow. S + (1-S)*D is a touch faster because inv() is cheap. 54cb93a386Sopenharmony_ci return s + d.approxMulDiv255(s.inv()); 55cb93a386Sopenharmony_ci} 56cb93a386Sopenharmony_ci 57cb93a386Sopenharmony_ci#undef XFERMODE 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci// A reasonable fallback mode for doing AA is to simply apply the transfermode first, 60cb93a386Sopenharmony_ci// then linearly interpolate the AA. 61cb93a386Sopenharmony_citemplate <typename Xfermode> 62cb93a386Sopenharmony_cistatic Sk4px xfer_aa(const Sk4px& d, const Sk4px& s, const Sk4px& aa) { 63cb93a386Sopenharmony_ci Sk4px bw = Xfermode()(d, s); 64cb93a386Sopenharmony_ci return (bw * aa + d * aa.inv()).div255(); 65cb93a386Sopenharmony_ci} 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci// For some transfermodes we specialize AA, either for correctness or performance. 68cb93a386Sopenharmony_ci#define XFERMODE_AA(Xfermode) \ 69cb93a386Sopenharmony_ci template <> inline Sk4px xfer_aa<Xfermode>(const Sk4px& d, const Sk4px& s, const Sk4px& aa) 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci// Plus' clamp needs to happen after AA. skia:3852 72cb93a386Sopenharmony_ciXFERMODE_AA(Plus) { // [ clamp( (1-AA)D + (AA)(S+D) ) == clamp(D + AA*S) ] 73cb93a386Sopenharmony_ci return d.saturatedAdd(s.approxMulDiv255(aa)); 74cb93a386Sopenharmony_ci} 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci#undef XFERMODE_AA 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ci// Src and Clear modes are safe to use with uninitialized dst buffers, 79cb93a386Sopenharmony_ci// even if the implementation branches based on bytes from dst (e.g. asserts in Debug mode). 80cb93a386Sopenharmony_ci// For those modes, just lie to MSAN that dst is always intialized. 81cb93a386Sopenharmony_citemplate <typename Xfermode> static void mark_dst_initialized_if_safe(void*, void*) {} 82cb93a386Sopenharmony_citemplate <> inline void mark_dst_initialized_if_safe<Src>(void* dst, void* end) { 83cb93a386Sopenharmony_ci sk_msan_mark_initialized(dst, end, "Src doesn't read dst."); 84cb93a386Sopenharmony_ci} 85cb93a386Sopenharmony_citemplate <> inline void mark_dst_initialized_if_safe<Clear>(void* dst, void* end) { 86cb93a386Sopenharmony_ci sk_msan_mark_initialized(dst, end, "Clear doesn't read dst."); 87cb93a386Sopenharmony_ci} 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_citemplate <typename Xfermode> 90cb93a386Sopenharmony_ciclass Sk4pxXfermode : public SkXfermode { 91cb93a386Sopenharmony_cipublic: 92cb93a386Sopenharmony_ci Sk4pxXfermode() {} 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override { 95cb93a386Sopenharmony_ci mark_dst_initialized_if_safe<Xfermode>(dst, dst+n); 96cb93a386Sopenharmony_ci if (nullptr == aa) { 97cb93a386Sopenharmony_ci Sk4px::MapDstSrc(n, dst, src, Xfermode()); 98cb93a386Sopenharmony_ci } else { 99cb93a386Sopenharmony_ci Sk4px::MapDstSrcAlpha(n, dst, src, aa, xfer_aa<Xfermode>); 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci}; 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci} // namespace 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_cinamespace SK_OPTS_NS { 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci/*not static*/ inline SkXfermode* create_xfermode(SkBlendMode mode) { 109cb93a386Sopenharmony_ci switch (mode) { 110cb93a386Sopenharmony_ci#define CASE(Xfermode) \ 111cb93a386Sopenharmony_ci case SkBlendMode::k##Xfermode: return new Sk4pxXfermode<Xfermode>() 112cb93a386Sopenharmony_ci CASE(Clear); 113cb93a386Sopenharmony_ci CASE(Src); 114cb93a386Sopenharmony_ci CASE(Dst); 115cb93a386Sopenharmony_ci CASE(SrcOver); 116cb93a386Sopenharmony_ci CASE(DstOver); 117cb93a386Sopenharmony_ci CASE(SrcIn); 118cb93a386Sopenharmony_ci CASE(DstIn); 119cb93a386Sopenharmony_ci CASE(SrcOut); 120cb93a386Sopenharmony_ci CASE(DstOut); 121cb93a386Sopenharmony_ci CASE(SrcATop); 122cb93a386Sopenharmony_ci CASE(DstATop); 123cb93a386Sopenharmony_ci CASE(Xor); 124cb93a386Sopenharmony_ci CASE(Plus); 125cb93a386Sopenharmony_ci CASE(Modulate); 126cb93a386Sopenharmony_ci CASE(Screen); 127cb93a386Sopenharmony_ci #undef CASE 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci default: break; 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci return nullptr; 132cb93a386Sopenharmony_ci} 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci} // namespace SK_OPTS_NS 135cb93a386Sopenharmony_ci 136cb93a386Sopenharmony_ci#endif // #ifdef SK_FORCE_RASTER_PIPELINE_BLITTER 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ci#endif//Sk4pxXfermode_DEFINED 139