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