Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/gpu/effects/GrBlendFragmentProcessor.cpp
Line
Count
Source (jump to first uncovered line)
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.
17
73.4k
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
73.4k
    return mode <= SkBlendMode::kLastSeparableMode && mode != SkBlendMode::kSoftLight &&
22
73.1k
           mode != SkBlendMode::kColorBurn;
23
73.4k
}
24
25
//////////////////////////////////////////////////////////////////////////////
26
27
class BlendFragmentProcessor : public GrFragmentProcessor {
28
public:
29
    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> src,
30
                                                     std::unique_ptr<GrFragmentProcessor> dst,
31
73.4k
                                                     SkBlendMode mode) {
32
73.4k
        return std::unique_ptr<GrFragmentProcessor>(
33
73.4k
                new BlendFragmentProcessor(std::move(src), std::move(dst), mode));
34
73.4k
    }
35
36
0
    const char* name() const override { return "Blend"; }
37
38
    std::unique_ptr<GrFragmentProcessor> clone() const override;
39
40
private:
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
73.4k
            , fMode(mode) {
46
73.4k
        this->setIsBlendFunction();
47
73.4k
        this->registerChild(std::move(src));
48
73.4k
        this->registerChild(std::move(dst));
49
73.4k
    }
50
51
    BlendFragmentProcessor(const BlendFragmentProcessor& that)
52
            : INHERITED(that)
53
4
            , fMode(that.fMode) {}
54
55
#if GR_TEST_UTILS
56
0
    SkString onDumpInfo() const override {
57
0
        return SkStringPrintf("(fMode=%s)", SkBlendMode_Name(fMode));
58
0
    }
59
#endif
60
61
    static OptimizationFlags OptFlags(const GrFragmentProcessor* src,
62
73.4k
                                      const GrFragmentProcessor* dst, SkBlendMode mode) {
63
73.4k
        OptimizationFlags flags;
64
73.4k
        switch (mode) {
65
0
            case SkBlendMode::kClear:
66
0
            case SkBlendMode::kSrc:
67
0
            case SkBlendMode::kDst:
68
0
                SkDEBUGFAIL("Shouldn't have created a Blend FP as 'clear', 'src', or 'dst'.");
69
0
                flags = kNone_OptimizationFlags;
70
0
                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
2.70k
            case SkBlendMode::kSrcIn:
76
40.9k
            case SkBlendMode::kDstIn:
77
73.1k
            case SkBlendMode::kModulate:
78
73.1k
                if (src && dst) {
79
1.01k
                    flags = ProcessorOptimizationFlags(src) & ProcessorOptimizationFlags(dst) &
80
1.01k
                            kPreservesOpaqueInput_OptimizationFlag;
81
72.1k
                } else if (src) {
82
41.4k
                    flags = ProcessorOptimizationFlags(src) &
83
41.4k
                            ~kConstantOutputForConstantInput_OptimizationFlag;
84
30.7k
                } else if (dst) {
85
30.7k
                    flags = ProcessorOptimizationFlags(dst) &
86
30.7k
                            ~kConstantOutputForConstantInput_OptimizationFlag;
87
0
                } else {
88
0
                    flags = kNone_OptimizationFlags;
89
0
                }
90
73.1k
                break;
91
92
            // Produces zero when both are opaque, indeterminate if one is opaque.
93
1
            case SkBlendMode::kSrcOut:
94
4
            case SkBlendMode::kDstOut:
95
4
            case SkBlendMode::kXor:
96
4
                flags = kNone_OptimizationFlags;
97
4
                break;
98
99
            // Is opaque if the dst is opaque.
100
0
            case SkBlendMode::kSrcATop:
101
0
                flags = ProcessorOptimizationFlags(dst) & kPreservesOpaqueInput_OptimizationFlag;
102
0
                break;
103
104
            // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque.
105
2
            case SkBlendMode::kDstATop:
106
2
            case SkBlendMode::kScreen:
107
2
                flags = ProcessorOptimizationFlags(src) & kPreservesOpaqueInput_OptimizationFlag;
108
2
                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
0
            case SkBlendMode::kSrcOver:
113
0
            case SkBlendMode::kDstOver:
114
1
            case SkBlendMode::kPlus:
115
1
            case SkBlendMode::kOverlay:
116
1
            case SkBlendMode::kDarken:
117
1
            case SkBlendMode::kLighten:
118
1
            case SkBlendMode::kColorDodge:
119
2
            case SkBlendMode::kColorBurn:
120
5
            case SkBlendMode::kHardLight:
121
5
            case SkBlendMode::kSoftLight:
122
5
            case SkBlendMode::kDifference:
123
5
            case SkBlendMode::kExclusion:
124
5
            case SkBlendMode::kMultiply:
125
5
            case SkBlendMode::kHue:
126
5
            case SkBlendMode::kSaturation:
127
5
            case SkBlendMode::kColor:
128
223
            case SkBlendMode::kLuminosity:
129
223
                flags = (ProcessorOptimizationFlags(src) | ProcessorOptimizationFlags(dst)) &
130
223
                        kPreservesOpaqueInput_OptimizationFlag;
131
223
                break;
132
73.4k
        }
133
73.4k
        if (does_cpu_blend_impl_match_gpu(mode) &&
134
73.1k
            (!src || src->hasConstantOutputForConstantInput()) &&
135
33.0k
            (!dst || dst->hasConstantOutputForConstantInput())) {
136
1.63k
            flags |= kConstantOutputForConstantInput_OptimizationFlag;
137
1.63k
        }
138
73.4k
        return flags;
139
73.4k
    }
