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