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