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