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