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