xref: /aosp_15_r20/external/skia/src/gpu/ganesh/effects/GrPorterDuffXferProcessor.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2014 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/effects/GrPorterDuffXferProcessor.h"
9 
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkColor.h"
12 #include "include/private/SkColorData.h"
13 #include "include/private/base/SkAssert.h"
14 #include "include/private/base/SkFloatingPoint.h"
15 #include "include/private/gpu/ganesh/GrTypesPriv.h"
16 #include "src/base/SkRandom.h"
17 #include "src/core/SkSLTypeShared.h"
18 #include "src/gpu/Blend.h"
19 #include "src/gpu/BlendFormula.h"
20 #include "src/gpu/KeyBuilder.h"
21 #include "src/gpu/ganesh/GrCaps.h"
22 #include "src/gpu/ganesh/GrProcessorAnalysis.h"
23 #include "src/gpu/ganesh/GrShaderCaps.h"
24 #include "src/gpu/ganesh/GrXferProcessor.h"
25 #include "src/gpu/ganesh/glsl/GrGLSLBlend.h"
26 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
27 #include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
28 #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
29 
30 #include <cstring>
31 #include <memory>
32 #include <string>
33 
34 using skgpu::BlendFormula;
35 
36 class PorterDuffXferProcessor : public GrXferProcessor {
37 public:
PorterDuffXferProcessor(BlendFormula blendFormula,GrProcessorAnalysisCoverage coverage)38     PorterDuffXferProcessor(BlendFormula blendFormula, GrProcessorAnalysisCoverage coverage)
39             : INHERITED(kPorterDuffXferProcessor_ClassID, /*willReadDstColor=*/false, coverage)
40             , fBlendFormula(blendFormula) {
41     }
42 
name() const43     const char* name() const override { return "Porter Duff"; }
44 
45     std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
46 
getBlendFormula() const47     BlendFormula getBlendFormula() const { return fBlendFormula; }
48 
49 private:
50     void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override;
51 
onHasSecondaryOutput() const52     bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
53 
onGetBlendInfo(skgpu::BlendInfo * blendInfo) const54     void onGetBlendInfo(skgpu::BlendInfo* blendInfo) const override {
55         blendInfo->fEquation = fBlendFormula.equation();
56         blendInfo->fSrcBlend = fBlendFormula.srcCoeff();
57         blendInfo->fDstBlend = fBlendFormula.dstCoeff();
58         blendInfo->fWritesColor = fBlendFormula.modifiesDst();
59     }
60 
onIsEqual(const GrXferProcessor & xpBase) const61     bool onIsEqual(const GrXferProcessor& xpBase) const override {
62         const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
63         return fBlendFormula == xp.fBlendFormula;
64     }
65 
66     const BlendFormula fBlendFormula;
67 
68     using INHERITED = GrXferProcessor;
69 };
70 
71 ///////////////////////////////////////////////////////////////////////////////
72 
append_color_output(const PorterDuffXferProcessor & xp,GrGLSLXPFragmentBuilder * fragBuilder,BlendFormula::OutputType outputType,const char * output,const char * inColor,const char * inCoverage)73 static void append_color_output(const PorterDuffXferProcessor& xp,
74                                 GrGLSLXPFragmentBuilder* fragBuilder,
75                                 BlendFormula::OutputType outputType, const char* output,
76                                 const char* inColor, const char* inCoverage) {
77     SkASSERT(inCoverage);
78     SkASSERT(inColor);
79     switch (outputType) {
80         case BlendFormula::kNone_OutputType:
81             fragBuilder->codeAppendf("%s = half4(0.0);", output);
82             break;
83         case BlendFormula::kCoverage_OutputType:
84             fragBuilder->codeAppendf("%s = %s;", output, inCoverage);
85             break;
86         case BlendFormula::kModulate_OutputType:
87             fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
88             break;
89         case BlendFormula::kSAModulate_OutputType:
90             fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
91             break;
92         case BlendFormula::kISAModulate_OutputType:
93             fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
94             break;
95         case BlendFormula::kISCModulate_OutputType:
96             fragBuilder->codeAppendf("%s = (half4(1.0) - %s) * %s;", output, inColor, inCoverage);
97             break;
98         default:
99             SK_ABORT("Unsupported output type.");
100             break;
101     }
102 }
103 
onAddToKey(const GrShaderCaps &,skgpu::KeyBuilder * b) const104 void PorterDuffXferProcessor::onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder* b) const {
105     b->add32(fBlendFormula.primaryOutput() | (fBlendFormula.secondaryOutput() << 3));
106     static_assert(BlendFormula::kLast_OutputType < 8);
107 }
108 
makeProgramImpl() const109 std::unique_ptr<GrXferProcessor::ProgramImpl> PorterDuffXferProcessor::makeProgramImpl() const {
110     class Impl : public ProgramImpl {
111     private:
112         void emitOutputsForBlendState(const EmitArgs& args) override {
113             const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
114             GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
115 
116             const BlendFormula& blendFormula = xp.fBlendFormula;
117             if (blendFormula.hasSecondaryOutput()) {
118                 append_color_output(xp,
119                                     fragBuilder,
120                                     blendFormula.secondaryOutput(),
121                                     args.fOutputSecondary,
122                                     args.fInputColor,
123                                     args.fInputCoverage);
124             }
125             append_color_output(xp,
126                                 fragBuilder,
127                                 blendFormula.primaryOutput(),
128                                 args.fOutputPrimary,
129                                 args.fInputColor,
130                                 args.fInputCoverage);
131         }
132     };
133 
134     return std::make_unique<Impl>();
135 }
136 
137 ///////////////////////////////////////////////////////////////////////////////
138 
139 class ShaderPDXferProcessor : public GrXferProcessor {
140 public:
ShaderPDXferProcessor(SkBlendMode xfermode,GrProcessorAnalysisCoverage coverage)141     ShaderPDXferProcessor(SkBlendMode xfermode, GrProcessorAnalysisCoverage coverage)
142             : INHERITED(kShaderPDXferProcessor_ClassID, /*willReadDstColor=*/true, coverage)
143             , fXfermode(xfermode) {
144     }
145 
name() const146     const char* name() const override { return "Porter Duff Shader"; }
147 
148     std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
149 
150 private:
151     void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override;
152 
onIsEqual(const GrXferProcessor & xpBase) const153     bool onIsEqual(const GrXferProcessor& xpBase) const override {
154         const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
155         return fXfermode == xp.fXfermode;
156     }
157 
158     const SkBlendMode fXfermode;
159 
160     using INHERITED = GrXferProcessor;
161 };
162 
163 ///////////////////////////////////////////////////////////////////////////////
164 
165 
onAddToKey(const GrShaderCaps &,skgpu::KeyBuilder * b) const166 void ShaderPDXferProcessor::onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder* b) const {
167     b->add32(GrGLSLBlend::BlendKey(fXfermode));
168 }
169 
makeProgramImpl() const170 std::unique_ptr<GrXferProcessor::ProgramImpl> ShaderPDXferProcessor::makeProgramImpl() const {
171     class Impl : public ProgramImpl {
172     private:
173         void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
174                                      GrGLSLUniformHandler* uniformHandler,
175                                      const char* srcColor,
176                                      const char* srcCoverage,
177                                      const char* dstColor,
178                                      const char* outColor,
179                                      const char* outColorSecondary,
180                                      const GrXferProcessor& proc) override {
181             const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
182 
183             std::string blendExpr = GrGLSLBlend::BlendExpression(
184                     &xp, uniformHandler, &fBlendUniform, srcColor, dstColor, xp.fXfermode);
185             fragBuilder->codeAppendf("%s = %s;", outColor, blendExpr.c_str());
186 
187             // Apply coverage.
188             DefaultCoverageModulation(fragBuilder,
189                                       srcCoverage,
190                                       dstColor,
191                                       outColor,
192                                       outColorSecondary,
193                                       xp);
194         }
195 
196         void onSetData(const GrGLSLProgramDataManager& pdman,
197                        const GrXferProcessor& proc) override {
198             if (fBlendUniform.isValid()) {
199                 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
200                 GrGLSLBlend::SetBlendModeUniformData(pdman, fBlendUniform, xp.fXfermode);
201             }
202         }
203 
204         GrGLSLUniformHandler::UniformHandle fBlendUniform;
205     };
206 
207     return std::make_unique<Impl>();
208 }
209 
210 ///////////////////////////////////////////////////////////////////////////////
211 
212 class PDLCDXferProcessor : public GrXferProcessor {
213 public:
214     static sk_sp<const GrXferProcessor> Make(SkBlendMode mode,
215                                              const GrProcessorAnalysisColor& inputColor);
216 
name() const217     const char* name() const override { return "Porter Duff LCD"; }
218 
219     std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
220 
221 private:
222     PDLCDXferProcessor(const SkPMColor4f& blendConstant, float alpha);
223 
onAddToKey(const GrShaderCaps &,skgpu::KeyBuilder *) const224     void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override {}
225 
onGetBlendInfo(skgpu::BlendInfo * blendInfo) const226     void onGetBlendInfo(skgpu::BlendInfo* blendInfo) const override {
227         blendInfo->fSrcBlend = skgpu::BlendCoeff::kConstC;
228         blendInfo->fDstBlend = skgpu::BlendCoeff::kISC;
229         blendInfo->fBlendConstant = fBlendConstant;
230     }
231 
onIsEqual(const GrXferProcessor & xpBase) const232     bool onIsEqual(const GrXferProcessor& xpBase) const override {
233         const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
234         if (fBlendConstant != xp.fBlendConstant || fAlpha != xp.fAlpha) {
235             return false;
236         }
237         return true;
238     }
239 
240     SkPMColor4f fBlendConstant;
241     float fAlpha;
242 
243     using INHERITED = GrXferProcessor;
244 };
245 
PDLCDXferProcessor(const SkPMColor4f & blendConstant,float alpha)246 PDLCDXferProcessor::PDLCDXferProcessor(const SkPMColor4f& blendConstant, float alpha)
247     : INHERITED(kPDLCDXferProcessor_ClassID, /*willReadDstColor=*/false,
248                 GrProcessorAnalysisCoverage::kLCD)
249     , fBlendConstant(blendConstant)
250     , fAlpha(alpha) {
251 }
252 
Make(SkBlendMode mode,const GrProcessorAnalysisColor & color)253 sk_sp<const GrXferProcessor> PDLCDXferProcessor::Make(SkBlendMode mode,
254                                                       const GrProcessorAnalysisColor& color) {
255     if (SkBlendMode::kSrcOver != mode) {
256         return nullptr;
257     }
258     SkPMColor4f blendConstantPM;
259     if (!color.isConstant(&blendConstantPM)) {
260         return nullptr;
261     }
262     SkColor4f blendConstantUPM = blendConstantPM.unpremul();
263     float alpha = blendConstantUPM.fA;
264     blendConstantPM = { blendConstantUPM.fR, blendConstantUPM.fG, blendConstantUPM.fB, 1 };
265     return sk_sp<GrXferProcessor>(new PDLCDXferProcessor(blendConstantPM, alpha));
266 }
267 
makeProgramImpl() const268 std::unique_ptr<GrXferProcessor::ProgramImpl> PDLCDXferProcessor::makeProgramImpl() const {
269     class Impl : public ProgramImpl {
270     private:
271         void emitOutputsForBlendState(const EmitArgs& args) override {
272             const char* alpha;
273             fAlphaUniform = args.fUniformHandler->addUniform(nullptr,
274                                                              kFragment_GrShaderFlag,
275                                                              SkSLType::kHalf,
276                                                              "alpha",
277                                                              &alpha);
278             GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
279             // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
280             // value of the src color. We know that there are no color stages (or we wouldn't have
281             // created this xp) and the r,g, and b channels of the op's input color are baked into
282             // the blend constant.
283             SkASSERT(args.fInputCoverage);
284             fragBuilder->codeAppendf("%s = %s * %s;",
285                                      args.fOutputPrimary,
286                                      alpha, args.fInputCoverage);
287         }
288 
289         void onSetData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) override {
290             float alpha = xp.cast<PDLCDXferProcessor>().fAlpha;
291             if (fLastAlpha != alpha) {
292                 pdm.set1f(fAlphaUniform, alpha);
293                 fLastAlpha = alpha;
294             }
295         }
296 
297         GrGLSLUniformHandler::UniformHandle fAlphaUniform;
298         float fLastAlpha = SK_FloatNaN;
299     };
300 
301     return std::make_unique<Impl>();
302 }
303 
304 ///////////////////////////////////////////////////////////////////////////////
305 
GrPorterDuffXPFactory(SkBlendMode xfermode)306 constexpr GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkBlendMode xfermode)
307         : fBlendMode(xfermode) {}
308 
Get(SkBlendMode blendMode)309 const GrXPFactory* GrPorterDuffXPFactory::Get(SkBlendMode blendMode) {
310     SkASSERT((unsigned)blendMode <= (unsigned)SkBlendMode::kLastCoeffMode);
311 
312     static constexpr const GrPorterDuffXPFactory gClearPDXPF(SkBlendMode::kClear);
313     static constexpr const GrPorterDuffXPFactory gSrcPDXPF(SkBlendMode::kSrc);
314     static constexpr const GrPorterDuffXPFactory gDstPDXPF(SkBlendMode::kDst);
315     static constexpr const GrPorterDuffXPFactory gSrcOverPDXPF(SkBlendMode::kSrcOver);
316     static constexpr const GrPorterDuffXPFactory gDstOverPDXPF(SkBlendMode::kDstOver);
317     static constexpr const GrPorterDuffXPFactory gSrcInPDXPF(SkBlendMode::kSrcIn);
318     static constexpr const GrPorterDuffXPFactory gDstInPDXPF(SkBlendMode::kDstIn);
319     static constexpr const GrPorterDuffXPFactory gSrcOutPDXPF(SkBlendMode::kSrcOut);
320     static constexpr const GrPorterDuffXPFactory gDstOutPDXPF(SkBlendMode::kDstOut);
321     static constexpr const GrPorterDuffXPFactory gSrcATopPDXPF(SkBlendMode::kSrcATop);
322     static constexpr const GrPorterDuffXPFactory gDstATopPDXPF(SkBlendMode::kDstATop);
323     static constexpr const GrPorterDuffXPFactory gXorPDXPF(SkBlendMode::kXor);
324     static constexpr const GrPorterDuffXPFactory gPlusPDXPF(SkBlendMode::kPlus);
325     static constexpr const GrPorterDuffXPFactory gModulatePDXPF(SkBlendMode::kModulate);
326     static constexpr const GrPorterDuffXPFactory gScreenPDXPF(SkBlendMode::kScreen);
327 
328     switch (blendMode) {
329         case SkBlendMode::kClear:
330             return &gClearPDXPF;
331         case SkBlendMode::kSrc:
332             return &gSrcPDXPF;
333         case SkBlendMode::kDst:
334             return &gDstPDXPF;
335         case SkBlendMode::kSrcOver:
336             return &gSrcOverPDXPF;
337         case SkBlendMode::kDstOver:
338             return &gDstOverPDXPF;
339         case SkBlendMode::kSrcIn:
340             return &gSrcInPDXPF;
341         case SkBlendMode::kDstIn:
342             return &gDstInPDXPF;
343         case SkBlendMode::kSrcOut:
344             return &gSrcOutPDXPF;
345         case SkBlendMode::kDstOut:
346             return &gDstOutPDXPF;
347         case SkBlendMode::kSrcATop:
348             return &gSrcATopPDXPF;
349         case SkBlendMode::kDstATop:
350             return &gDstATopPDXPF;
351         case SkBlendMode::kXor:
352             return &gXorPDXPF;
353         case SkBlendMode::kPlus:
354             return &gPlusPDXPF;
355         case SkBlendMode::kModulate:
356             return &gModulatePDXPF;
357         case SkBlendMode::kScreen:
358             return &gScreenPDXPF;
359         default:
360             SK_ABORT("Unexpected blend mode.");
361     }
362 }
363 
makeXferProcessor(const GrProcessorAnalysisColor & color,GrProcessorAnalysisCoverage coverage,const GrCaps & caps,GrClampType clampType) const364 sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::makeXferProcessor(
365         const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
366         const GrCaps& caps, GrClampType clampType) const {
367     bool isLCD = coverage == GrProcessorAnalysisCoverage::kLCD;
368     // See comment in MakeSrcOverXferProcessor about color.isOpaque here
369     if (isLCD &&
370         SkBlendMode::kSrcOver == fBlendMode && color.isConstant() && /*color.isOpaque() &&*/
371         !caps.shaderCaps()->fDualSourceBlendingSupport &&
372         !caps.shaderCaps()->fDstReadInShaderSupport) {
373         // If we don't have dual source blending or in shader dst reads, we fall back to this
374         // trick for rendering SrcOver LCD text instead of doing a dst copy.
375         return PDLCDXferProcessor::Make(fBlendMode, color);
376     }
377     BlendFormula blendFormula = [&](){
378         if (isLCD) {
379             return skgpu::GetLCDBlendFormula(fBlendMode);
380         }
381         if (fBlendMode == SkBlendMode::kSrcOver && color.isOpaque() &&
382             coverage == GrProcessorAnalysisCoverage::kNone &&
383             caps.shouldCollapseSrcOverToSrcWhenAble())
384         {
385             return skgpu::GetBlendFormula(true, false, SkBlendMode::kSrc);
386         }
387         return skgpu::GetBlendFormula(
388                 color.isOpaque(), GrProcessorAnalysisCoverage::kNone != coverage, fBlendMode);
389     }();
390 
391     // Skia always saturates after the kPlus blend mode, so it requires shader-based blending when
392     // pixels aren't guaranteed to automatically be normalized (i.e. any floating point config).
393     if ((blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->fDualSourceBlendingSupport) ||
394         (isLCD && (SkBlendMode::kSrcOver != fBlendMode /*|| !color.isOpaque()*/)) ||
395         (GrClampType::kAuto != clampType && SkBlendMode::kPlus == fBlendMode)) {
396         return sk_sp<const GrXferProcessor>(new ShaderPDXferProcessor(fBlendMode, coverage));
397     }
398     return sk_sp<const GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage));
399 }
400 
analysis_properties(const GrProcessorAnalysisColor & color,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType,SkBlendMode mode)401 static inline GrXPFactory::AnalysisProperties analysis_properties(
402         const GrProcessorAnalysisColor& color, const GrProcessorAnalysisCoverage& coverage,
403         const GrCaps& caps, GrClampType clampType, SkBlendMode mode) {
404     using AnalysisProperties = GrXPFactory::AnalysisProperties;
405     AnalysisProperties props = AnalysisProperties::kNone;
406     bool hasCoverage = GrProcessorAnalysisCoverage::kNone != coverage;
407     bool isLCD = GrProcessorAnalysisCoverage::kLCD == coverage;
408     BlendFormula formula = [&](){
409         if (isLCD) {
410             return skgpu::GetLCDBlendFormula(mode);
411         }
412         return skgpu::GetBlendFormula(color.isOpaque(), hasCoverage, mode);
413     }();
414 
415     if (formula.canTweakAlphaForCoverage() && !isLCD) {
416         props |= AnalysisProperties::kCompatibleWithCoverageAsAlpha;
417     }
418 
419     if (isLCD) {
420         // See comment in MakeSrcOverXferProcessor about color.isOpaque here
421         if (SkBlendMode::kSrcOver == mode && color.isConstant() && /*color.isOpaque() &&*/
422             !caps.shaderCaps()->fDualSourceBlendingSupport &&
423             !caps.shaderCaps()->fDstReadInShaderSupport) {
424             props |= AnalysisProperties::kIgnoresInputColor;
425         } else {
426             // For LCD blending, if the color is not opaque we must read the dst in shader even if
427             // we have dual source blending. The opaqueness check must be done after blending so for
428             // simplicity we only allow src-over to not take the dst read path (though src, src-in,
429             // and DstATop would also work). We also fall into the dst read case for src-over if we
430             // do not have dual source blending.
431             if (SkBlendMode::kSrcOver != mode ||
432                 /*!color.isOpaque() ||*/ // See comment in MakeSrcOverXferProcessor about isOpaque.
433                 (formula.hasSecondaryOutput() && !caps.shaderCaps()->fDualSourceBlendingSupport)) {
434                 props |= AnalysisProperties::kReadsDstInShader;
435             }
436         }
437     } else {
438         // With dual-source blending we never need the destination color in the shader.
439         if (!caps.shaderCaps()->fDualSourceBlendingSupport) {
440             if (formula.hasSecondaryOutput()) {
441                 props |= AnalysisProperties::kReadsDstInShader;
442             }
443         }
444     }
445 
446     if (GrClampType::kAuto != clampType && SkBlendMode::kPlus == mode) {
447         props |= AnalysisProperties::kReadsDstInShader;
448     }
449 
450     if (!formula.modifiesDst() || !formula.usesInputColor()) {
451         props |= AnalysisProperties::kIgnoresInputColor;
452     }
453     if (formula.unaffectedByDst() || (formula.unaffectedByDstIfOpaque() && color.isOpaque() &&
454                                       !hasCoverage)) {
455         props |= AnalysisProperties::kUnaffectedByDstValue;
456     }
457     return props;
458 }
459 
analysisProperties(const GrProcessorAnalysisColor & color,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType) const460 GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::analysisProperties(
461         const GrProcessorAnalysisColor& color,
462         const GrProcessorAnalysisCoverage& coverage,
463         const GrCaps& caps,
464         GrClampType clampType) const {
465     return analysis_properties(color, coverage, caps, clampType, fBlendMode);
466 }
467 
GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory) const468 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory)
469 
470 #if defined(GPU_TEST_UTILS)
471 const GrXPFactory* GrPorterDuffXPFactory::TestGet(GrProcessorTestData* d) {
472     SkBlendMode mode = SkBlendMode(d->fRandom->nextULessThan((int)SkBlendMode::kLastCoeffMode));
473     return GrPorterDuffXPFactory::Get(mode);
474 }
475 #endif
476 
TestGetXPOutputTypes(const GrXferProcessor * xp,int * outPrimary,int * outSecondary)477 void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
478                                                  int* outPrimary,
479                                                  int* outSecondary) {
480     if (!!strcmp(xp->name(), "Porter Duff")) {
481         *outPrimary = *outSecondary = -1;
482         return;
483     }
484     BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
485     *outPrimary = blendFormula.primaryOutput();
486     *outSecondary = blendFormula.secondaryOutput();
487 }
488 
489 ////////////////////////////////////////////////////////////////////////////////////////////////
490 // SrcOver Global functions
491 ////////////////////////////////////////////////////////////////////////////////////////////////
SimpleSrcOverXP()492 const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
493     static BlendFormula kSrcOverBlendFormula = skgpu::GetBlendFormula(
494             /*isOpaque=*/false, /*hasCoverage=*/false, SkBlendMode::kSrcOver);
495     static PorterDuffXferProcessor gSrcOverXP(kSrcOverBlendFormula,
496                                               GrProcessorAnalysisCoverage::kSingleChannel);
497     return gSrcOverXP;
498 }
499 
MakeSrcOverXferProcessor(const GrProcessorAnalysisColor & color,GrProcessorAnalysisCoverage coverage,const GrCaps & caps)500 sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeSrcOverXferProcessor(
501         const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
502         const GrCaps& caps) {
503     // We want to not make an xfer processor if possible. Thus for the simple case where we are not
504     // doing lcd blending we will just use our global SimpleSrcOverXP. This slightly differs from
505     // the general case where we convert a src-over blend that has solid coverage and an opaque
506     // color to src-mode, which allows disabling of blending.
507     if (coverage != GrProcessorAnalysisCoverage::kLCD) {
508         if (color.isOpaque() && coverage == GrProcessorAnalysisCoverage::kNone &&
509             caps.shouldCollapseSrcOverToSrcWhenAble()) {
510             BlendFormula blendFormula = skgpu::GetBlendFormula(true, false, SkBlendMode::kSrc);
511             return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage));
512         }
513         // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP".
514         // We don't simply return the address of that XP here because our caller would have to unref
515         // it and since it is a global object and GrProgramElement's ref-cnting system is not thread
516         // safe.
517         return nullptr;
518     }
519 
520     // Currently up the stack Skia is requiring that the dst is opaque or that the client has said
521     // the opaqueness doesn't matter. Thus for src-over we don't need to worry about the src color
522     // being opaque or not. This allows us to use faster code paths as well as avoid various bugs
523     // that occur with dst reads in the shader blending. For now we disable the check for
524     // opaqueness, but in the future we should pass down the knowledge about dst opaqueness and make
525     // the correct decision here.
526     //
527     // This also fixes a chrome bug on macs where we are getting random fuzziness when doing
528     // blending in the shader for non opaque sources.
529     if (color.isConstant() && /*color.isOpaque() &&*/
530         !caps.shaderCaps()->fDualSourceBlendingSupport &&
531         !caps.shaderCaps()->fDstReadInShaderSupport) {
532         // If we don't have dual source blending or in shader dst reads, we fall
533         // back to this trick for rendering SrcOver LCD text instead of doing a
534         // dst copy.
535         return PDLCDXferProcessor::Make(SkBlendMode::kSrcOver, color);
536     }
537 
538     BlendFormula blendFormula = skgpu::GetLCDBlendFormula(SkBlendMode::kSrcOver);
539     // See comment above regarding why the opaque check is commented out here.
540     if (/*!color.isOpaque() ||*/
541         (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->fDualSourceBlendingSupport)) {
542         return sk_sp<GrXferProcessor>(new ShaderPDXferProcessor(SkBlendMode::kSrcOver, coverage));
543     }
544     return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage));
545 }
546 
MakeNoCoverageXP(SkBlendMode blendmode)547 sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeNoCoverageXP(SkBlendMode blendmode) {
548     BlendFormula formula = skgpu::GetBlendFormula(false, false, blendmode);
549     return sk_make_sp<PorterDuffXferProcessor>(formula, GrProcessorAnalysisCoverage::kNone);
550 }
551 
SrcOverAnalysisProperties(const GrProcessorAnalysisColor & color,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType)552 GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::SrcOverAnalysisProperties(
553         const GrProcessorAnalysisColor& color,
554         const GrProcessorAnalysisCoverage& coverage,
555         const GrCaps& caps,
556         GrClampType clampType) {
557     return analysis_properties(color, coverage, caps, clampType, SkBlendMode::kSrcOver);
558 }
559