OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 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 #ifndef Sk4pxXfermode_DEFINED | 8 #ifndef Sk4pxXfermode_DEFINED |
9 #define Sk4pxXfermode_DEFINED | 9 #define Sk4pxXfermode_DEFINED |
10 | 10 |
11 #include "Sk4px.h" | 11 #include "Sk4px.h" |
| 12 #include "SkPMFloat.h" |
12 | 13 |
13 // This file is possibly included into multiple .cpp files. | 14 // This file is possibly included into multiple .cpp files. |
14 // Each gets its own independent instantiation by wrapping in an anonymous names
pace. | 15 // Each gets its own independent instantiation by wrapping in an anonymous names
pace. |
15 namespace { | 16 namespace { |
16 | 17 |
| 18 // Most xfermodes can be done most efficiently 4 pixels at a time in 8 or 16-bit
fixed point. |
17 #define XFERMODE(Name) \ | 19 #define XFERMODE(Name) \ |
18 struct Name { \ | 20 struct Name { \ |
19 static Sk4px Xfer(const Sk4px&, const Sk4px&); \ | 21 static Sk4px Xfer(const Sk4px&, const Sk4px&); \ |
20 static const SkXfermode::Mode kMode = SkXfermode::k##Name##_Mode; \ | 22 static const SkXfermode::Mode kMode = SkXfermode::k##Name##_Mode; \ |
21 }; \ | 23 }; \ |
22 inline Sk4px Name::Xfer(const Sk4px& s, const Sk4px& d) | 24 inline Sk4px Name::Xfer(const Sk4px& s, const Sk4px& d) |
23 | 25 |
24 XFERMODE(Clear) { return Sk4px::DupPMColor(0); } | 26 XFERMODE(Clear) { return Sk4px::DupPMColor(0); } |
25 XFERMODE(Src) { return s; } | 27 XFERMODE(Src) { return s; } |
26 XFERMODE(Dst) { return d; } | 28 XFERMODE(Dst) { return d; } |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 } | 92 } |
91 XFERMODE(Lighten) { | 93 XFERMODE(Lighten) { |
92 auto sda = s.approxMulDiv255(d.alphas()), | 94 auto sda = s.approxMulDiv255(d.alphas()), |
93 dsa = d.approxMulDiv255(s.alphas()); | 95 dsa = d.approxMulDiv255(s.alphas()); |
94 auto srcover = s + (d - dsa), | 96 auto srcover = s + (d - dsa), |
95 dstover = d + (s - sda); | 97 dstover = d + (s - sda); |
96 auto alphas = srcover, | 98 auto alphas = srcover, |
97 colors = (sda < dsa).thenElse(dstover, srcover); | 99 colors = (sda < dsa).thenElse(dstover, srcover); |
98 return alphas.zeroColors() + colors.zeroAlphas(); | 100 return alphas.zeroColors() + colors.zeroAlphas(); |
99 } | 101 } |
| 102 #undef XFERMODE |
100 | 103 |
| 104 // Some xfermodes use math like divide or sqrt that's best done in floats 1 pixe
l at a time. |
| 105 #define XFERMODE(Name) \ |
| 106 struct Name { \ |
| 107 static SkPMFloat Xfer(const SkPMFloat&, const SkPMFloat&); \ |
| 108 static const SkXfermode::Mode kMode = SkXfermode::k##Name##_Mode; \ |
| 109 }; \ |
| 110 inline SkPMFloat Name::Xfer(const SkPMFloat& s, const SkPMFloat& d) |
| 111 |
| 112 XFERMODE(ColorDodge) { |
| 113 auto sa = s.alphas(), |
| 114 da = d.alphas(), |
| 115 isa = Sk4f(1)-sa, |
| 116 ida = Sk4f(1)-da; |
| 117 |
| 118 auto srcover = s + d*isa, |
| 119 dstover = d + s*ida, |
| 120 otherwise = sa * Sk4f::Min(da, (d*sa)*(sa-s).approxInvert()) + s*ida +
d*isa; |
| 121 |
| 122 // Order matters here, preferring d==0 over s==sa. |
| 123 auto colors = (d == Sk4f(0)).thenElse(dstover, |
| 124 (s == sa).thenElse(srcover, |
| 125 otherwise)); |
| 126 return srcover * SkPMFloat(1,0,0,0) + colors * SkPMFloat(0,1,1,1); |
| 127 } |
| 128 XFERMODE(ColorBurn) { |
| 129 auto sa = s.alphas(), |
| 130 da = d.alphas(), |
| 131 isa = Sk4f(1)-sa, |
| 132 ida = Sk4f(1)-da; |
| 133 |
| 134 auto srcover = s + d*isa, |
| 135 dstover = d + s*ida, |
| 136 otherwise = sa*(da-Sk4f::Min(da, (da-d)*sa*s.approxInvert())) + s*ida +
d*isa; |
| 137 |
| 138 // Order matters here, preferring d==da over s==0. |
| 139 auto colors = (d == da).thenElse(dstover, |
| 140 (s == Sk4f(0)).thenElse(srcover, |
| 141 otherwise)); |
| 142 return srcover * SkPMFloat(1,0,0,0) + colors * SkPMFloat(0,1,1,1); |
| 143 } |
101 #undef XFERMODE | 144 #undef XFERMODE |
102 | 145 |
103 // A reasonable fallback mode for doing AA is to simply apply the transfermode f
irst, | 146 // A reasonable fallback mode for doing AA is to simply apply the transfermode f
irst, |
104 // then linearly interpolate the AA. | 147 // then linearly interpolate the AA. |
105 template <typename Mode> | 148 template <typename Mode> |
106 static Sk4px xfer_aa(const Sk4px& s, const Sk4px& d, const Sk4px& aa) { | 149 static Sk4px xfer_aa(const Sk4px& s, const Sk4px& d, const Sk4px& aa) { |
107 Sk4px bw = Mode::Xfer(s, d); | 150 Sk4px bw = Mode::Xfer(s, d); |
108 return (bw * aa + d * aa.inv()).div255(); | 151 return (bw * aa + d * aa.inv()).div255(); |
109 } | 152 } |
110 | 153 |
(...skipping 22 matching lines...) Expand all Loading... |
133 }); | 176 }); |
134 } else { | 177 } else { |
135 Sk4px::MapDstSrcAlpha(n, dst, src, aa, | 178 Sk4px::MapDstSrcAlpha(n, dst, src, aa, |
136 [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha
) { | 179 [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha
) { |
137 return xfer_aa<ProcType>(src4, dst4, alpha); | 180 return xfer_aa<ProcType>(src4, dst4, alpha); |
138 }); | 181 }); |
139 } | 182 } |
140 } | 183 } |
141 | 184 |
142 private: | 185 private: |
143 SkT4pxXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, ProcType::kM
ode) {} | 186 SkT4pxXfermode(const ProcCoeff& rec) : INHERITED(rec, ProcType::kMode) {} |
144 | 187 |
145 typedef SkProcCoeffXfermode INHERITED; | 188 typedef SkProcCoeffXfermode INHERITED; |
146 }; | 189 }; |
| 190 |
| 191 template <typename ProcType> |
| 192 class SkTPMFloatXfermode : public SkProcCoeffXfermode { |
| 193 public: |
| 194 static SkProcCoeffXfermode* Create(const ProcCoeff& rec) { |
| 195 return SkNEW_ARGS(SkTPMFloatXfermode, (rec)); |
| 196 } |
| 197 |
| 198 void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[
]) const override { |
| 199 for (int i = 0; i < n; i++) { |
| 200 SkPMFloat s(src[i]), |
| 201 d(dst[i]), |
| 202 b(ProcType::Xfer(s,d)); |
| 203 if (aa) { |
| 204 // We do aa in full float precision before going back down to by
tes, because we can! |
| 205 SkPMFloat a = Sk4f(aa[i]) * Sk4f(1.0f/255); |
| 206 b = b*a + d*(Sk4f(1)-a); |
| 207 } |
| 208 dst[i] = b.round(); |
| 209 } |
| 210 } |
| 211 |
| 212 private: |
| 213 SkTPMFloatXfermode(const ProcCoeff& rec) : INHERITED(rec, ProcType::kMode) {
} |
| 214 |
| 215 typedef SkProcCoeffXfermode INHERITED; |
| 216 }; |
147 | 217 |
148 static SkProcCoeffXfermode* SkCreate4pxXfermode(const ProcCoeff& rec, SkXfermode
::Mode mode) { | 218 static SkProcCoeffXfermode* SkCreate4pxXfermode(const ProcCoeff& rec, SkXfermode
::Mode mode) { |
149 #if !defined(SK_CPU_ARM32) || defined(SK_ARM_HAS_NEON) | 219 #if !defined(SK_CPU_ARM32) || defined(SK_ARM_HAS_NEON) |
150 switch (mode) { | 220 switch (mode) { |
151 case SkXfermode::kClear_Mode: return SkT4pxXfermode<Clear>::Create(
rec); | 221 case SkXfermode::kClear_Mode: return SkT4pxXfermode<Clear>::Create(
rec); |
152 case SkXfermode::kSrc_Mode: return SkT4pxXfermode<Src>::Create(re
c); | 222 case SkXfermode::kSrc_Mode: return SkT4pxXfermode<Src>::Create(re
c); |
153 case SkXfermode::kDst_Mode: return SkT4pxXfermode<Dst>::Create(re
c); | 223 case SkXfermode::kDst_Mode: return SkT4pxXfermode<Dst>::Create(re
c); |
154 case SkXfermode::kSrcOver_Mode: return SkT4pxXfermode<SrcOver>::Creat
e(rec); | 224 case SkXfermode::kSrcOver_Mode: return SkT4pxXfermode<SrcOver>::Creat
e(rec); |
155 case SkXfermode::kDstOver_Mode: return SkT4pxXfermode<DstOver>::Creat
e(rec); | 225 case SkXfermode::kDstOver_Mode: return SkT4pxXfermode<DstOver>::Creat
e(rec); |
156 case SkXfermode::kSrcIn_Mode: return SkT4pxXfermode<SrcIn>::Create(
rec); | 226 case SkXfermode::kSrcIn_Mode: return SkT4pxXfermode<SrcIn>::Create(
rec); |
157 case SkXfermode::kDstIn_Mode: return SkT4pxXfermode<DstIn>::Create(
rec); | 227 case SkXfermode::kDstIn_Mode: return SkT4pxXfermode<DstIn>::Create(
rec); |
158 case SkXfermode::kSrcOut_Mode: return SkT4pxXfermode<SrcOut>::Create
(rec); | 228 case SkXfermode::kSrcOut_Mode: return SkT4pxXfermode<SrcOut>::Create
(rec); |
159 case SkXfermode::kDstOut_Mode: return SkT4pxXfermode<DstOut>::Create
(rec); | 229 case SkXfermode::kDstOut_Mode: return SkT4pxXfermode<DstOut>::Create
(rec); |
160 case SkXfermode::kSrcATop_Mode: return SkT4pxXfermode<SrcATop>::Creat
e(rec); | 230 case SkXfermode::kSrcATop_Mode: return SkT4pxXfermode<SrcATop>::Creat
e(rec); |
161 case SkXfermode::kDstATop_Mode: return SkT4pxXfermode<DstATop>::Creat
e(rec); | 231 case SkXfermode::kDstATop_Mode: return SkT4pxXfermode<DstATop>::Creat
e(rec); |
162 case SkXfermode::kXor_Mode: return SkT4pxXfermode<Xor>::Create(re
c); | 232 case SkXfermode::kXor_Mode: return SkT4pxXfermode<Xor>::Create(re
c); |
163 case SkXfermode::kPlus_Mode: return SkT4pxXfermode<Plus>::Create(r
ec); | 233 case SkXfermode::kPlus_Mode: return SkT4pxXfermode<Plus>::Create(r
ec); |
164 case SkXfermode::kModulate_Mode: return SkT4pxXfermode<Modulate>::Crea
te(rec); | 234 case SkXfermode::kModulate_Mode: return SkT4pxXfermode<Modulate>::Crea
te(rec); |
165 case SkXfermode::kScreen_Mode: return SkT4pxXfermode<Screen>::Create
(rec); | 235 case SkXfermode::kScreen_Mode: return SkT4pxXfermode<Screen>::Create
(rec); |
166 case SkXfermode::kMultiply_Mode: return SkT4pxXfermode<Multiply>::Crea
te(rec); | 236 case SkXfermode::kMultiply_Mode: return SkT4pxXfermode<Multiply>::Crea
te(rec); |
167 case SkXfermode::kDifference_Mode: return SkT4pxXfermode<Difference>::Cr
eate(rec); | 237 case SkXfermode::kDifference_Mode: return SkT4pxXfermode<Difference>::Cr
eate(rec); |
168 case SkXfermode::kExclusion_Mode: return SkT4pxXfermode<Exclusion>::Cre
ate(rec); | 238 case SkXfermode::kExclusion_Mode: return SkT4pxXfermode<Exclusion>::Cre
ate(rec); |
169 #if !defined(SK_SUPPORT_LEGACY_XFERMODES) // For staging in Chrome (layout test
s). | 239 #if !defined(SK_SUPPORT_LEGACY_XFERMODES) // For staging in Chrome (layout test
s). |
170 case SkXfermode::kHardLight_Mode: return SkT4pxXfermode<HardLight>::Cre
ate(rec); | 240 case SkXfermode::kHardLight_Mode: return SkT4pxXfermode<HardLight>::Cre
ate(rec); |
171 case SkXfermode::kOverlay_Mode: return SkT4pxXfermode<Overlay>::Creat
e(rec); | 241 case SkXfermode::kOverlay_Mode: return SkT4pxXfermode<Overlay>::Creat
e(rec); |
172 case SkXfermode::kDarken_Mode: return SkT4pxXfermode<Darken>::Create
(rec); | 242 case SkXfermode::kDarken_Mode: return SkT4pxXfermode<Darken>::Create
(rec); |
173 case SkXfermode::kLighten_Mode: return SkT4pxXfermode<Lighten>::Creat
e(rec); | 243 case SkXfermode::kLighten_Mode: return SkT4pxXfermode<Lighten>::Creat
e(rec); |
| 244 |
| 245 case SkXfermode::kColorDodge_Mode: return SkTPMFloatXfermode<ColorDodge>
::Create(rec); |
| 246 case SkXfermode::kColorBurn_Mode: return SkTPMFloatXfermode<ColorBurn>:
:Create(rec); |
174 #endif | 247 #endif |
175 default: break; | 248 default: break; |
176 } | 249 } |
177 #endif | 250 #endif |
178 return nullptr; | 251 return nullptr; |
179 } | 252 } |
180 | 253 |
181 } // namespace | 254 } // namespace |
182 | 255 |
183 #endif//Sk4pxXfermode_DEFINED | 256 #endif//Sk4pxXfermode_DEFINED |
OLD | NEW |