Coverage Report

Created: 2024-09-14 07:19

/src/skia/src/gpu/ganesh/GrXferProcessor.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/ganesh/GrXferProcessor.h"
9
10
#include "include/core/SkBlendMode.h"
11
#include "include/core/SkString.h"
12
#include "include/gpu/ganesh/GrTypes.h"
13
#include "src/gpu/KeyBuilder.h"
14
#include "src/gpu/ganesh/GrCaps.h"
15
#include "src/gpu/ganesh/GrShaderCaps.h"
16
#include "src/gpu/ganesh/effects/GrCustomXfermode.h"
17
#include "src/gpu/ganesh/effects/GrPorterDuffXferProcessor.h"
18
#include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
19
20
#include <cstdint>
21
22
enum class GrClampType;
23
24
GrXferProcessor::GrXferProcessor(ClassID classID)
25
        : INHERITED(classID)
26
        , fWillReadDstColor(false)
27
45.9k
        , fIsLCD(false) {}
28
29
GrXferProcessor::GrXferProcessor(ClassID classID, bool willReadDstColor,
30
                                 GrProcessorAnalysisCoverage coverage)
31
        : INHERITED(classID)
32
        , fWillReadDstColor(willReadDstColor)
33
197k
        , fIsLCD(GrProcessorAnalysisCoverage::kLCD == coverage) {}
34
35
0
bool GrXferProcessor::hasSecondaryOutput() const {
36
0
    if (!this->willReadDstColor()) {
37
0
        return this->onHasSecondaryOutput();
38
0
    }
39
0
    return false;
40
0
}
41
42
void GrXferProcessor::addToKey(const GrShaderCaps& caps,
43
                               skgpu::KeyBuilder* b,
44
                               const GrSurfaceOrigin* originIfDstTexture,
45
0
                               bool usesInputAttachmentForDstRead) const {
46
0
    uint32_t key = this->willReadDstColor() ? 0x1 : 0x0;
47
0
    if (key) {
48
0
        if (originIfDstTexture) {
49
0
            key |= 0x2;
50
0
            if (kTopLeft_GrSurfaceOrigin == *originIfDstTexture) {
51
0
                key |= 0x4;
52
0
            }
53
0
            if (usesInputAttachmentForDstRead) {
54
0
                key |= 0x8;
55
0
            }
56
0
        }
57
0
    }
58
0
    if (fIsLCD) {
59
0
        key |= 0x10;
60
0
    }
61
0
    b->add32(key);
62
0
    this->onAddToKey(caps, b);
63
0
}
64
65
///////////////////////////////////////////////////////////////////////////////
66
67
GrXPFactory::AnalysisProperties GrXPFactory::GetAnalysisProperties(
68
        const GrXPFactory* factory,
69
        const GrProcessorAnalysisColor& color,
70
        const GrProcessorAnalysisCoverage& coverage,
71
        const GrCaps& caps,
72
326k
        GrClampType clampType) {
73
326k
    AnalysisProperties result;
74
326k
    if (factory) {
75
243k
        result = factory->analysisProperties(color, coverage, caps, clampType);
76
243k
    } else {
77
83.7k
        result = GrPorterDuffXPFactory::SrcOverAnalysisProperties(color, coverage, caps, clampType);
78
83.7k
    }
79
326k
    if (coverage == GrProcessorAnalysisCoverage::kNone) {
80
233k
        result |= AnalysisProperties::kCompatibleWithCoverageAsAlpha;
81
233k
    }
82
326k
    SkASSERT(!(result & AnalysisProperties::kRequiresDstTexture));
83
326k
    if ((result & AnalysisProperties::kReadsDstInShader) &&
84
326k
        !caps.shaderCaps()->fDstReadInShaderSupport) {
85
37.1k
        result |= AnalysisProperties::kRequiresDstTexture |
86
37.1k
                  AnalysisProperties::kRequiresNonOverlappingDraws;
87
37.1k
    }
88
326k
    return result;
89
326k
}
90
91
sk_sp<const GrXferProcessor> GrXPFactory::MakeXferProcessor(const GrXPFactory* factory,
92
                                                            const GrProcessorAnalysisColor& color,
93
                                                            GrProcessorAnalysisCoverage coverage,
94
                                                            const GrCaps& caps,
95
326k
                                                            GrClampType clampType) {
96
326k
    if (factory) {
97
243k
        return factory->makeXferProcessor(color, coverage, caps, clampType);
98
243k
    } else {
99
83.7k
        return GrPorterDuffXPFactory::MakeSrcOverXferProcessor(color, coverage, caps);
100
83.7k
    }
101
326k
}
102
103
239k
const GrXPFactory* GrXPFactory::FromBlendMode(SkBlendMode mode) {
104
239k
    if (SkBlendMode_AsCoeff(mode, nullptr, nullptr)) {
105
186k
        const GrXPFactory* result = GrPorterDuffXPFactory::Get(mode);
106
186k
        SkASSERT(result);
107
186k
        return result;
108
186k
    }
109
110
52.6k
    SkASSERT(GrCustomXfermode::IsSupportedMode(mode));
111
52.6k
    return GrCustomXfermode::Get(mode);
112
239k
}
113
114
//////////////////////////////////////////////////////////////////////////////
115
116
using ProgramImpl = GrXferProcessor::ProgramImpl;
117
118
// This is only called for cases where we are doing LCD coverage and not using in shader blending.
119
// For these cases we assume the the src alpha is 1, thus we can just use the max for the alpha
120
// coverage since src alpha will always be greater than or equal to dst alpha.
121
static void adjust_for_lcd_coverage(GrGLSLXPFragmentBuilder* fragBuilder,
122
                                    const char* srcCoverage,
123
0
                                    const GrXferProcessor& proc) {
124
0
    if (srcCoverage && proc.isLCD()) {
125
0
        fragBuilder->codeAppendf("%s.a = max(max(%s.r, %s.g), %s.b);",
126
0
                                 srcCoverage,
127
0
                                 srcCoverage,
128
0
                                 srcCoverage,
129
0
                                 srcCoverage);
130
0
    }
131
0
}
132
133
0
void ProgramImpl::emitCode(const EmitArgs& args) {
134
0
    if (!args.fXP.willReadDstColor()) {
135
0
        adjust_for_lcd_coverage(args.fXPFragBuilder, args.fInputCoverage, args.fXP);
136
0
        this->emitOutputsForBlendState(args);
137
0
    } else {
138
0
        GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
139
0
        GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
140
0
        const char* dstColor = fragBuilder->dstColor();
141
142
0
        bool needsLocalOutColor = false;
143
144
0
        if (args.fDstTextureSamplerHandle.isValid()) {
145
0
            if (args.fInputCoverage) {
146
                // We don't think any shaders actually output negative coverage, but just as a
147
                // safety check for floating point precision errors, we compare with <= here. We
148
                // just check the RGB values of the coverage, since the alpha may not have been set
149
                // when using LCD. If we are using single-channel coverage, alpha will be equal to
150
                // RGB anyway.
151
                //
152
                // The discard here also helps for batching text-draws together, which need to read
153
                // from a dst copy for blends. However, this only helps the case where the outer
154
                // bounding boxes of each letter overlap and not two actually parts of the text.
155
0
                fragBuilder->codeAppendf("if (all(lessThanEqual(%s.rgb, half3(0)))) {"
156
0
                                         "    discard;"
157
0
                                         "}",
158
0
                                         args.fInputCoverage);
159
0
            }
160
0
        } else {
161
0
            needsLocalOutColor = args.fShaderCaps->fRequiresLocalOutputColorForFBFetch;
162
0
        }
163
164
0
        const char* outColor = "_localColorOut";
165
0
        if (!needsLocalOutColor) {
166
0
            outColor = args.fOutputPrimary;
167
0
        } else {
168
0
            fragBuilder->codeAppendf("half4 %s;", outColor);
169
0
        }
170
171
0
        this->emitBlendCodeForDstRead(fragBuilder,
172
0
                                      uniformHandler,
173
0
                                      args.fInputColor,
174
0
                                      args.fInputCoverage,
175
0
                                      dstColor,
176
0
                                      outColor,
177
0
                                      args.fOutputSecondary,
178
0
                                      args.fXP);
179
0
        if (needsLocalOutColor) {
180
0
            fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, outColor);
181
0
        }
182
0
    }
