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