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