183
184
    // Swizzle the fragment shader outputs if necessary.
185
0
    this->emitWriteSwizzle(args.fXPFragBuilder,
186
0
                           args.fWriteSwizzle,
187
0
                           args.fOutputPrimary,
188
0
                           args.fOutputSecondary);
189
0
}
190
191
void ProgramImpl::emitWriteSwizzle(GrGLSLXPFragmentBuilder* x,
192
                                   const skgpu::Swizzle& swizzle,
193
                                   const char* outColor,
194
0
                                   const char* outColorSecondary) const {
195
0
    if (skgpu::Swizzle::RGBA() != swizzle) {
196
0
        x->codeAppendf("%s = %s.%s;", outColor, outColor, swizzle.asString().c_str());
197
0
        if (outColorSecondary) {
198
0
            x->codeAppendf("%s = %s.%s;",
199
0
                           outColorSecondary,
200
0
                           outColorSecondary,
201
0
                           swizzle.asString().c_str());
202
0
        }
203
0
    }
204
0
}
205
206
0
void ProgramImpl::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) {
207
0
    this->onSetData(pdm, xp);
208
0
}
209
210
void ProgramImpl::DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder,
211
                                            const char* srcCoverage,
212
                                            const char* dstColor,
213
                                            const char* outColor,
214
                                            const char* outColorSecondary,
215
0
                                            const GrXferProcessor& proc) {
216
0
    if (srcCoverage) {
217
0
        if (proc.isLCD()) {
218
0
            fragBuilder->codeAppendf("half3 lerpRGB = mix(%s.aaa, %s.aaa, %s.rgb);",
219
0
                                     dstColor,
220
0
                                     outColor,
221
0
                                     srcCoverage);
222
0
        }
223
0
        fragBuilder->codeAppendf("%s = %s * %s + (half4(1.0) - %s) * %s;",
224
0
                                 outColor,
225
0
                                 srcCoverage,
226
0
                                 outColor,
227
0
                                 srcCoverage,
228
0
                                 dstColor);
229
0
        if (proc.isLCD()) {
230
0
            fragBuilder->codeAppendf("%s.a = max(max(lerpRGB.r, lerpRGB.b), lerpRGB.g);", outColor);
231
0
        }
232
0
    }
233
0
}