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(), | |
reed1
2015/06/26 17:17:58
in general, I just love the expressiveness of SkPM
| |
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 | |
121 auto colors = (d == Sk4f(0)).thenElse(dstover, | |
reed1
2015/06/26 17:17:58
After staring for a while, it looks like this is a
mtklein
2015/06/26 17:39:56
Acknowledged.
| |
122 (s == sa).thenElse(srcover, | |
123 sa * Sk4f::Min(da, (d*sa)*(sa-s).approxInvert()) + s*ida + d*isa)); | |
124 | |
125 return srcover * SkPMFloat(1,0,0,0) + colors * SkPMFloat(0,1,1,1); | |
126 } | |
127 XFERMODE(ColorBurn) { | |
128 auto sa = s.alphas(), | |
129 da = d.alphas(), | |
130 isa = Sk4f(1)-sa, | |
131 ida = Sk4f(1)-da; | |
132 | |
133 auto srcover = s + d*isa, | |
134 dstover = d + s*ida; | |
135 | |
136 auto colors = (d == da).thenElse(dstover, | |
137 (s == Sk4f(0)).thenElse(srcover, | |
138 sa*(da-Sk4f::Min(da, (da-d)*sa*s.approxInvert())) + s*ida + d*isa)); | |
139 | |
140 return srcover * SkPMFloat(1,0,0,0) + colors * SkPMFloat(0,1,1,1); | |
141 } | |
101 #undef XFERMODE | 142 #undef XFERMODE |
102 | 143 |
103 // A reasonable fallback mode for doing AA is to simply apply the transfermode f irst, | 144 // A reasonable fallback mode for doing AA is to simply apply the transfermode f irst, |
104 // then linearly interpolate the AA. | 145 // then linearly interpolate the AA. |
105 template <typename Mode> | 146 template <typename Mode> |
106 static Sk4px xfer_aa(const Sk4px& s, const Sk4px& d, const Sk4px& aa) { | 147 static Sk4px xfer_aa(const Sk4px& s, const Sk4px& d, const Sk4px& aa) { |
107 Sk4px bw = Mode::Xfer(s, d); | 148 Sk4px bw = Mode::Xfer(s, d); |
108 return (bw * aa + d * aa.inv()).div255(); | 149 return (bw * aa + d * aa.inv()).div255(); |
109 } | 150 } |
110 | 151 |
(...skipping 22 matching lines...) Expand all Loading... | |
133 }); | 174 }); |
134 } else { | 175 } else { |
135 Sk4px::MapDstSrcAlpha(n, dst, src, aa, | 176 Sk4px::MapDstSrcAlpha(n, dst, src, aa, |
136 [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha ) { | 177 [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha ) { |
137 return xfer_aa<ProcType>(src4, dst4, alpha); | 178 return xfer_aa<ProcType>(src4, dst4, alpha); |
138 }); | 179 }); |
139 } | 180 } |
140 } | 181 } |
141 | 182 |
142 private: | 183 private: |
143 SkT4pxXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, ProcType::kM ode) {} | 184 SkT4pxXfermode(const ProcCoeff& rec) : INHERITED(rec, ProcType::kMode) {} |
144 | 185 |
145 typedef SkProcCoeffXfermode INHERITED; | 186 typedef SkProcCoeffXfermode INHERITED; |
146 }; | 187 }; |
188 | |
189 template <typename ProcType> | |
190 class SkTPMFloatXfermode : public SkProcCoeffXfermode { | |
191 public: | |
192 static SkProcCoeffXfermode* Create(const ProcCoeff& rec) { | |
193 return SkNEW_ARGS(SkTPMFloatXfermode, (rec)); | |
194 } | |
195 | |
196 void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[ ]) const override { | |
197 for (int i = 0; i < n; i++) { | |
198 SkPMFloat s(src[i]), | |
199 d(dst[i]), | |
200 b(ProcType::Xfer(s,d)); | |
201 if (aa) { | |
202 // We do aa in full float precision before going back down to by tes, because we can! | |
203 SkPMFloat a = Sk4f(aa[i]) * Sk4f(1.0f/255); | |
204 b = b*a + d*(Sk4f(1)-a); | |
205 } | |
206 dst[i] = b.round(); | |
207 } | |
208 } | |
209 | |
210 private: | |
211 SkTPMFloatXfermode(const ProcCoeff& rec) : INHERITED(rec, ProcType::kMode) { } | |
212 | |
213 typedef SkProcCoeffXfermode INHERITED; | |
214 }; | |
147 | 215 |
148 static SkProcCoeffXfermode* SkCreate4pxXfermode(const ProcCoeff& rec, SkXfermode ::Mode mode) { | 216 static SkProcCoeffXfermode* SkCreate4pxXfermode(const ProcCoeff& rec, SkXfermode ::Mode mode) { |
149 #if !defined(SK_CPU_ARM32) || defined(SK_ARM_HAS_NEON) | 217 #if !defined(SK_CPU_ARM32) || defined(SK_ARM_HAS_NEON) |
150 switch (mode) { | 218 switch (mode) { |
151 case SkXfermode::kClear_Mode: return SkT4pxXfermode<Clear>::Create( rec); | 219 case SkXfermode::kClear_Mode: return SkT4pxXfermode<Clear>::Create( rec); |
152 case SkXfermode::kSrc_Mode: return SkT4pxXfermode<Src>::Create(re c); | 220 case SkXfermode::kSrc_Mode: return SkT4pxXfermode<Src>::Create(re c); |
153 case SkXfermode::kDst_Mode: return SkT4pxXfermode<Dst>::Create(re c); | 221 case SkXfermode::kDst_Mode: return SkT4pxXfermode<Dst>::Create(re c); |
154 case SkXfermode::kSrcOver_Mode: return SkT4pxXfermode<SrcOver>::Creat e(rec); | 222 case SkXfermode::kSrcOver_Mode: return SkT4pxXfermode<SrcOver>::Creat e(rec); |
155 case SkXfermode::kDstOver_Mode: return SkT4pxXfermode<DstOver>::Creat e(rec); | 223 case SkXfermode::kDstOver_Mode: return SkT4pxXfermode<DstOver>::Creat e(rec); |
156 case SkXfermode::kSrcIn_Mode: return SkT4pxXfermode<SrcIn>::Create( rec); | 224 case SkXfermode::kSrcIn_Mode: return SkT4pxXfermode<SrcIn>::Create( rec); |
157 case SkXfermode::kDstIn_Mode: return SkT4pxXfermode<DstIn>::Create( rec); | 225 case SkXfermode::kDstIn_Mode: return SkT4pxXfermode<DstIn>::Create( rec); |
158 case SkXfermode::kSrcOut_Mode: return SkT4pxXfermode<SrcOut>::Create (rec); | 226 case SkXfermode::kSrcOut_Mode: return SkT4pxXfermode<SrcOut>::Create (rec); |
159 case SkXfermode::kDstOut_Mode: return SkT4pxXfermode<DstOut>::Create (rec); | 227 case SkXfermode::kDstOut_Mode: return SkT4pxXfermode<DstOut>::Create (rec); |
160 case SkXfermode::kSrcATop_Mode: return SkT4pxXfermode<SrcATop>::Creat e(rec); | 228 case SkXfermode::kSrcATop_Mode: return SkT4pxXfermode<SrcATop>::Creat e(rec); |
161 case SkXfermode::kDstATop_Mode: return SkT4pxXfermode<DstATop>::Creat e(rec); | 229 case SkXfermode::kDstATop_Mode: return SkT4pxXfermode<DstATop>::Creat e(rec); |
162 case SkXfermode::kXor_Mode: return SkT4pxXfermode<Xor>::Create(re c); | 230 case SkXfermode::kXor_Mode: return SkT4pxXfermode<Xor>::Create(re c); |
163 case SkXfermode::kPlus_Mode: return SkT4pxXfermode<Plus>::Create(r ec); | 231 case SkXfermode::kPlus_Mode: return SkT4pxXfermode<Plus>::Create(r ec); |
164 case SkXfermode::kModulate_Mode: return SkT4pxXfermode<Modulate>::Crea te(rec); | 232 case SkXfermode::kModulate_Mode: return SkT4pxXfermode<Modulate>::Crea te(rec); |
165 case SkXfermode::kScreen_Mode: return SkT4pxXfermode<Screen>::Create (rec); | 233 case SkXfermode::kScreen_Mode: return SkT4pxXfermode<Screen>::Create (rec); |
166 case SkXfermode::kMultiply_Mode: return SkT4pxXfermode<Multiply>::Crea te(rec); | 234 case SkXfermode::kMultiply_Mode: return SkT4pxXfermode<Multiply>::Crea te(rec); |
167 case SkXfermode::kDifference_Mode: return SkT4pxXfermode<Difference>::Cr eate(rec); | 235 case SkXfermode::kDifference_Mode: return SkT4pxXfermode<Difference>::Cr eate(rec); |
168 case SkXfermode::kExclusion_Mode: return SkT4pxXfermode<Exclusion>::Cre ate(rec); | 236 case SkXfermode::kExclusion_Mode: return SkT4pxXfermode<Exclusion>::Cre ate(rec); |
169 #if !defined(SK_SUPPORT_LEGACY_XFERMODES) // For staging in Chrome (layout test s). | 237 #if !defined(SK_SUPPORT_LEGACY_XFERMODES) // For staging in Chrome (layout test s). |
170 case SkXfermode::kHardLight_Mode: return SkT4pxXfermode<HardLight>::Cre ate(rec); | 238 case SkXfermode::kHardLight_Mode: return SkT4pxXfermode<HardLight>::Cre ate(rec); |
171 case SkXfermode::kOverlay_Mode: return SkT4pxXfermode<Overlay>::Creat e(rec); | 239 case SkXfermode::kOverlay_Mode: return SkT4pxXfermode<Overlay>::Creat e(rec); |
172 case SkXfermode::kDarken_Mode: return SkT4pxXfermode<Darken>::Create (rec); | 240 case SkXfermode::kDarken_Mode: return SkT4pxXfermode<Darken>::Create (rec); |
173 case SkXfermode::kLighten_Mode: return SkT4pxXfermode<Lighten>::Creat e(rec); | 241 case SkXfermode::kLighten_Mode: return SkT4pxXfermode<Lighten>::Creat e(rec); |
242 | |
243 case SkXfermode::kColorDodge_Mode: return SkTPMFloatXfermode<ColorDodge> ::Create(rec); | |
244 case SkXfermode::kColorBurn_Mode: return SkTPMFloatXfermode<ColorBurn>: :Create(rec); | |
174 #endif | 245 #endif |
175 default: break; | 246 default: break; |
176 } | 247 } |
177 #endif | 248 #endif |
178 return nullptr; | 249 return nullptr; |
179 } | 250 } |
180 | 251 |
181 } // namespace | 252 } // namespace |
182 | 253 |
183 #endif//Sk4pxXfermode_DEFINED | 254 #endif//Sk4pxXfermode_DEFINED |
OLD | NEW |