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