xref: /aosp_15_r20/external/skia/src/gpu/ganesh/effects/GrCustomXfermode.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2015 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrCustomXfermode.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/Blend.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/KeyBuilder.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorAnalysis.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorUnitTest.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderCaps.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrXferProcessor.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLBlend.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
26*c8dee2aaSAndroid Build Coastguard Worker #include <string>
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker class GrGLSLProgramDataManager;
29*c8dee2aaSAndroid Build Coastguard Worker enum class GrClampType;
30*c8dee2aaSAndroid Build Coastguard Worker 
IsSupportedMode(SkBlendMode mode)31*c8dee2aaSAndroid Build Coastguard Worker bool GrCustomXfermode::IsSupportedMode(SkBlendMode mode) {
32*c8dee2aaSAndroid Build Coastguard Worker     return (int)mode  > (int)SkBlendMode::kLastCoeffMode &&
33*c8dee2aaSAndroid Build Coastguard Worker            (int)mode <= (int)SkBlendMode::kLastMode;
34*c8dee2aaSAndroid Build Coastguard Worker }
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
37*c8dee2aaSAndroid Build Coastguard Worker // Static helpers
38*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
39*c8dee2aaSAndroid Build Coastguard Worker 
hw_blend_equation(SkBlendMode mode)40*c8dee2aaSAndroid Build Coastguard Worker static constexpr skgpu::BlendEquation hw_blend_equation(SkBlendMode mode) {
41*c8dee2aaSAndroid Build Coastguard Worker     constexpr int kEqOffset = ((int)skgpu::BlendEquation::kOverlay - (int)SkBlendMode::kOverlay);
42*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kOverlay == (int)SkBlendMode::kOverlay + kEqOffset);
43*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kDarken == (int)SkBlendMode::kDarken + kEqOffset);
44*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kLighten == (int)SkBlendMode::kLighten + kEqOffset);
45*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kColorDodge == (int)SkBlendMode::kColorDodge + kEqOffset);
46*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kColorBurn == (int)SkBlendMode::kColorBurn + kEqOffset);
47*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kHardLight == (int)SkBlendMode::kHardLight + kEqOffset);
48*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kSoftLight == (int)SkBlendMode::kSoftLight + kEqOffset);
49*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kDifference == (int)SkBlendMode::kDifference + kEqOffset);
50*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kExclusion == (int)SkBlendMode::kExclusion + kEqOffset);
51*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kMultiply == (int)SkBlendMode::kMultiply + kEqOffset);
52*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kHSLHue == (int)SkBlendMode::kHue + kEqOffset);
53*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kHSLSaturation == (int)SkBlendMode::kSaturation + kEqOffset);
54*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kHSLColor == (int)SkBlendMode::kColor + kEqOffset);
55*c8dee2aaSAndroid Build Coastguard Worker     static_assert((int)skgpu::BlendEquation::kHSLLuminosity == (int)SkBlendMode::kLuminosity + kEqOffset);
56*c8dee2aaSAndroid Build Coastguard Worker 
57*c8dee2aaSAndroid Build Coastguard Worker     // There's an illegal BlendEquation that corresponds to no SkBlendMode, hence the extra +1.
58*c8dee2aaSAndroid Build Coastguard Worker     static_assert(skgpu::kBlendEquationCnt == (int)SkBlendMode::kLastMode + 1 + 1 + kEqOffset);
59*c8dee2aaSAndroid Build Coastguard Worker 
60*c8dee2aaSAndroid Build Coastguard Worker     return static_cast<skgpu::BlendEquation>((int)mode + kEqOffset);
61*c8dee2aaSAndroid Build Coastguard Worker #undef EQ_OFFSET
62*c8dee2aaSAndroid Build Coastguard Worker }
63*c8dee2aaSAndroid Build Coastguard Worker 
can_use_hw_blend_equation(skgpu::BlendEquation equation,GrProcessorAnalysisCoverage coverage,const GrCaps & caps)64*c8dee2aaSAndroid Build Coastguard Worker static bool can_use_hw_blend_equation(skgpu::BlendEquation equation,
65*c8dee2aaSAndroid Build Coastguard Worker                                       GrProcessorAnalysisCoverage coverage, const GrCaps& caps) {
66*c8dee2aaSAndroid Build Coastguard Worker     if (!caps.advancedBlendEquationSupport()) {
67*c8dee2aaSAndroid Build Coastguard Worker         return false;
68*c8dee2aaSAndroid Build Coastguard Worker     }
69*c8dee2aaSAndroid Build Coastguard Worker     if (GrProcessorAnalysisCoverage::kLCD == coverage) {
70*c8dee2aaSAndroid Build Coastguard Worker         return false; // LCD coverage must be applied after the blend equation.
71*c8dee2aaSAndroid Build Coastguard Worker     }
72*c8dee2aaSAndroid Build Coastguard Worker     if (caps.isAdvancedBlendEquationDisabled(equation)) {
73*c8dee2aaSAndroid Build Coastguard Worker         return false;
74*c8dee2aaSAndroid Build Coastguard Worker     }
75*c8dee2aaSAndroid Build Coastguard Worker     return true;
76*c8dee2aaSAndroid Build Coastguard Worker }
77*c8dee2aaSAndroid Build Coastguard Worker 
78*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
79*c8dee2aaSAndroid Build Coastguard Worker // Xfer Processor
80*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
81*c8dee2aaSAndroid Build Coastguard Worker 
82*c8dee2aaSAndroid Build Coastguard Worker class CustomXP : public GrXferProcessor {
83*c8dee2aaSAndroid Build Coastguard Worker public:
CustomXP(SkBlendMode mode,skgpu::BlendEquation hwBlendEquation)84*c8dee2aaSAndroid Build Coastguard Worker     CustomXP(SkBlendMode mode, skgpu::BlendEquation hwBlendEquation)
85*c8dee2aaSAndroid Build Coastguard Worker         : INHERITED(kCustomXP_ClassID)
86*c8dee2aaSAndroid Build Coastguard Worker         , fMode(mode)
87*c8dee2aaSAndroid Build Coastguard Worker         , fHWBlendEquation(hwBlendEquation) {}
88*c8dee2aaSAndroid Build Coastguard Worker 
CustomXP(SkBlendMode mode,GrProcessorAnalysisCoverage coverage)89*c8dee2aaSAndroid Build Coastguard Worker     CustomXP(SkBlendMode mode, GrProcessorAnalysisCoverage coverage)
90*c8dee2aaSAndroid Build Coastguard Worker             : INHERITED(kCustomXP_ClassID, /*willReadDstColor=*/true, coverage)
91*c8dee2aaSAndroid Build Coastguard Worker             , fMode(mode)
92*c8dee2aaSAndroid Build Coastguard Worker             , fHWBlendEquation(skgpu::BlendEquation::kIllegal) {
93*c8dee2aaSAndroid Build Coastguard Worker     }
94*c8dee2aaSAndroid Build Coastguard Worker 
name() const95*c8dee2aaSAndroid Build Coastguard Worker     const char* name() const override { return "Custom Xfermode"; }
96*c8dee2aaSAndroid Build Coastguard Worker 
97*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker     GrXferBarrierType xferBarrierType(const GrCaps&) const override;
100*c8dee2aaSAndroid Build Coastguard Worker 
101*c8dee2aaSAndroid Build Coastguard Worker private:
hasHWBlendEquation() const102*c8dee2aaSAndroid Build Coastguard Worker     bool hasHWBlendEquation() const { return skgpu::BlendEquation::kIllegal != fHWBlendEquation; }
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker     void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override;
105*c8dee2aaSAndroid Build Coastguard Worker 
106*c8dee2aaSAndroid Build Coastguard Worker     void onGetBlendInfo(skgpu::BlendInfo*) const override;
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker     bool onIsEqual(const GrXferProcessor& xpBase) const override;
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker     const SkBlendMode          fMode;
111*c8dee2aaSAndroid Build Coastguard Worker     const skgpu::BlendEquation fHWBlendEquation;
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GrXferProcessor;
114*c8dee2aaSAndroid Build Coastguard Worker };
115*c8dee2aaSAndroid Build Coastguard Worker 
onAddToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b) const116*c8dee2aaSAndroid Build Coastguard Worker void CustomXP::onAddToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const {
117*c8dee2aaSAndroid Build Coastguard Worker     if (this->hasHWBlendEquation()) {
118*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(caps.fAdvBlendEqInteraction > 0);  // 0 will mean !xp.hasHWBlendEquation().
119*c8dee2aaSAndroid Build Coastguard Worker         b->addBool(true, "has hardware blend equation");
120*c8dee2aaSAndroid Build Coastguard Worker         b->add32(caps.fAdvBlendEqInteraction);
121*c8dee2aaSAndroid Build Coastguard Worker     } else {
122*c8dee2aaSAndroid Build Coastguard Worker         b->addBool(false, "has hardware blend equation");
123*c8dee2aaSAndroid Build Coastguard Worker         b->add32(GrGLSLBlend::BlendKey(fMode));
124*c8dee2aaSAndroid Build Coastguard Worker     }
125*c8dee2aaSAndroid Build Coastguard Worker }
126*c8dee2aaSAndroid Build Coastguard Worker 
makeProgramImpl() const127*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrXferProcessor::ProgramImpl> CustomXP::makeProgramImpl() const {
128*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(this->willReadDstColor() != this->hasHWBlendEquation());
129*c8dee2aaSAndroid Build Coastguard Worker 
130*c8dee2aaSAndroid Build Coastguard Worker     class Impl : public ProgramImpl {
131*c8dee2aaSAndroid Build Coastguard Worker     private:
132*c8dee2aaSAndroid Build Coastguard Worker         void emitOutputsForBlendState(const EmitArgs& args) override {
133*c8dee2aaSAndroid Build Coastguard Worker             const CustomXP& xp = args.fXP.cast<CustomXP>();
134*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(xp.hasHWBlendEquation());
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker             GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
137*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->enableAdvancedBlendEquationIfNeeded(xp.fHWBlendEquation);
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker             // Apply coverage by multiplying it into the src color before blending. This will "just
140*c8dee2aaSAndroid Build Coastguard Worker             // work" automatically. (See analysisProperties())
141*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf("%s = %s * %s;",
142*c8dee2aaSAndroid Build Coastguard Worker                                      args.fOutputPrimary,
143*c8dee2aaSAndroid Build Coastguard Worker                                      args.fInputCoverage,
144*c8dee2aaSAndroid Build Coastguard Worker                                      args.fInputColor);
145*c8dee2aaSAndroid Build Coastguard Worker         }
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker         void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
148*c8dee2aaSAndroid Build Coastguard Worker                                      GrGLSLUniformHandler* uniformHandler,
149*c8dee2aaSAndroid Build Coastguard Worker                                      const char* srcColor,
150*c8dee2aaSAndroid Build Coastguard Worker                                      const char* srcCoverage,
151*c8dee2aaSAndroid Build Coastguard Worker                                      const char* dstColor,
152*c8dee2aaSAndroid Build Coastguard Worker                                      const char* outColor,
153*c8dee2aaSAndroid Build Coastguard Worker                                      const char* outColorSecondary,
154*c8dee2aaSAndroid Build Coastguard Worker                                      const GrXferProcessor& proc) override {
155*c8dee2aaSAndroid Build Coastguard Worker             const CustomXP& xp = proc.cast<CustomXP>();
156*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!xp.hasHWBlendEquation());
157*c8dee2aaSAndroid Build Coastguard Worker 
158*c8dee2aaSAndroid Build Coastguard Worker             std::string blendExpr = GrGLSLBlend::BlendExpression(
159*c8dee2aaSAndroid Build Coastguard Worker                     &xp, uniformHandler, &fBlendUniform, srcColor, dstColor, xp.fMode);
160*c8dee2aaSAndroid Build Coastguard Worker             fragBuilder->codeAppendf("%s = %s;", outColor, blendExpr.c_str());
161*c8dee2aaSAndroid Build Coastguard Worker 
162*c8dee2aaSAndroid Build Coastguard Worker             // Apply coverage.
163*c8dee2aaSAndroid Build Coastguard Worker             DefaultCoverageModulation(fragBuilder,
164*c8dee2aaSAndroid Build Coastguard Worker                                       srcCoverage,
165*c8dee2aaSAndroid Build Coastguard Worker                                       dstColor,
166*c8dee2aaSAndroid Build Coastguard Worker                                       outColor,
167*c8dee2aaSAndroid Build Coastguard Worker                                       outColorSecondary,
168*c8dee2aaSAndroid Build Coastguard Worker                                       xp);
169*c8dee2aaSAndroid Build Coastguard Worker         }
170*c8dee2aaSAndroid Build Coastguard Worker 
171*c8dee2aaSAndroid Build Coastguard Worker         void onSetData(const GrGLSLProgramDataManager& pdman,
172*c8dee2aaSAndroid Build Coastguard Worker                        const GrXferProcessor& proc) override {
173*c8dee2aaSAndroid Build Coastguard Worker             if (fBlendUniform.isValid()) {
174*c8dee2aaSAndroid Build Coastguard Worker                 const CustomXP& xp = proc.cast<CustomXP>();
175*c8dee2aaSAndroid Build Coastguard Worker                 GrGLSLBlend::SetBlendModeUniformData(pdman, fBlendUniform, xp.fMode);
176*c8dee2aaSAndroid Build Coastguard Worker             }
177*c8dee2aaSAndroid Build Coastguard Worker         }
178*c8dee2aaSAndroid Build Coastguard Worker 
179*c8dee2aaSAndroid Build Coastguard Worker         GrGLSLUniformHandler::UniformHandle fBlendUniform;
180*c8dee2aaSAndroid Build Coastguard Worker     };
181*c8dee2aaSAndroid Build Coastguard Worker 
182*c8dee2aaSAndroid Build Coastguard Worker     return std::make_unique<Impl>();
183*c8dee2aaSAndroid Build Coastguard Worker }
184*c8dee2aaSAndroid Build Coastguard Worker 
onIsEqual(const GrXferProcessor & other) const185*c8dee2aaSAndroid Build Coastguard Worker bool CustomXP::onIsEqual(const GrXferProcessor& other) const {
186*c8dee2aaSAndroid Build Coastguard Worker     const CustomXP& s = other.cast<CustomXP>();
187*c8dee2aaSAndroid Build Coastguard Worker     return fMode == s.fMode && fHWBlendEquation == s.fHWBlendEquation;
188*c8dee2aaSAndroid Build Coastguard Worker }
189*c8dee2aaSAndroid Build Coastguard Worker 
xferBarrierType(const GrCaps & caps) const190*c8dee2aaSAndroid Build Coastguard Worker GrXferBarrierType CustomXP::xferBarrierType(const GrCaps& caps) const {
191*c8dee2aaSAndroid Build Coastguard Worker     if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) {
192*c8dee2aaSAndroid Build Coastguard Worker         return kBlend_GrXferBarrierType;
193*c8dee2aaSAndroid Build Coastguard Worker     }
194*c8dee2aaSAndroid Build Coastguard Worker     return kNone_GrXferBarrierType;
195*c8dee2aaSAndroid Build Coastguard Worker }
196*c8dee2aaSAndroid Build Coastguard Worker 
onGetBlendInfo(skgpu::BlendInfo * blendInfo) const197*c8dee2aaSAndroid Build Coastguard Worker void CustomXP::onGetBlendInfo(skgpu::BlendInfo* blendInfo) const {
198*c8dee2aaSAndroid Build Coastguard Worker     if (this->hasHWBlendEquation()) {
199*c8dee2aaSAndroid Build Coastguard Worker         blendInfo->fEquation = fHWBlendEquation;
200*c8dee2aaSAndroid Build Coastguard Worker     }
201*c8dee2aaSAndroid Build Coastguard Worker }
202*c8dee2aaSAndroid Build Coastguard Worker 
203*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
204*c8dee2aaSAndroid Build Coastguard Worker 
205*c8dee2aaSAndroid Build Coastguard Worker // See the comment above GrXPFactory's definition about this warning suppression.
206*c8dee2aaSAndroid Build Coastguard Worker #if defined(__GNUC__)
207*c8dee2aaSAndroid Build Coastguard Worker #pragma GCC diagnostic push
208*c8dee2aaSAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
209*c8dee2aaSAndroid Build Coastguard Worker #endif
210*c8dee2aaSAndroid Build Coastguard Worker #if defined(__clang__)
211*c8dee2aaSAndroid Build Coastguard Worker #pragma clang diagnostic push
212*c8dee2aaSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
213*c8dee2aaSAndroid Build Coastguard Worker #endif
214*c8dee2aaSAndroid Build Coastguard Worker class CustomXPFactory : public GrXPFactory {
215*c8dee2aaSAndroid Build Coastguard Worker public:
CustomXPFactory(SkBlendMode mode)216*c8dee2aaSAndroid Build Coastguard Worker     constexpr CustomXPFactory(SkBlendMode mode)
217*c8dee2aaSAndroid Build Coastguard Worker             : fMode(mode), fHWBlendEquation(hw_blend_equation(mode)) {}
218*c8dee2aaSAndroid Build Coastguard Worker 
219*c8dee2aaSAndroid Build Coastguard Worker private:
220*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<const GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
221*c8dee2aaSAndroid Build Coastguard Worker                                                    GrProcessorAnalysisCoverage,
222*c8dee2aaSAndroid Build Coastguard Worker                                                    const GrCaps&,
223*c8dee2aaSAndroid Build Coastguard Worker                                                    GrClampType) const override;
224*c8dee2aaSAndroid Build Coastguard Worker 
225*c8dee2aaSAndroid Build Coastguard Worker     AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&,
226*c8dee2aaSAndroid Build Coastguard Worker                                           const GrProcessorAnalysisCoverage&,
227*c8dee2aaSAndroid Build Coastguard Worker                                           const GrCaps&,
228*c8dee2aaSAndroid Build Coastguard Worker                                           GrClampType) const override;
229*c8dee2aaSAndroid Build Coastguard Worker 
230*c8dee2aaSAndroid Build Coastguard Worker     GR_DECLARE_XP_FACTORY_TEST
231*c8dee2aaSAndroid Build Coastguard Worker 
232*c8dee2aaSAndroid Build Coastguard Worker     SkBlendMode fMode;
233*c8dee2aaSAndroid Build Coastguard Worker     skgpu::BlendEquation fHWBlendEquation;
234*c8dee2aaSAndroid Build Coastguard Worker 
235*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GrXPFactory;
236*c8dee2aaSAndroid Build Coastguard Worker };
237*c8dee2aaSAndroid Build Coastguard Worker #if defined(__GNUC__)
238*c8dee2aaSAndroid Build Coastguard Worker #pragma GCC diagnostic pop
239*c8dee2aaSAndroid Build Coastguard Worker #endif
240*c8dee2aaSAndroid Build Coastguard Worker #if defined(__clang__)
241*c8dee2aaSAndroid Build Coastguard Worker #pragma clang diagnostic pop
242*c8dee2aaSAndroid Build Coastguard Worker #endif
243*c8dee2aaSAndroid Build Coastguard Worker 
makeXferProcessor(const GrProcessorAnalysisColor &,GrProcessorAnalysisCoverage coverage,const GrCaps & caps,GrClampType clampType) const244*c8dee2aaSAndroid Build Coastguard Worker sk_sp<const GrXferProcessor> CustomXPFactory::makeXferProcessor(
245*c8dee2aaSAndroid Build Coastguard Worker         const GrProcessorAnalysisColor&,
246*c8dee2aaSAndroid Build Coastguard Worker         GrProcessorAnalysisCoverage coverage,
247*c8dee2aaSAndroid Build Coastguard Worker         const GrCaps& caps,
248*c8dee2aaSAndroid Build Coastguard Worker         GrClampType clampType) const {
249*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
250*c8dee2aaSAndroid Build Coastguard Worker     if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) {
251*c8dee2aaSAndroid Build Coastguard Worker         return sk_sp<GrXferProcessor>(new CustomXP(fMode, fHWBlendEquation));
252*c8dee2aaSAndroid Build Coastguard Worker     }
253*c8dee2aaSAndroid Build Coastguard Worker     return sk_sp<GrXferProcessor>(new CustomXP(fMode, coverage));
254*c8dee2aaSAndroid Build Coastguard Worker }
255*c8dee2aaSAndroid Build Coastguard Worker 
analysisProperties(const GrProcessorAnalysisColor &,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType) const256*c8dee2aaSAndroid Build Coastguard Worker GrXPFactory::AnalysisProperties CustomXPFactory::analysisProperties(
257*c8dee2aaSAndroid Build Coastguard Worker         const GrProcessorAnalysisColor&, const GrProcessorAnalysisCoverage& coverage,
258*c8dee2aaSAndroid Build Coastguard Worker         const GrCaps& caps, GrClampType clampType) const {
259*c8dee2aaSAndroid Build Coastguard Worker     /*
260*c8dee2aaSAndroid Build Coastguard Worker       The general SVG blend equation is defined in the spec as follows:
261*c8dee2aaSAndroid Build Coastguard Worker 
262*c8dee2aaSAndroid Build Coastguard Worker         Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa)
263*c8dee2aaSAndroid Build Coastguard Worker         Da'  = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa)
264*c8dee2aaSAndroid Build Coastguard Worker 
265*c8dee2aaSAndroid Build Coastguard Worker       (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha,
266*c8dee2aaSAndroid Build Coastguard Worker        and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied
267*c8dee2aaSAndroid Build Coastguard Worker        RGB colors.)
268*c8dee2aaSAndroid Build Coastguard Worker 
269*c8dee2aaSAndroid Build Coastguard Worker       For every blend mode supported by this class, i.e. the "advanced" blend
270*c8dee2aaSAndroid Build Coastguard Worker       modes, X=Y=Z=1 and this equation reduces to the PDF blend equation.
271*c8dee2aaSAndroid Build Coastguard Worker 
272*c8dee2aaSAndroid Build Coastguard Worker       It can be shown that when X=Y=Z=1, these equations can modulate alpha for
273*c8dee2aaSAndroid Build Coastguard Worker       coverage.
274*c8dee2aaSAndroid Build Coastguard Worker 
275*c8dee2aaSAndroid Build Coastguard Worker 
276*c8dee2aaSAndroid Build Coastguard Worker       == Color ==
277*c8dee2aaSAndroid Build Coastguard Worker 
278*c8dee2aaSAndroid Build Coastguard Worker       We substitute Y=Z=1 and define a blend() function that calculates Dca' in
279*c8dee2aaSAndroid Build Coastguard Worker       terms of premultiplied alpha only:
280*c8dee2aaSAndroid Build Coastguard Worker 
281*c8dee2aaSAndroid Build Coastguard Worker         blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0,
282*c8dee2aaSAndroid Build Coastguard Worker                                    Sca : if Da == 0,
283*c8dee2aaSAndroid Build Coastguard Worker                                    B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if
284*c8dee2aaSAndroid Build Coastguard Worker       Sa,Da != 0}
285*c8dee2aaSAndroid Build Coastguard Worker 
286*c8dee2aaSAndroid Build Coastguard Worker       And for coverage modulation, we use a post blend src-over model:
287*c8dee2aaSAndroid Build Coastguard Worker 
288*c8dee2aaSAndroid Build Coastguard Worker         Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
289*c8dee2aaSAndroid Build Coastguard Worker 
290*c8dee2aaSAndroid Build Coastguard Worker       (Where f is the fractional coverage.)
291*c8dee2aaSAndroid Build Coastguard Worker 
292*c8dee2aaSAndroid Build Coastguard Worker       Next we show that canTweakAlphaForCoverage() is true by proving the
293*c8dee2aaSAndroid Build Coastguard Worker       following relationship:
294*c8dee2aaSAndroid Build Coastguard Worker 
295*c8dee2aaSAndroid Build Coastguard Worker         blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
296*c8dee2aaSAndroid Build Coastguard Worker 
297*c8dee2aaSAndroid Build Coastguard Worker       General case (f,Sa,Da != 0):
298*c8dee2aaSAndroid Build Coastguard Worker 
299*c8dee2aaSAndroid Build Coastguard Worker         f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
300*c8dee2aaSAndroid Build Coastguard Worker           = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca  [Sa,Da !=
301*c8dee2aaSAndroid Build Coastguard Worker       0, definition of blend()]
302*c8dee2aaSAndroid Build Coastguard Worker           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca
303*c8dee2aaSAndroid Build Coastguard Worker           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca
304*c8dee2aaSAndroid Build Coastguard Worker           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca
305*c8dee2aaSAndroid Build Coastguard Worker           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca
306*c8dee2aaSAndroid Build Coastguard Worker           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)
307*c8dee2aaSAndroid Build Coastguard Worker           = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)  [f!=0]
308*c8dee2aaSAndroid Build Coastguard Worker           = blend(f*Sca, Dca, f*Sa, Da)  [definition of blend()]
309*c8dee2aaSAndroid Build Coastguard Worker 
310*c8dee2aaSAndroid Build Coastguard Worker       Corner cases (Sa=0, Da=0, and f=0):
311*c8dee2aaSAndroid Build Coastguard Worker 
312*c8dee2aaSAndroid Build Coastguard Worker         Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
313*c8dee2aaSAndroid Build Coastguard Worker                 = f * Dca + (1-f) * Dca  [Sa=0, definition of blend()]
314*c8dee2aaSAndroid Build Coastguard Worker                 = Dca
315*c8dee2aaSAndroid Build Coastguard Worker                 = blend(0, Dca, 0, Da)  [definition of blend()]
316*c8dee2aaSAndroid Build Coastguard Worker                 = blend(f*Sca, Dca, f*Sa, Da)  [Sa=0]
317*c8dee2aaSAndroid Build Coastguard Worker 
318*c8dee2aaSAndroid Build Coastguard Worker         Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
319*c8dee2aaSAndroid Build Coastguard Worker                 = f * Sca + (1-f) * Dca  [Da=0, definition of blend()]
320*c8dee2aaSAndroid Build Coastguard Worker                 = f * Sca  [Da=0]
321*c8dee2aaSAndroid Build Coastguard Worker                 = blend(f*Sca, 0, f*Sa, 0)  [definition of blend()]
322*c8dee2aaSAndroid Build Coastguard Worker                 = blend(f*Sca, Dca, f*Sa, Da)  [Da=0]
323*c8dee2aaSAndroid Build Coastguard Worker 
324*c8dee2aaSAndroid Build Coastguard Worker         f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
325*c8dee2aaSAndroid Build Coastguard Worker                = Dca  [f=0]
326*c8dee2aaSAndroid Build Coastguard Worker                = blend(0, Dca, 0, Da)  [definition of blend()]
327*c8dee2aaSAndroid Build Coastguard Worker                = blend(f*Sca, Dca, f*Sa, Da)  [f=0]
328*c8dee2aaSAndroid Build Coastguard Worker 
329*c8dee2aaSAndroid Build Coastguard Worker       == Alpha ==
330*c8dee2aaSAndroid Build Coastguard Worker 
331*c8dee2aaSAndroid Build Coastguard Worker       We substitute X=Y=Z=1 and define a blend() function that calculates Da':
332*c8dee2aaSAndroid Build Coastguard Worker 
333*c8dee2aaSAndroid Build Coastguard Worker         blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa)
334*c8dee2aaSAndroid Build Coastguard Worker                       = Sa * Da + Sa - Sa * Da + Da - Da * Sa
335*c8dee2aaSAndroid Build Coastguard Worker                       = Sa + Da - Sa * Da
336*c8dee2aaSAndroid Build Coastguard Worker 
337*c8dee2aaSAndroid Build Coastguard Worker       We use the same model for coverage modulation as we did with color:
338*c8dee2aaSAndroid Build Coastguard Worker 
339*c8dee2aaSAndroid Build Coastguard Worker         Da'' = f * blend(Sa, Da) + (1-f) * Da
340*c8dee2aaSAndroid Build Coastguard Worker 
341*c8dee2aaSAndroid Build Coastguard Worker       And show that canTweakAlphaForCoverage() is true by proving the following
342*c8dee2aaSAndroid Build Coastguard Worker       relationship:
343*c8dee2aaSAndroid Build Coastguard Worker 
344*c8dee2aaSAndroid Build Coastguard Worker         blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da
345*c8dee2aaSAndroid Build Coastguard Worker 
346*c8dee2aaSAndroid Build Coastguard Worker 
347*c8dee2aaSAndroid Build Coastguard Worker         f * blend(Sa, Da) + (1-f) * Da
348*c8dee2aaSAndroid Build Coastguard Worker           = f * (Sa + Da - Sa * Da) + (1-f) * Da
349*c8dee2aaSAndroid Build Coastguard Worker           = f*Sa + f*Da - f*Sa * Da + Da - f*Da
350*c8dee2aaSAndroid Build Coastguard Worker           = f*Sa - f*Sa * Da + Da
351*c8dee2aaSAndroid Build Coastguard Worker           = f*Sa + Da - f*Sa * Da
352*c8dee2aaSAndroid Build Coastguard Worker           = blend(f*Sa, Da)
353*c8dee2aaSAndroid Build Coastguard Worker     */
354*c8dee2aaSAndroid Build Coastguard Worker     if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) {
355*c8dee2aaSAndroid Build Coastguard Worker         if (caps.blendEquationSupport() == GrCaps::kAdvancedCoherent_BlendEquationSupport) {
356*c8dee2aaSAndroid Build Coastguard Worker             return AnalysisProperties::kCompatibleWithCoverageAsAlpha;
357*c8dee2aaSAndroid Build Coastguard Worker         } else {
358*c8dee2aaSAndroid Build Coastguard Worker             return AnalysisProperties::kCompatibleWithCoverageAsAlpha |
359*c8dee2aaSAndroid Build Coastguard Worker                    AnalysisProperties::kRequiresNonOverlappingDraws |
360*c8dee2aaSAndroid Build Coastguard Worker                    AnalysisProperties::kUsesNonCoherentHWBlending;
361*c8dee2aaSAndroid Build Coastguard Worker         }
362*c8dee2aaSAndroid Build Coastguard Worker     }
363*c8dee2aaSAndroid Build Coastguard Worker     return AnalysisProperties::kCompatibleWithCoverageAsAlpha |
364*c8dee2aaSAndroid Build Coastguard Worker            AnalysisProperties::kReadsDstInShader;
365*c8dee2aaSAndroid Build Coastguard Worker }
366*c8dee2aaSAndroid Build Coastguard Worker 
GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory) const367*c8dee2aaSAndroid Build Coastguard Worker GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory)
368*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
369*c8dee2aaSAndroid Build Coastguard Worker const GrXPFactory* CustomXPFactory::TestGet(GrProcessorTestData* d) {
370*c8dee2aaSAndroid Build Coastguard Worker     int mode = d->fRandom->nextRangeU((int)SkBlendMode::kLastCoeffMode + 1,
371*c8dee2aaSAndroid Build Coastguard Worker                                       (int)SkBlendMode::kLastSeparableMode);
372*c8dee2aaSAndroid Build Coastguard Worker 
373*c8dee2aaSAndroid Build Coastguard Worker     return GrCustomXfermode::Get((SkBlendMode)mode);
374*c8dee2aaSAndroid Build Coastguard Worker }
375*c8dee2aaSAndroid Build Coastguard Worker #endif
376*c8dee2aaSAndroid Build Coastguard Worker 
377*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
378*c8dee2aaSAndroid Build Coastguard Worker 
Get(SkBlendMode mode)379*c8dee2aaSAndroid Build Coastguard Worker const GrXPFactory* GrCustomXfermode::Get(SkBlendMode mode) {
380*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gOverlay(SkBlendMode::kOverlay);
381*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gDarken(SkBlendMode::kDarken);
382*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gLighten(SkBlendMode::kLighten);
383*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gColorDodge(SkBlendMode::kColorDodge);
384*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gColorBurn(SkBlendMode::kColorBurn);
385*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gHardLight(SkBlendMode::kHardLight);
386*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gSoftLight(SkBlendMode::kSoftLight);
387*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gDifference(SkBlendMode::kDifference);
388*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gExclusion(SkBlendMode::kExclusion);
389*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gMultiply(SkBlendMode::kMultiply);
390*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gHue(SkBlendMode::kHue);
391*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gSaturation(SkBlendMode::kSaturation);
392*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gColor(SkBlendMode::kColor);
393*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const CustomXPFactory gLuminosity(SkBlendMode::kLuminosity);
394*c8dee2aaSAndroid Build Coastguard Worker     switch (mode) {
395*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kOverlay:
396*c8dee2aaSAndroid Build Coastguard Worker             return &gOverlay;
397*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kDarken:
398*c8dee2aaSAndroid Build Coastguard Worker             return &gDarken;
399*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kLighten:
400*c8dee2aaSAndroid Build Coastguard Worker             return &gLighten;
401*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kColorDodge:
402*c8dee2aaSAndroid Build Coastguard Worker             return &gColorDodge;
403*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kColorBurn:
404*c8dee2aaSAndroid Build Coastguard Worker             return &gColorBurn;
405*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kHardLight:
406*c8dee2aaSAndroid Build Coastguard Worker             return &gHardLight;
407*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kSoftLight:
408*c8dee2aaSAndroid Build Coastguard Worker             return &gSoftLight;
409*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kDifference:
410*c8dee2aaSAndroid Build Coastguard Worker             return &gDifference;
411*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kExclusion:
412*c8dee2aaSAndroid Build Coastguard Worker             return &gExclusion;
413*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kMultiply:
414*c8dee2aaSAndroid Build Coastguard Worker             return &gMultiply;
415*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kHue:
416*c8dee2aaSAndroid Build Coastguard Worker             return &gHue;
417*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kSaturation:
418*c8dee2aaSAndroid Build Coastguard Worker             return &gSaturation;
419*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kColor:
420*c8dee2aaSAndroid Build Coastguard Worker             return &gColor;
421*c8dee2aaSAndroid Build Coastguard Worker         case SkBlendMode::kLuminosity:
422*c8dee2aaSAndroid Build Coastguard Worker             return &gLuminosity;
423*c8dee2aaSAndroid Build Coastguard Worker         default:
424*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!GrCustomXfermode::IsSupportedMode(mode));
425*c8dee2aaSAndroid Build Coastguard Worker             return nullptr;
426*c8dee2aaSAndroid Build Coastguard Worker     }
427*c8dee2aaSAndroid Build Coastguard Worker }
428