blob: 942251c980942659b1795a86f85d15734b761dfd [file] [log] [blame]
wangyix809e5af2015-09-09 12:58:32 -07001/*
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"
bsalomonae4738f2015-09-15 15:33:27 -070012#include "gl/GrGLSLBlend.h"
wangyix809e5af2015-09-09 12:58:32 -070013#include "gl/builders/GrGLProgramBuilder.h"
bsalomonae4738f2015-09-15 15:33:27 -070014#include "SkGr.h"
wangyix809e5af2015-09-09 12:58:32 -070015
bsalomonae4738f2015-09-15 15:33:27 -070016class ComposeTwoFragmentProcessor : public GrFragmentProcessor {
wangyix809e5af2015-09-09 12:58:32 -070017public:
bsalomonae4738f2015-09-15 15:33:27 -070018 ComposeTwoFragmentProcessor(const GrFragmentProcessor* src, const GrFragmentProcessor* dst,
wangyix809e5af2015-09-09 12:58:32 -070019 SkXfermode::Mode mode)
20 : fMode(mode) {
bsalomonae4738f2015-09-15 15:33:27 -070021 this->initClassID<ComposeTwoFragmentProcessor>();
wangyix809e5af2015-09-09 12:58:32 -070022 SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(src);
23 SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(dst);
24 SkASSERT(0 == shaderAChildIndex);
25 SkASSERT(1 == shaderBChildIndex);
26 }
27
bsalomonae4738f2015-09-15 15:33:27 -070028 const char* name() const override { return "ComposeTwo"; }
wangyix809e5af2015-09-09 12:58:32 -070029
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 {
bsalomonae4738f2015-09-15 15:33:27 -070038 const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>();
wangyix809e5af2015-09-09 12:58:32 -070039 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
bsalomonae4738f2015-09-15 15:33:27 -070058class GLComposeTwoFragmentProcessor : public GrGLFragmentProcessor {
wangyix809e5af2015-09-09 12:58:32 -070059public:
bsalomonae4738f2015-09-15 15:33:27 -070060 GLComposeTwoFragmentProcessor(const GrProcessor& processor) {}
wangyix809e5af2015-09-09 12:58:32 -070061
62 void emitCode(EmitArgs&) override;
63
64private:
65 typedef GrGLFragmentProcessor INHERITED;
66};
67
68/////////////////////////////////////////////////////////////////////
69
bsalomonae4738f2015-09-15 15:33:27 -070070GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor);
wangyix809e5af2015-09-09 12:58:32 -070071
bsalomonae4738f2015-09-15 15:33:27 -070072const GrFragmentProcessor* ComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) {
wangyix809e5af2015-09-09 12:58:32 -070073 // Create two random frag procs.
bsalomon506c8022015-09-14 13:16:26 -070074 SkAutoTUnref<const GrFragmentProcessor> fpA(GrProcessorUnitTest::CreateChildFP(d));
75 SkAutoTUnref<const GrFragmentProcessor> fpB(GrProcessorUnitTest::CreateChildFP(d));
wangyix809e5af2015-09-09 12:58:32 -070076
77 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(
bsalomonae4738f2015-09-15 15:33:27 -070078 d->fRandom->nextRangeU(0, SkXfermode::kLastMode));
79 return new ComposeTwoFragmentProcessor(fpA, fpB, mode);
wangyix809e5af2015-09-09 12:58:32 -070080}
81
bsalomonae4738f2015-09-15 15:33:27 -070082GrGLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLInstance() const{
83 return new GLComposeTwoFragmentProcessor(*this);
wangyix809e5af2015-09-09 12:58:32 -070084}
85
86/////////////////////////////////////////////////////////////////////
87
bsalomonae4738f2015-09-15 15:33:27 -070088void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
wangyix809e5af2015-09-09 12:58:32 -070089
90 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
bsalomonae4738f2015-09-15 15:33:27 -070091 const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProcessor>();
wangyix809e5af2015-09-09 12:58:32 -070092
93 // Store alpha of input color and un-premultiply the input color by its alpha. We will
94 // re-multiply by this alpha after blending the output colors of the two child procs.
95 // This is because we don't want the paint's alpha to affect either child proc's output
96 // before the blend; we want to apply the paint's alpha AFTER the blend. This mirrors the
97 // software implementation of SkComposeShader.
bsalomonb5b60322015-09-14 12:26:33 -070098 const char* opaqueInput = nullptr;
99 const char* inputAlpha = nullptr;
100 if (args.fInputColor) {
101 inputAlpha = "inputAlpha";
102 opaqueInput = "opaqueInput";
103 fsBuilder->codeAppendf("float inputAlpha = %s.a;", args.fInputColor);
104 fsBuilder->codeAppendf("vec4 opaqueInput = vec4(%s.rgb / inputAlpha, 1);",
105 args.fInputColor);
106 }
wangyix809e5af2015-09-09 12:58:32 -0700107
108 // declare outputColor and emit the code for each of the two children
109 SkString outputColorSrc(args.fOutputColor);
110 outputColorSrc.append("_src");
111 fsBuilder->codeAppendf("vec4 %s;\n", outputColorSrc.c_str());
bsalomonb5b60322015-09-14 12:26:33 -0700112 this->emitChild(0, opaqueInput, outputColorSrc.c_str(), args);
wangyix809e5af2015-09-09 12:58:32 -0700113
114 SkString outputColorDst(args.fOutputColor);
115 outputColorDst.append("_dst");
116 fsBuilder->codeAppendf("vec4 %s;\n", outputColorDst.c_str());
bsalomonb5b60322015-09-14 12:26:33 -0700117 this->emitChild(1, opaqueInput, outputColorDst.c_str(), args);
wangyix809e5af2015-09-09 12:58:32 -0700118
119 // emit blend code
120 SkXfermode::Mode mode = cs.getMode();
121 fsBuilder->codeAppend("{");
122 fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
bsalomonae4738f2015-09-15 15:33:27 -0700123 GrGLSLBlend::AppendMode(fsBuilder, outputColorSrc.c_str(),
124 outputColorDst.c_str(), args.fOutputColor, mode);
wangyix809e5af2015-09-09 12:58:32 -0700125 fsBuilder->codeAppend("}");
126
127 // re-multiply the output color by the input color's alpha
bsalomonb5b60322015-09-14 12:26:33 -0700128 if (inputAlpha) {
129 fsBuilder->codeAppendf("%s *= %s;", args.fOutputColor, inputAlpha);
130 }
wangyix809e5af2015-09-09 12:58:32 -0700131}
132
wangyix809e5af2015-09-09 12:58:32 -0700133const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromTwoProcessors(
134 const GrFragmentProcessor* src, const GrFragmentProcessor* dst, SkXfermode::Mode mode) {
wangyix809e5af2015-09-09 12:58:32 -0700135 switch (mode) {
136 case SkXfermode::kClear_Mode:
bsalomonae4738f2015-09-15 15:33:27 -0700137 return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
wangyix809e5af2015-09-09 12:58:32 -0700138 GrConstColorProcessor::kIgnore_InputMode);
wangyix809e5af2015-09-09 12:58:32 -0700139 case SkXfermode::kSrc_Mode:
wangyix809e5af2015-09-09 12:58:32 -0700140 return SkRef(src);
wangyix809e5af2015-09-09 12:58:32 -0700141 case SkXfermode::kDst_Mode:
wangyix809e5af2015-09-09 12:58:32 -0700142 return SkRef(dst);
wangyix809e5af2015-09-09 12:58:32 -0700143 default:
bsalomonae4738f2015-09-15 15:33:27 -0700144 return new ComposeTwoFragmentProcessor(src, dst, mode);
145 }
146}
147
148//////////////////////////////////////////////////////////////////////////////
149
150class ComposeOneFragmentProcessor : public GrFragmentProcessor {
151public:
152 enum Child {
153 kDst_Child,
154 kSrc_Child,
155 };
156
157 ComposeOneFragmentProcessor(const GrFragmentProcessor* dst, SkXfermode::Mode mode, Child child)
158 : fMode(mode)
159 , fChild(child) {
160 this->initClassID<ComposeOneFragmentProcessor>();
161 SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst);
162 SkASSERT(0 == dstIndex);
163 }
164
165 const char* name() const override { return "ComposeOne"; }
166
167 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
168 GR_STATIC_ASSERT((SkXfermode::kLastMode & SK_MaxU16) == SkXfermode::kLastMode);
169 b->add32(fMode | (fChild << 16));
170 }
171
172 SkXfermode::Mode mode() const { return fMode; }
173
174 Child child() const { return fChild; }
175
176protected:
177 bool onIsEqual(const GrFragmentProcessor& that) const override {
178 return fMode == that.cast<ComposeOneFragmentProcessor>().fMode;
179 }
180
181 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
182 SkXfermode::Coeff skSrcCoeff, skDstCoeff;
183 if (SkXfermode::ModeAsCoeff(fMode, &skSrcCoeff, &skDstCoeff)) {
184 GrBlendCoeff srcCoeff = SkXfermodeCoeffToGrBlendCoeff(skSrcCoeff);
185 GrBlendCoeff dstCoeff = SkXfermodeCoeffToGrBlendCoeff(skDstCoeff);
186 GrInvariantOutput childOutput(0xFFFFFFFF, kRGBA_GrColorComponentFlags, false);
187 this->childProcessor(0).computeInvariantOutput(&childOutput);
188 GrColor blendColor;
189 GrColorComponentFlags blendFlags;
190 if (kDst_Child == fChild) {
191 GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff,
192 inout->color(), inout->validFlags(),
193 childOutput.color(), childOutput.validFlags(),
194 &blendColor, &blendFlags);
195 } else {
196 GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff,
197 childOutput.color(), childOutput.validFlags(),
198 inout->color(), inout->validFlags(),
199 &blendColor, &blendFlags);
200 }
201 // will the shader code reference the input color?
202 GrInvariantOutput::ReadInput readsInput = GrInvariantOutput::kWillNot_ReadInput;
203 if (kDst_Child == fChild) {
204 if (kZero_GrBlendCoeff != srcCoeff || GrBlendCoeffRefsSrc(dstCoeff)) {
205 readsInput = GrInvariantOutput::kWill_ReadInput;
206 }
207 } else {
208 if (kZero_GrBlendCoeff != dstCoeff || GrBlendCoeffRefsDst(srcCoeff)) {
209 readsInput = GrInvariantOutput::kWill_ReadInput;
210 }
211 }
212 inout->setToOther(blendFlags, blendColor, readsInput);
213 } else {
214 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
215 }
216 }
217
218private:
219 GrGLFragmentProcessor* onCreateGLInstance() const override;
220
221 SkXfermode::Mode fMode;
222 Child fChild;
223
224 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
225
226 typedef GrFragmentProcessor INHERITED;
227};
228
229//////////////////////////////////////////////////////////////////////////////
230
231class GLComposeOneFragmentProcessor : public GrGLFragmentProcessor {
232public:
233 GLComposeOneFragmentProcessor(const GrProcessor& processor) {}
234
235 void emitCode(EmitArgs& args) override {
236 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
237 SkXfermode::Mode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode();
238 ComposeOneFragmentProcessor::Child child =
239 args.fFp.cast<ComposeOneFragmentProcessor>().child();
240 // declare _dstColor and emit the code for the two child
241 fsBuilder->codeAppendf("vec4 _child;");
242 this->emitChild(0, nullptr, "_child", args);
243
244 const char* inputColor = args.fInputColor;
245 // We don't try to optimize for this case at all
246 if (!inputColor) {
247 fsBuilder->codeAppendf("const vec4 ones = vec4(1);");
248 inputColor = "ones";
249 }
250
251 // emit blend code
252 fsBuilder->codeAppend("{");
253 fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
254 if (ComposeOneFragmentProcessor::kDst_Child == child) {
255 GrGLSLBlend::AppendMode(fsBuilder, inputColor, "_child", args.fOutputColor, mode);
256 } else {
257 GrGLSLBlend::AppendMode(fsBuilder, "_child", inputColor, args.fOutputColor, mode);
258 }
259 fsBuilder->codeAppend("}");
260 }
261
262private:
263 typedef GrGLFragmentProcessor INHERITED;
264};
265
266/////////////////////////////////////////////////////////////////////
267
268GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor);
269
270const GrFragmentProcessor* ComposeOneFragmentProcessor::TestCreate(GrProcessorTestData* d) {
271 // Create one random frag procs.
272 // For now, we'll prevent either children from being a shader with children to prevent the
273 // possibility of an arbitrarily large tree of procs.
274 SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d));
275 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(
276 d->fRandom->nextRangeU(0, SkXfermode::kLastMode));
277 ComposeOneFragmentProcessor::Child child = d->fRandom->nextBool() ?
278 ComposeOneFragmentProcessor::kDst_Child :
279 ComposeOneFragmentProcessor::kSrc_Child;
280 return new ComposeOneFragmentProcessor(dst, mode, child);
281}
282
283GrGLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLInstance() const {
284 return new GLComposeOneFragmentProcessor(*this);
285}
286
287//////////////////////////////////////////////////////////////////////////////
288
289const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromDstProcessor(
290 const GrFragmentProcessor* dst, SkXfermode::Mode mode) {
291 switch (mode) {
292 case SkXfermode::kClear_Mode:
293 return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
294 GrConstColorProcessor::kIgnore_InputMode);
295 case SkXfermode::kSrc_Mode:
296 return nullptr;
297 default:
298 return new ComposeOneFragmentProcessor(dst, mode,
299 ComposeOneFragmentProcessor::kDst_Child);
300 }
301}
302
303const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromSrcProcessor(
304 const GrFragmentProcessor* src, SkXfermode::Mode mode) {
305 switch (mode) {
306 case SkXfermode::kClear_Mode:
307 return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
308 GrConstColorProcessor::kIgnore_InputMode);
309 case SkXfermode::kDst_Mode:
310 return nullptr;
311 default:
312 return new ComposeOneFragmentProcessor(src, mode,
313 ComposeOneFragmentProcessor::kSrc_Child);
wangyix809e5af2015-09-09 12:58:32 -0700314 }
315}