1/*
2* Copyright 2015 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 "effects/GrXfermodeFragmentProcessor.h"
9
10#include "GrFragmentProcessor.h"
11#include "GrInvariantOutput.h"
12#include "effects/GrConstColorProcessor.h"
13#include "glsl/GrGLSLFragmentProcessor.h"
14#include "glsl/GrGLSLBlend.h"
15#include "glsl/GrGLSLFragmentShaderBuilder.h"
16#include "SkGrPriv.h"
17
18class ComposeTwoFragmentProcessor : public GrFragmentProcessor {
19public:
20    ComposeTwoFragmentProcessor(const GrFragmentProcessor* src, const GrFragmentProcessor* dst,
21                    SkXfermode::Mode mode)
22        : fMode(mode) {
23        this->initClassID<ComposeTwoFragmentProcessor>();
24        SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(src);
25        SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(dst);
26        SkASSERT(0 == shaderAChildIndex);
27        SkASSERT(1 == shaderBChildIndex);
28    }
29
30    const char* name() const override { return "ComposeTwo"; }
31
32    void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
33        b->add32(fMode);
34    }
35
36    SkXfermode::Mode getMode() const { return fMode; }
37
38protected:
39    bool onIsEqual(const GrFragmentProcessor& other) const override {
40        const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>();
41        return fMode == cs.fMode;
42    }
43
44    void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
45        inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
46    }
47
48private:
49    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
50
51    SkXfermode::Mode fMode;
52
53    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
54
55    typedef GrFragmentProcessor INHERITED;
56};
57
58/////////////////////////////////////////////////////////////////////
59
60class GLComposeTwoFragmentProcessor : public GrGLSLFragmentProcessor {
61public:
62    void emitCode(EmitArgs&) override;
63
64private:
65    typedef GrGLSLFragmentProcessor INHERITED;
66};
67
68/////////////////////////////////////////////////////////////////////
69
70GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor);
71
72const GrFragmentProcessor* ComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) {
73    // Create two random frag procs.
74    SkAutoTUnref<const GrFragmentProcessor> fpA(GrProcessorUnitTest::CreateChildFP(d));
75    SkAutoTUnref<const GrFragmentProcessor> fpB(GrProcessorUnitTest::CreateChildFP(d));
76
77    SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(
78        d->fRandom->nextRangeU(0, SkXfermode::kLastMode));
79    return new ComposeTwoFragmentProcessor(fpA, fpB, mode);
80}
81
82GrGLSLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLSLInstance() const{
83    return new GLComposeTwoFragmentProcessor;
84}
85
86/////////////////////////////////////////////////////////////////////
87
88void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
89
90    GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
91    const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProcessor>();
92
93    const char* inputColor = nullptr;
94    if (args.fInputColor) {
95        inputColor = "inputColor";
96        fragBuilder->codeAppendf("vec4 inputColor = vec4(%s.rgb, 1.0);", args.fInputColor);
97    }
98
99    // declare outputColor and emit the code for each of the two children
100    SkString srcColor("src");
101    this->emitChild(0, inputColor, &srcColor, args);
102
103    SkString dstColor("dst");
104    this->emitChild(1, inputColor, &dstColor, args);
105
106    // emit blend code
107    SkXfermode::Mode mode = cs.getMode();
108    fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
109    GrGLSLBlend::AppendMode(fragBuilder,
110                            srcColor.c_str(),
111                            dstColor.c_str(),
112                            args.fOutputColor,
113                            mode);
114
115    // re-multiply the output color by the input color's alpha
116    if (args.fInputColor) {
117        fragBuilder->codeAppendf("%s *= %s.a;", args.fOutputColor, args.fInputColor);
118    }
119}
120
121const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromTwoProcessors(
122         const GrFragmentProcessor* src, const GrFragmentProcessor* dst, SkXfermode::Mode mode) {
123    switch (mode) {
124        case SkXfermode::kClear_Mode:
125            return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
126                                                 GrConstColorProcessor::kIgnore_InputMode);
127        case SkXfermode::kSrc_Mode:
128            return SkRef(src);
129        case SkXfermode::kDst_Mode:
130            return SkRef(dst);
131        default:
132            return new ComposeTwoFragmentProcessor(src, dst, mode);
133    }
134}
135
136//////////////////////////////////////////////////////////////////////////////
137
138class ComposeOneFragmentProcessor : public GrFragmentProcessor {
139public:
140    enum Child {
141        kDst_Child,
142        kSrc_Child,
143    };
144
145    ComposeOneFragmentProcessor(const GrFragmentProcessor* dst, SkXfermode::Mode mode, Child child)
146        : fMode(mode)
147        , fChild(child) {
148        this->initClassID<ComposeOneFragmentProcessor>();
149        SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst);
150        SkASSERT(0 == dstIndex);
151    }
152
153    const char* name() const override { return "ComposeOne"; }
154
155    SkString dumpInfo() const override {
156        SkString str;
157
158        for (int i = 0; i < this->numChildProcessors(); ++i) {
159            str.append(this->childProcessor(i).dumpInfo());
160        }
161        return str;
162    }
163
164    void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
165        GR_STATIC_ASSERT((SkXfermode::kLastMode & SK_MaxU16) == SkXfermode::kLastMode);
166        b->add32(fMode | (fChild << 16));
167    }
168
169    SkXfermode::Mode mode() const { return fMode; }
170
171    Child child() const { return fChild; }
172
173protected:
174    bool onIsEqual(const GrFragmentProcessor& that) const override {
175        return fMode == that.cast<ComposeOneFragmentProcessor>().fMode;
176    }
177
178    void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
179        SkXfermode::Coeff skSrcCoeff, skDstCoeff;
180        if (SkXfermode::ModeAsCoeff(fMode, &skSrcCoeff, &skDstCoeff)) {
181            GrBlendCoeff srcCoeff = SkXfermodeCoeffToGrBlendCoeff(skSrcCoeff);
182            GrBlendCoeff dstCoeff = SkXfermodeCoeffToGrBlendCoeff(skDstCoeff);
183            GrInvariantOutput childOutput(0xFFFFFFFF, kRGBA_GrColorComponentFlags, false);
184            this->childProcessor(0).computeInvariantOutput(&childOutput);
185            GrColor blendColor;
186            GrColorComponentFlags blendFlags;
187            if (kDst_Child == fChild) {
188                GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff,
189                                               inout->color(), inout->validFlags(),
190                                               childOutput.color(), childOutput.validFlags(),
191                                               &blendColor, &blendFlags);
192            } else {
193                GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff,
194                                               childOutput.color(), childOutput.validFlags(),
195                                               inout->color(), inout->validFlags(),
196                                               &blendColor, &blendFlags);
197            }
198            // will the shader code reference the input color?
199            GrInvariantOutput::ReadInput readsInput = GrInvariantOutput::kWillNot_ReadInput;
200            if (kDst_Child == fChild) {
201                if (kZero_GrBlendCoeff != srcCoeff || GrBlendCoeffRefsSrc(dstCoeff)) {
202                    readsInput = GrInvariantOutput::kWill_ReadInput;
203                }
204            } else {
205                if (kZero_GrBlendCoeff != dstCoeff || GrBlendCoeffRefsDst(srcCoeff)) {
206                    readsInput = GrInvariantOutput::kWill_ReadInput;
207                }
208            }
209            inout->setToOther(blendFlags, blendColor, readsInput);
210        } else {
211            inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
212        }
213    }
214
215private:
216    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
217
218    SkXfermode::Mode    fMode;
219    Child               fChild;
220
221    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
222
223    typedef GrFragmentProcessor INHERITED;
224};
225
226//////////////////////////////////////////////////////////////////////////////
227
228class GLComposeOneFragmentProcessor : public GrGLSLFragmentProcessor {
229public:
230    void emitCode(EmitArgs& args) override {
231        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
232        SkXfermode::Mode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode();
233        ComposeOneFragmentProcessor::Child child =
234            args.fFp.cast<ComposeOneFragmentProcessor>().child();
235        SkString childColor("child");
236        this->emitChild(0, nullptr, &childColor, args);
237
238        const char* inputColor = args.fInputColor;
239        // We don't try to optimize for this case at all
240        if (!inputColor) {
241            fragBuilder->codeAppendf("const vec4 ones = vec4(1);");
242            inputColor = "ones";
243        }
244
245        // emit blend code
246        fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
247        const char* childStr = childColor.c_str();
248        if (ComposeOneFragmentProcessor::kDst_Child == child) {
249            GrGLSLBlend::AppendMode(fragBuilder, inputColor, childStr, args.fOutputColor, mode);
250        } else {
251            GrGLSLBlend::AppendMode(fragBuilder, childStr, inputColor, args.fOutputColor, mode);
252        }
253    }
254
255private:
256    typedef GrGLSLFragmentProcessor INHERITED;
257};
258
259/////////////////////////////////////////////////////////////////////
260
261GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor);
262
263const GrFragmentProcessor* ComposeOneFragmentProcessor::TestCreate(GrProcessorTestData* d) {
264    // Create one random frag procs.
265    // For now, we'll prevent either children from being a shader with children to prevent the
266    // possibility of an arbitrarily large tree of procs.
267    SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d));
268    SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(
269        d->fRandom->nextRangeU(0, SkXfermode::kLastMode));
270    ComposeOneFragmentProcessor::Child child = d->fRandom->nextBool() ?
271        ComposeOneFragmentProcessor::kDst_Child :
272        ComposeOneFragmentProcessor::kSrc_Child;
273    return new ComposeOneFragmentProcessor(dst, mode, child);
274}
275
276GrGLSLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLSLInstance() const {
277    return new GLComposeOneFragmentProcessor;
278}
279
280//////////////////////////////////////////////////////////////////////////////
281
282const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromDstProcessor(
283    const GrFragmentProcessor* dst, SkXfermode::Mode mode) {
284    switch (mode) {
285        case SkXfermode::kClear_Mode:
286            return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
287                                                 GrConstColorProcessor::kIgnore_InputMode);
288        case SkXfermode::kSrc_Mode:
289            return nullptr;
290        default:
291            return new ComposeOneFragmentProcessor(dst, mode,
292                                                   ComposeOneFragmentProcessor::kDst_Child);
293    }
294}
295
296const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromSrcProcessor(
297    const GrFragmentProcessor* src, SkXfermode::Mode mode) {
298    switch (mode) {
299        case SkXfermode::kClear_Mode:
300            return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
301                                                 GrConstColorProcessor::kIgnore_InputMode);
302        case SkXfermode::kDst_Mode:
303            return nullptr;
304        default:
305            return new ComposeOneFragmentProcessor(src, mode,
306                                                   ComposeOneFragmentProcessor::kSrc_Child);
307    }
308}
309