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 
18 class ComposeTwoFragmentProcessor : public GrFragmentProcessor {
19 public:
ComposeTwoFragmentProcessor(const GrFragmentProcessor * src,const GrFragmentProcessor * dst,SkXfermode::Mode mode)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 
name() const30     const char* name() const override { return "ComposeTwo"; }
31 
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const32     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
33         b->add32(fMode);
34     }
35 
getMode() const36     SkXfermode::Mode getMode() const { return fMode; }
37 
38 protected:
onIsEqual(const GrFragmentProcessor & other) const39     bool onIsEqual(const GrFragmentProcessor& other) const override {
40         const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>();
41         return fMode == cs.fMode;
42     }
43 
onComputeInvariantOutput(GrInvariantOutput * inout) const44     void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
45         inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
46     }
47 
48 private:
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 
60 class GLComposeTwoFragmentProcessor : public GrGLSLFragmentProcessor {
61 public:
62     void emitCode(EmitArgs&) override;
63 
64 private:
65     typedef GrGLSLFragmentProcessor INHERITED;
66 };
67 
68 /////////////////////////////////////////////////////////////////////
69 
70 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor);
71 
TestCreate(GrProcessorTestData * d)72 const 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 
onCreateGLSLInstance() const82 GrGLSLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLSLInstance() const{
83     return new GLComposeTwoFragmentProcessor;
84 }
85 
86 /////////////////////////////////////////////////////////////////////
87 
emitCode(EmitArgs & args)88 void 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 
CreateFromTwoProcessors(const GrFragmentProcessor * src,const GrFragmentProcessor * dst,SkXfermode::Mode mode)121 const 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 
138 class ComposeOneFragmentProcessor : public GrFragmentProcessor {
139 public:
140     enum Child {
141         kDst_Child,
142         kSrc_Child,
143     };
144 
ComposeOneFragmentProcessor(const GrFragmentProcessor * dst,SkXfermode::Mode mode,Child child)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 
name() const153     const char* name() const override { return "ComposeOne"; }
154 
dumpInfo() const155     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 
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const164     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 
mode() const169     SkXfermode::Mode mode() const { return fMode; }
170 
child() const171     Child child() const { return fChild; }
172 
173 protected:
onIsEqual(const GrFragmentProcessor & that) const174     bool onIsEqual(const GrFragmentProcessor& that) const override {
175         return fMode == that.cast<ComposeOneFragmentProcessor>().fMode;
176     }
177 
onComputeInvariantOutput(GrInvariantOutput * inout) const178     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 
215 private:
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 
228 class GLComposeOneFragmentProcessor : public GrGLSLFragmentProcessor {
229 public:
emitCode(EmitArgs & args)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 
255 private:
256     typedef GrGLSLFragmentProcessor INHERITED;
257 };
258 
259 /////////////////////////////////////////////////////////////////////
260 
261 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor);
262 
TestCreate(GrProcessorTestData * d)263 const 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 
onCreateGLSLInstance() const276 GrGLSLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLSLInstance() const {
277     return new GLComposeOneFragmentProcessor;
278 }
279 
280 //////////////////////////////////////////////////////////////////////////////
281 
CreateFromDstProcessor(const GrFragmentProcessor * dst,SkXfermode::Mode mode)282 const 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 
CreateFromSrcProcessor(const GrFragmentProcessor * src,SkXfermode::Mode mode)296 const 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