140
141
0
    void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
142
0
        b->add32((int)fMode);
143
0
    }
144
145
56.4k
    bool onIsEqual(const GrFragmentProcessor& other) const override {
146
56.4k
        const BlendFragmentProcessor& cs = other.cast<BlendFragmentProcessor>();
147
56.4k
        return fMode == cs.fMode;
148
56.4k
    }
149
150
28
    SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
151
28
        const auto* src = this->childProcessor(0);
152
28
        const auto* dst = this->childProcessor(1);
153
154
28
        SkPMColor4f srcColor = ConstantOutputForConstantInput(src, input);
155
28
        SkPMColor4f dstColor = ConstantOutputForConstantInput(dst, input);
156
157
28
        return SkBlendMode_Apply(fMode, srcColor, dstColor);
158
28
    }
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
175
0
std::unique_ptr<GrFragmentProcessor> BlendFragmentProcessor::TestCreate(GrProcessorTestData* d) {
176
    // Create one or two random fragment processors.
177
0
    std::unique_ptr<GrFragmentProcessor> src(GrProcessorUnitTest::MakeOptionalChildFP(d));
178
0
    std::unique_ptr<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d));
179
0
    if (d->fRandom->nextBool()) {
180
0
        std::swap(src, dst);
181
0
    }
182
183
0
    SkBlendMode mode;
184
0
    do {
185
0
        mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
186
0
    } while (SkBlendMode::kClear == mode || SkBlendMode::kSrc == mode || SkBlendMode::kDst == mode);
187
0
    return std::unique_ptr<GrFragmentProcessor>(
188
0
            new BlendFragmentProcessor(std::move(src), std::move(dst), mode));
189
0
}
190
#endif
191
192
4
std::unique_ptr<GrFragmentProcessor> BlendFragmentProcessor::clone() const {
193
4
    return std::unique_ptr<GrFragmentProcessor>(new BlendFragmentProcessor(*this));
194
4
}
195
196
0
std::unique_ptr<GrFragmentProcessor::ProgramImpl> BlendFragmentProcessor::onMakeProgramImpl() const {
197
0
    class Impl : public ProgramImpl {
198
0
    public:
199
0
        void emitCode(EmitArgs& args) override {
200
0
            GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
201
0
            const BlendFragmentProcessor& bfp = args.fFp.cast<BlendFragmentProcessor>();
202
0
            SkBlendMode mode = bfp.fMode;
203
204
0
            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
0
            SkString srcColor = this->invokeChild(0, args);
208
0
            SkString dstColor = this->invokeChild(1, args);
209
210
            // Blend src and dst colors together.
211
0
            fragBuilder->codeAppendf("return %s(%s, %s);",
212
0
                                     GrGLSLBlend::BlendFuncName(mode),
213
0
                                     srcColor.c_str(),
214
0
                                     dstColor.c_str());
215
0
        }
216
0
    };
217
218
0
    return std::make_unique<Impl>();
219
0
}
220
221
//////////////////////////////////////////////////////////////////////////////
222
223
std::unique_ptr<GrFragmentProcessor> GrBlendFragmentProcessor::Make(
224
        std::unique_ptr<GrFragmentProcessor> src,
225
        std::unique_ptr<GrFragmentProcessor> dst,
226
75.8k
        SkBlendMode mode) {
227
75.8k
    switch (mode) {
228
833
        case SkBlendMode::kClear:
229
833
            return GrFragmentProcessor::MakeColor(SK_PMColor4fTRANSPARENT);
230
313
        case SkBlendMode::kSrc:
231
313
            return src;
232
1.31k
        case SkBlendMode::kDst:
233
1.31k
            return dst;
234
73.4k
        default:
235
73.4k
            return BlendFragmentProcessor::Make(std::move(src), std::move(dst), mode);
236
75.8k
    }
237
75.8k
}