|
1 /* |
|
2 * Copyright 2013 Google Inc. |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license that can be |
|
5 * found in the LICENSE file. |
|
6 */ |
|
7 |
|
8 #include "SkArithmeticMode.h" |
|
9 #include "SkColorPriv.h" |
|
10 #include "SkReadBuffer.h" |
|
11 #include "SkWriteBuffer.h" |
|
12 #include "SkString.h" |
|
13 #include "SkUnPreMultiply.h" |
|
14 #if SK_SUPPORT_GPU |
|
15 #include "GrContext.h" |
|
16 #include "GrCoordTransform.h" |
|
17 #include "gl/GrGLEffect.h" |
|
18 #include "GrTBackendEffectFactory.h" |
|
19 #endif |
|
20 |
|
21 static const bool gUseUnpremul = false; |
|
22 |
|
23 class SkArithmeticMode_scalar : public SkXfermode { |
|
24 public: |
|
25 static SkArithmeticMode_scalar* Create(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4) { |
|
26 return SkNEW_ARGS(SkArithmeticMode_scalar, (k1, k2, k3, k4)); |
|
27 } |
|
28 |
|
29 virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, |
|
30 const SkAlpha aa[]) const SK_OVERRIDE; |
|
31 |
|
32 SK_TO_STRING_OVERRIDE() |
|
33 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar) |
|
34 |
|
35 #if SK_SUPPORT_GPU |
|
36 virtual bool asNewEffect(GrEffectRef** effect, GrTexture* background) const SK_OVERRIDE; |
|
37 #endif |
|
38 |
|
39 private: |
|
40 SkArithmeticMode_scalar(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4) { |
|
41 fK[0] = k1; |
|
42 fK[1] = k2; |
|
43 fK[2] = k3; |
|
44 fK[3] = k4; |
|
45 } |
|
46 |
|
47 SkArithmeticMode_scalar(SkReadBuffer& buffer) : INHERITED(buffer) { |
|
48 fK[0] = buffer.readScalar(); |
|
49 fK[1] = buffer.readScalar(); |
|
50 fK[2] = buffer.readScalar(); |
|
51 fK[3] = buffer.readScalar(); |
|
52 } |
|
53 |
|
54 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE { |
|
55 INHERITED::flatten(buffer); |
|
56 buffer.writeScalar(fK[0]); |
|
57 buffer.writeScalar(fK[1]); |
|
58 buffer.writeScalar(fK[2]); |
|
59 buffer.writeScalar(fK[3]); |
|
60 } |
|
61 SkScalar fK[4]; |
|
62 |
|
63 typedef SkXfermode INHERITED; |
|
64 }; |
|
65 |
|
66 static int pinToByte(int value) { |
|
67 if (value < 0) { |
|
68 value = 0; |
|
69 } else if (value > 255) { |
|
70 value = 255; |
|
71 } |
|
72 return value; |
|
73 } |
|
74 |
|
75 static int arith(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, |
|
76 int src, int dst) { |
|
77 SkScalar result = SkScalarMul(k1, src * dst) + |
|
78 SkScalarMul(k2, src) + |
|
79 SkScalarMul(k3, dst) + |
|
80 k4; |
|
81 int res = SkScalarRoundToInt(result); |
|
82 return pinToByte(res); |
|
83 } |
|
84 |
|
85 static int blend(int src, int dst, int scale) { |
|
86 return dst + ((src - dst) * scale >> 8); |
|
87 } |
|
88 |
|
89 static bool needsUnpremul(int alpha) { |
|
90 return 0 != alpha && 0xFF != alpha; |
|
91 } |
|
92 |
|
93 void SkArithmeticMode_scalar::xfer32(SkPMColor dst[], const SkPMColor src[], |
|
94 int count, const SkAlpha aaCoverage[]) const { |
|
95 SkScalar k1 = fK[0] / 255; |
|
96 SkScalar k2 = fK[1]; |
|
97 SkScalar k3 = fK[2]; |
|
98 SkScalar k4 = fK[3] * 255; |
|
99 |
|
100 for (int i = 0; i < count; ++i) { |
|
101 if ((NULL == aaCoverage) || aaCoverage[i]) { |
|
102 SkPMColor sc = src[i]; |
|
103 SkPMColor dc = dst[i]; |
|
104 |
|
105 int a, r, g, b; |
|
106 |
|
107 if (gUseUnpremul) { |
|
108 int sa = SkGetPackedA32(sc); |
|
109 int da = SkGetPackedA32(dc); |
|
110 |
|
111 int srcNeedsUnpremul = needsUnpremul(sa); |
|
112 int dstNeedsUnpremul = needsUnpremul(da); |
|
113 |
|
114 if (!srcNeedsUnpremul && !dstNeedsUnpremul) { |
|
115 a = arith(k1, k2, k3, k4, sa, da); |
|
116 r = arith(k1, k2, k3, k4, SkGetPackedR32(sc), SkGetPackedR32(dc)); |
|
117 g = arith(k1, k2, k3, k4, SkGetPackedG32(sc), SkGetPackedG32(dc)); |
|
118 b = arith(k1, k2, k3, k4, SkGetPackedB32(sc), SkGetPackedB32(dc)); |
|
119 } else { |
|
120 int sr = SkGetPackedR32(sc); |
|
121 int sg = SkGetPackedG32(sc); |
|
122 int sb = SkGetPackedB32(sc); |
|
123 if (srcNeedsUnpremul) { |
|
124 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(sa); |
|
125 sr = SkUnPreMultiply::ApplyScale(scale, sr); |
|
126 sg = SkUnPreMultiply::ApplyScale(scale, sg); |
|
127 sb = SkUnPreMultiply::ApplyScale(scale, sb); |
|
128 } |
|
129 |
|
130 int dr = SkGetPackedR32(dc); |
|
131 int dg = SkGetPackedG32(dc); |
|
132 int db = SkGetPackedB32(dc); |
|
133 if (dstNeedsUnpremul) { |
|
134 SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(da); |
|
135 dr = SkUnPreMultiply::ApplyScale(scale, dr); |
|
136 dg = SkUnPreMultiply::ApplyScale(scale, dg); |
|
137 db = SkUnPreMultiply::ApplyScale(scale, db); |
|
138 } |
|
139 |
|
140 a = arith(k1, k2, k3, k4, sa, da); |
|
141 r = arith(k1, k2, k3, k4, sr, dr); |
|
142 g = arith(k1, k2, k3, k4, sg, dg); |
|
143 b = arith(k1, k2, k3, k4, sb, db); |
|
144 } |
|
145 } else { |
|
146 a = arith(k1, k2, k3, k4, SkGetPackedA32(sc), SkGetPackedA32(dc)); |
|
147 r = arith(k1, k2, k3, k4, SkGetPackedR32(sc), SkGetPackedR32(dc)); |
|
148 r = SkMin32(r, a); |
|
149 g = arith(k1, k2, k3, k4, SkGetPackedG32(sc), SkGetPackedG32(dc)); |
|
150 g = SkMin32(g, a); |
|
151 b = arith(k1, k2, k3, k4, SkGetPackedB32(sc), SkGetPackedB32(dc)); |
|
152 b = SkMin32(b, a); |
|
153 } |
|
154 |
|
155 // apply antialias coverage if necessary |
|
156 if (aaCoverage && 0xFF != aaCoverage[i]) { |
|
157 int scale = aaCoverage[i] + (aaCoverage[i] >> 7); |
|
158 a = blend(a, SkGetPackedA32(sc), scale); |
|
159 r = blend(r, SkGetPackedR32(sc), scale); |
|
160 g = blend(g, SkGetPackedG32(sc), scale); |
|
161 b = blend(b, SkGetPackedB32(sc), scale); |
|
162 } |
|
163 |
|
164 // turn the result back into premul |
|
165 if (gUseUnpremul && (0xFF != a)) { |
|
166 int scale = a + (a >> 7); |
|
167 r = SkAlphaMul(r, scale); |
|
168 g = SkAlphaMul(g, scale); |
|
169 b = SkAlphaMul(b, scale); |
|
170 } |
|
171 dst[i] = SkPackARGB32(a, r, g, b); |
|
172 } |
|
173 } |
|
174 } |
|
175 |
|
176 #ifndef SK_IGNORE_TO_STRING |
|
177 void SkArithmeticMode_scalar::toString(SkString* str) const { |
|
178 str->append("SkArithmeticMode_scalar: "); |
|
179 for (int i = 0; i < 4; ++i) { |
|
180 str->appendScalar(fK[i]); |
|
181 if (i < 3) { |
|
182 str->append(" "); |
|
183 } |
|
184 } |
|
185 } |
|
186 #endif |
|
187 |
|
188 /////////////////////////////////////////////////////////////////////////////// |
|
189 |
|
190 static bool fitsInBits(SkScalar x, int bits) { |
|
191 return SkScalarAbs(x) < (1 << (bits - 1)); |
|
192 } |
|
193 |
|
194 #if 0 // UNUSED |
|
195 static int32_t toDot8(SkScalar x) { |
|
196 return (int32_t)(x * 256); |
|
197 } |
|
198 #endif |
|
199 |
|
200 SkXfermode* SkArithmeticMode::Create(SkScalar k1, SkScalar k2, |
|
201 SkScalar k3, SkScalar k4) { |
|
202 if (fitsInBits(k1, 8) && fitsInBits(k2, 16) && |
|
203 fitsInBits(k2, 16) && fitsInBits(k2, 24)) { |
|
204 |
|
205 #if 0 // UNUSED |
|
206 int32_t i1 = toDot8(k1); |
|
207 int32_t i2 = toDot8(k2); |
|
208 int32_t i3 = toDot8(k3); |
|
209 int32_t i4 = toDot8(k4); |
|
210 if (i1) { |
|
211 return SkNEW_ARGS(SkArithmeticMode_quad, (i1, i2, i3, i4)); |
|
212 } |
|
213 if (0 == i2) { |
|
214 return SkNEW_ARGS(SkArithmeticMode_dst, (i3, i4)); |
|
215 } |
|
216 if (0 == i3) { |
|
217 return SkNEW_ARGS(SkArithmeticMode_src, (i2, i4)); |
|
218 } |
|
219 return SkNEW_ARGS(SkArithmeticMode_linear, (i2, i3, i4)); |
|
220 #endif |
|
221 } |
|
222 return SkArithmeticMode_scalar::Create(k1, k2, k3, k4); |
|
223 } |
|
224 |
|
225 |
|
226 ////////////////////////////////////////////////////////////////////////////// |
|
227 |
|
228 #if SK_SUPPORT_GPU |
|
229 |
|
230 class GrGLArithmeticEffect : public GrGLEffect { |
|
231 public: |
|
232 GrGLArithmeticEffect(const GrBackendEffectFactory&, const GrDrawEffect&); |
|
233 virtual ~GrGLArithmeticEffect(); |
|
234 |
|
235 virtual void emitCode(GrGLShaderBuilder*, |
|
236 const GrDrawEffect&, |
|
237 EffectKey, |
|
238 const char* outputColor, |
|
239 const char* inputColor, |
|
240 const TransformedCoordsArray&, |
|
241 const TextureSamplerArray&) SK_OVERRIDE; |
|
242 |
|
243 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; |
|
244 |
|
245 private: |
|
246 GrGLUniformManager::UniformHandle fKUni; |
|
247 |
|
248 typedef GrGLEffect INHERITED; |
|
249 }; |
|
250 |
|
251 /////////////////////////////////////////////////////////////////////////////// |
|
252 |
|
253 class GrArithmeticEffect : public GrEffect { |
|
254 public: |
|
255 static GrEffectRef* Create(float k1, float k2, float k3, float k4, GrTexture* background) { |
|
256 AutoEffectUnref effect(SkNEW_ARGS(GrArithmeticEffect, (k1, k2, k3, k4, background))); |
|
257 return CreateEffectRef(effect); |
|
258 } |
|
259 |
|
260 virtual ~GrArithmeticEffect(); |
|
261 |
|
262 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; |
|
263 |
|
264 typedef GrGLArithmeticEffect GLEffect; |
|
265 static const char* Name() { return "Arithmetic"; } |
|
266 GrTexture* backgroundTexture() const { return fBackgroundAccess.getTexture(); } |
|
267 |
|
268 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; |
|
269 |
|
270 float k1() const { return fK1; } |
|
271 float k2() const { return fK2; } |
|
272 float k3() const { return fK3; } |
|
273 float k4() const { return fK4; } |
|
274 |
|
275 private: |
|
276 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; |
|
277 |
|
278 GrArithmeticEffect(float k1, float k2, float k3, float k4, GrTexture* background); |
|
279 float fK1, fK2, fK3, fK4; |
|
280 GrCoordTransform fBackgroundTransform; |
|
281 GrTextureAccess fBackgroundAccess; |
|
282 |
|
283 GR_DECLARE_EFFECT_TEST; |
|
284 typedef GrEffect INHERITED; |
|
285 |
|
286 }; |
|
287 |
|
288 /////////////////////////////////////////////////////////////////////////////// |
|
289 |
|
290 GrArithmeticEffect::GrArithmeticEffect(float k1, float k2, float k3, float k4, |
|
291 GrTexture* background) |
|
292 : fK1(k1), fK2(k2), fK3(k3), fK4(k4) { |
|
293 if (background) { |
|
294 fBackgroundTransform.reset(kLocal_GrCoordSet, background); |
|
295 this->addCoordTransform(&fBackgroundTransform); |
|
296 fBackgroundAccess.reset(background); |
|
297 this->addTextureAccess(&fBackgroundAccess); |
|
298 } else { |
|
299 this->setWillReadDstColor(); |
|
300 } |
|
301 } |
|
302 |
|
303 GrArithmeticEffect::~GrArithmeticEffect() { |
|
304 } |
|
305 |
|
306 bool GrArithmeticEffect::onIsEqual(const GrEffect& sBase) const { |
|
307 const GrArithmeticEffect& s = CastEffect<GrArithmeticEffect>(sBase); |
|
308 return fK1 == s.fK1 && |
|
309 fK2 == s.fK2 && |
|
310 fK3 == s.fK3 && |
|
311 fK4 == s.fK4 && |
|
312 backgroundTexture() == s.backgroundTexture(); |
|
313 } |
|
314 |
|
315 const GrBackendEffectFactory& GrArithmeticEffect::getFactory() const { |
|
316 return GrTBackendEffectFactory<GrArithmeticEffect>::getInstance(); |
|
317 } |
|
318 |
|
319 void GrArithmeticEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { |
|
320 // TODO: optimize this |
|
321 *validFlags = 0; |
|
322 } |
|
323 |
|
324 /////////////////////////////////////////////////////////////////////////////// |
|
325 |
|
326 GrGLArithmeticEffect::GrGLArithmeticEffect(const GrBackendEffectFactory& factory, |
|
327 const GrDrawEffect& drawEffect) |
|
328 : INHERITED(factory) { |
|
329 } |
|
330 |
|
331 GrGLArithmeticEffect::~GrGLArithmeticEffect() { |
|
332 } |
|
333 |
|
334 void GrGLArithmeticEffect::emitCode(GrGLShaderBuilder* builder, |
|
335 const GrDrawEffect& drawEffect, |
|
336 EffectKey key, |
|
337 const char* outputColor, |
|
338 const char* inputColor, |
|
339 const TransformedCoordsArray& coords, |
|
340 const TextureSamplerArray& samplers) { |
|
341 |
|
342 GrTexture* backgroundTex = drawEffect.castEffect<GrArithmeticEffect>().backgroundTexture(); |
|
343 const char* dstColor; |
|
344 if (backgroundTex) { |
|
345 builder->fsCodeAppend("\t\tvec4 bgColor = "); |
|
346 builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type()); |
|
347 builder->fsCodeAppendf(";\n"); |
|
348 dstColor = "bgColor"; |
|
349 } else { |
|
350 dstColor = builder->dstColor(); |
|
351 } |
|
352 |
|
353 SkASSERT(NULL != dstColor); |
|
354 fKUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
|
355 kVec4f_GrSLType, "k"); |
|
356 const char* kUni = builder->getUniformCStr(fKUni); |
|
357 |
|
358 // We don't try to optimize for this case at all |
|
359 if (NULL == inputColor) { |
|
360 builder->fsCodeAppendf("\t\tconst vec4 src = vec4(1);\n"); |
|
361 } else { |
|
362 builder->fsCodeAppendf("\t\tvec4 src = %s;\n", inputColor); |
|
363 if (gUseUnpremul) { |
|
364 builder->fsCodeAppendf("\t\tsrc.rgb = clamp(src.rgb / src.a, 0.0, 1.0);\n"); |
|
365 } |
|
366 } |
|
367 |
|
368 builder->fsCodeAppendf("\t\tvec4 dst = %s;\n", dstColor); |
|
369 if (gUseUnpremul) { |
|
370 builder->fsCodeAppendf("\t\tdst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);\n"); |
|
371 } |
|
372 |
|
373 builder->fsCodeAppendf("\t\t%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;\n", outputColor, kUni, kUni, kUni, kUni); |
|
374 builder->fsCodeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor); |
|
375 if (gUseUnpremul) { |
|
376 builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor); |
|
377 } else { |
|
378 builder->fsCodeAppendf("\t\t%s.rgb = min(%s.rgb, %s.a);\n", outputColor, outputColor, outputColor); |
|
379 } |
|
380 } |
|
381 |
|
382 void GrGLArithmeticEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { |
|
383 const GrArithmeticEffect& arith = drawEffect.castEffect<GrArithmeticEffect>(); |
|
384 uman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); |
|
385 } |
|
386 |
|
387 GrEffectRef* GrArithmeticEffect::TestCreate(SkRandom* rand, |
|
388 GrContext*, |
|
389 const GrDrawTargetCaps&, |
|
390 GrTexture*[]) { |
|
391 float k1 = rand->nextF(); |
|
392 float k2 = rand->nextF(); |
|
393 float k3 = rand->nextF(); |
|
394 float k4 = rand->nextF(); |
|
395 |
|
396 AutoEffectUnref gEffect(SkNEW_ARGS(GrArithmeticEffect, (k1, k2, k3, k4, NULL))); |
|
397 return CreateEffectRef(gEffect); |
|
398 } |
|
399 |
|
400 GR_DEFINE_EFFECT_TEST(GrArithmeticEffect); |
|
401 |
|
402 bool SkArithmeticMode_scalar::asNewEffect(GrEffectRef** effect, GrTexture* background) const { |
|
403 if (effect) { |
|
404 *effect = GrArithmeticEffect::Create(SkScalarToFloat(fK[0]), |
|
405 SkScalarToFloat(fK[1]), |
|
406 SkScalarToFloat(fK[2]), |
|
407 SkScalarToFloat(fK[3]), |
|
408 background); |
|
409 } |
|
410 return true; |
|
411 } |
|
412 |
|
413 #endif |
|
414 |
|
415 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkArithmeticMode) |
|
416 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArithmeticMode_scalar) |
|
417 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |