• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/gpu/effects/GrBlendFragmentProcessor.h"
9 
10 #include "src/gpu/GrFragmentProcessor.h"
11 #include "src/gpu/SkGr.h"
12 #include "src/gpu/glsl/GrGLSLBlend.h"
13 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
14 
15 // Some of the CPU implementations of blend modes differ from the GPU enough that
16 // we can't use the CPU implementation to implement constantOutputForConstantInput.
does_cpu_blend_impl_match_gpu(SkBlendMode mode)17 static inline bool does_cpu_blend_impl_match_gpu(SkBlendMode mode) {
18     // The non-separable modes differ too much. So does SoftLight. ColorBurn differs too much on our
19     // test iOS device, but we just disable it across the board since it might differ on untested
20     // GPUs.
21     return mode <= SkBlendMode::kLastSeparableMode && mode != SkBlendMode::kSoftLight &&
22            mode != SkBlendMode::kColorBurn;
23 }
24 
25 //////////////////////////////////////////////////////////////////////////////
26 
27 class BlendFragmentProcessor : public GrFragmentProcessor {
28 public:
Make(std::unique_ptr<GrFragmentProcessor> src,std::unique_ptr<GrFragmentProcessor> dst,SkBlendMode mode)29     static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> src,
30                                                      std::unique_ptr<GrFragmentProcessor> dst,
31                                                      SkBlendMode mode) {
32         return std::unique_ptr<GrFragmentProcessor>(
33                 new BlendFragmentProcessor(std::move(src), std::move(dst), mode));
34     }
35 
name() const36     const char* name() const override { return "Blend"; }
37 
38     std::unique_ptr<GrFragmentProcessor> clone() const override;
39 
40 private:
BlendFragmentProcessor(std::unique_ptr<GrFragmentProcessor> src,std::unique_ptr<GrFragmentProcessor> dst,SkBlendMode mode)41     BlendFragmentProcessor(std::unique_ptr<GrFragmentProcessor> src,
42                            std::unique_ptr<GrFragmentProcessor> dst,
43                            SkBlendMode mode)
44             : INHERITED(kBlendFragmentProcessor_ClassID, OptFlags(src.get(), dst.get(), mode))
45             , fMode(mode) {
46         this->setIsBlendFunction();
47         this->registerChild(std::move(src));
48         this->registerChild(std::move(dst));
49     }
50 
BlendFragmentProcessor(const BlendFragmentProcessor & that)51     BlendFragmentProcessor(const BlendFragmentProcessor& that)
52             : INHERITED(that)
53             , fMode(that.fMode) {}
54 
55 #if GR_TEST_UTILS
onDumpInfo() const56     SkString onDumpInfo() const override {
57         return SkStringPrintf("(fMode=%s)", SkBlendMode_Name(fMode));
58     }
59 #endif
60 
OptFlags(const GrFragmentProcessor * src,const GrFragmentProcessor * dst,SkBlendMode mode)61     static OptimizationFlags OptFlags(const GrFragmentProcessor* src,
62                                       const GrFragmentProcessor* dst, SkBlendMode mode) {
63         OptimizationFlags flags;
64         switch (mode) {
65             case SkBlendMode::kClear:
66             case SkBlendMode::kSrc:
67             case SkBlendMode::kDst:
68                 SkDEBUGFAIL("Shouldn't have created a Blend FP as 'clear', 'src', or 'dst'.");
69                 flags = kNone_OptimizationFlags;
70                 break;
71 
72             // Produces opaque if both src and dst are opaque. These also will modulate the child's
73             // output by either the input color or alpha. However, if the child is not compatible
74             // with the coverage as alpha then it may produce a color that is not valid premul.
75             case SkBlendMode::kSrcIn:
76             case SkBlendMode::kDstIn:
77             case SkBlendMode::kModulate:
78                 if (src && dst) {
79                     flags = ProcessorOptimizationFlags(src) & ProcessorOptimizationFlags(dst) &
80                             kPreservesOpaqueInput_OptimizationFlag;
81                 } else if (src) {
82                     flags = ProcessorOptimizationFlags(src) &
83                             ~kConstantOutputForConstantInput_OptimizationFlag;
84                 } else if (dst) {
85                     flags = ProcessorOptimizationFlags(dst) &
86                             ~kConstantOutputForConstantInput_OptimizationFlag;
87                 } else {
88                     flags = kNone_OptimizationFlags;
89                 }
90                 break;
91 
92             // Produces zero when both are opaque, indeterminate if one is opaque.
93             case SkBlendMode::kSrcOut:
94             case SkBlendMode::kDstOut:
95             case SkBlendMode::kXor:
96                 flags = kNone_OptimizationFlags;
97                 break;
98 
99             // Is opaque if the dst is opaque.
100             case SkBlendMode::kSrcATop:
101                 flags = ProcessorOptimizationFlags(dst) & kPreservesOpaqueInput_OptimizationFlag;
102                 break;
103 
104             // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque.
105             case SkBlendMode::kDstATop:
106             case SkBlendMode::kScreen:
107                 flags = ProcessorOptimizationFlags(src) & kPreservesOpaqueInput_OptimizationFlag;
108                 break;
109 
110             // These modes are all opaque if either src or dst is opaque. All the advanced modes
111             // compute alpha as src-over.
112             case SkBlendMode::kSrcOver:
113             case SkBlendMode::kDstOver:
114             case SkBlendMode::kPlus:
115             case SkBlendMode::kOverlay:
116             case SkBlendMode::kDarken:
117             case SkBlendMode::kLighten:
118             case SkBlendMode::kColorDodge:
119             case SkBlendMode::kColorBurn:
120             case SkBlendMode::kHardLight:
121             case SkBlendMode::kSoftLight:
122             case SkBlendMode::kDifference:
123             case SkBlendMode::kExclusion:
124             case SkBlendMode::kMultiply:
125             case SkBlendMode::kHue:
126             case SkBlendMode::kSaturation:
127             case SkBlendMode::kColor:
128             case SkBlendMode::kLuminosity:
129                 flags = (ProcessorOptimizationFlags(src) | ProcessorOptimizationFlags(dst)) &
130                         kPreservesOpaqueInput_OptimizationFlag;
131                 break;
132         }
133         if (does_cpu_blend_impl_match_gpu(mode) &&
134             (!src || src->hasConstantOutputForConstantInput()) &&
135             (!dst || dst->hasConstantOutputForConstantInput())) {
136             flags |= kConstantOutputForConstantInput_OptimizationFlag;
137         }
138         return flags;
139     }
140 
onAddToKey(const GrShaderCaps &,GrProcessorKeyBuilder * b) const141     void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
142         b->add32((int)fMode);
143     }
144 
onIsEqual(const GrFragmentProcessor & other) const145     bool onIsEqual(const GrFragmentProcessor& other) const override {
146         const BlendFragmentProcessor& cs = other.cast<BlendFragmentProcessor>();
147         return fMode == cs.fMode;
148     }
149 
constantOutputForConstantInput(const SkPMColor4f & input) const150     SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
151         const auto* src = this->childProcessor(0);
152         const auto* dst = this->childProcessor(1);
153 
154         SkPMColor4f srcColor = ConstantOutputForConstantInput(src, input);
155         SkPMColor4f dstColor = ConstantOutputForConstantInput(dst, input);
156 
157         return SkBlendMode_Apply(fMode, srcColor, dstColor);
158     }
159 
160     std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override;
161 
162     SkBlendMode fMode;
163 
164     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
165 
166     using INHERITED = GrFragmentProcessor;
167 };
168 
169 /////////////////////////////////////////////////////////////////////
170 
171 
172 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BlendFragmentProcessor);
173 
174 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)175 std::unique_ptr<GrFragmentProcessor> BlendFragmentProcessor::TestCreate(GrProcessorTestData* d) {
176     // Create one or two random fragment processors.
177     std::unique_ptr<GrFragmentProcessor> src(GrProcessorUnitTest::MakeOptionalChildFP(d));
178     std::unique_ptr<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d));
179     if (d->fRandom->nextBool()) {
180         std::swap(src, dst);
181     }
182 
183     SkBlendMode mode;
184     do {
185         mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
186     } while (SkBlendMode::kClear == mode || SkBlendMode::kSrc == mode || SkBlendMode::kDst == mode);
187     return std::unique_ptr<GrFragmentProcessor>(
188             new BlendFragmentProcessor(std::move(src), std::move(dst), mode));
189 }
190 #endif
191 
clone() const192 std::unique_ptr<GrFragmentProcessor> BlendFragmentProcessor::clone() const {
193     return std::unique_ptr<GrFragmentProcessor>(new BlendFragmentProcessor(*this));
194 }
195 
onMakeProgramImpl() const196 std::unique_ptr<GrFragmentProcessor::ProgramImpl> BlendFragmentProcessor::onMakeProgramImpl() const {
197     class Impl : public ProgramImpl {
198     public:
199         void emitCode(EmitArgs& args) override {
200             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
201             const BlendFragmentProcessor& bfp = args.fFp.cast<BlendFragmentProcessor>();
202             SkBlendMode mode = bfp.fMode;
203 
204             fragBuilder->codeAppendf("// Blend mode: %s\n", SkBlendMode_Name(mode));
205 
206             // Invoke src/dst with our input color (or substitute input color if no child FP)
207             SkString srcColor = this->invokeChild(0, args);
208             SkString dstColor = this->invokeChild(1, args);
209 
210             // Blend src and dst colors together.
211             fragBuilder->codeAppendf("return %s(%s, %s);",
212                                      GrGLSLBlend::BlendFuncName(mode),
213                                      srcColor.c_str(),
214                                      dstColor.c_str());
215         }
216     };
217 
218     return std::make_unique<Impl>();
219 }
220 
221 //////////////////////////////////////////////////////////////////////////////
222 
Make(std::unique_ptr<GrFragmentProcessor> src,std::unique_ptr<GrFragmentProcessor> dst,SkBlendMode mode)223 std::unique_ptr<GrFragmentProcessor> GrBlendFragmentProcessor::Make(
224         std::unique_ptr<GrFragmentProcessor> src,
225         std::unique_ptr<GrFragmentProcessor> dst,
226         SkBlendMode mode) {
227     switch (mode) {
228         case SkBlendMode::kClear:
229             return GrFragmentProcessor::MakeColor(SK_PMColor4fTRANSPARENT);
230         case SkBlendMode::kSrc:
231             return src;
232         case SkBlendMode::kDst:
233             return dst;
234         default:
235             return BlendFragmentProcessor::Make(std::move(src), std::move(dst), mode);
236     }
237 }
238