1/*
2 * Copyright 2017 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/core/SkBlendModePriv.h"
9#include "src/gpu/GrAppliedClip.h"
10#include "src/gpu/GrCaps.h"
11#include "src/gpu/GrProcessorSet.h"
12#include "src/gpu/GrUserStencilSettings.h"
13#include "src/gpu/GrXferProcessor.h"
14#include "src/gpu/effects/GrPorterDuffXferProcessor.h"
15
16const GrProcessorSet& GrProcessorSet::EmptySet() {
17 static GrProcessorSet gEmpty(GrProcessorSet::Empty::kEmpty);
18 return gEmpty;
19}
20
21GrProcessorSet GrProcessorSet::MakeEmptySet() {
22 return GrProcessorSet(GrProcessorSet::Empty::kEmpty);
23}
24
25GrProcessorSet::GrProcessorSet(GrPaint&& paint) : fXP(paint.getXPFactory()) {
26 fColorFragmentProcessor = std::move(paint.fColorFragmentProcessor);
27 fCoverageFragmentProcessor = std::move(paint.fCoverageFragmentProcessor);
28
29 SkDEBUGCODE(paint.fAlive = false;)
30}
31
32GrProcessorSet::GrProcessorSet(SkBlendMode mode) : fXP(SkBlendMode_AsXPFactory(mode)) {}
33
34GrProcessorSet::GrProcessorSet(std::unique_ptr<GrFragmentProcessor> colorFP)
35 : fXP((const GrXPFactory*)nullptr) {
36 SkASSERT(colorFP);
37 fColorFragmentProcessor = std::move(colorFP);
38}
39
40GrProcessorSet::GrProcessorSet(GrProcessorSet&& that)
41 : fColorFragmentProcessor(std::move(that.fColorFragmentProcessor))
42 , fCoverageFragmentProcessor(std::move(that.fCoverageFragmentProcessor))
43 , fXP(std::move(that.fXP))
44 , fFlags(that.fFlags) {}
45
46GrProcessorSet::~GrProcessorSet() {
47 if (this->isFinalized() && this->xferProcessor()) {
48 this->xferProcessor()->unref();
49 }
50}
51
52#if GR_TEST_UTILS
53SkString GrProcessorSet::dumpProcessors() const {
54 SkString result;
55 if (this->hasColorFragmentProcessor()) {
56 result.append("Color Fragment Processor:\n");
57 result += this->colorFragmentProcessor()->dumpTreeInfo();
58 } else {
59 result.append("No color fragment processor.\n");
60 }
61 if (this->hasCoverageFragmentProcessor()) {
62 result.append("Coverage Fragment Processor:\n");
63 result += this->coverageFragmentProcessor()->dumpTreeInfo();
64 } else {
65 result.append("No coverage fragment processors.\n");
66 }
67 if (this->isFinalized()) {
68 result.append("Xfer Processor: ");
69 if (this->xferProcessor()) {
70 result.appendf("%s\n", this->xferProcessor()->name());
71 } else {
72 result.append("SrcOver\n");
73 }
74 } else {
75 result.append("XP Factory dumping not implemented.\n");
76 }
77 return result;
78}
79#endif
80
81bool GrProcessorSet::operator==(const GrProcessorSet& that) const {
82 SkASSERT(this->isFinalized());
83 SkASSERT(that.isFinalized());
84 if (((fFlags ^ that.fFlags) & ~kFinalized_Flag) ||
85 this->hasColorFragmentProcessor() != that.hasColorFragmentProcessor() ||
86 this->hasCoverageFragmentProcessor() != that.hasCoverageFragmentProcessor()) {
87 return false;
88 }
89
90 if (this->hasColorFragmentProcessor()) {
91 if (!colorFragmentProcessor()->isEqual(*that.colorFragmentProcessor())) {
92 return false;
93 }
94 }
95
96 if (this->hasCoverageFragmentProcessor()) {
97 if (!coverageFragmentProcessor()->isEqual(*that.coverageFragmentProcessor())) {
98 return false;
99 }
100 }
101
102 // Most of the time both of these are null
103 if (!this->xferProcessor() && !that.xferProcessor()) {
104 return true;
105 }
106 const GrXferProcessor& thisXP = this->xferProcessor()
107 ? *this->xferProcessor()
108 : GrPorterDuffXPFactory::SimpleSrcOverXP();
109 const GrXferProcessor& thatXP = that.xferProcessor()
110 ? *that.xferProcessor()
111 : GrPorterDuffXPFactory::SimpleSrcOverXP();
112 return thisXP.isEqual(thatXP);
113}
114
115GrProcessorSet::Analysis GrProcessorSet::finalize(
116 const GrProcessorAnalysisColor& colorInput, const GrProcessorAnalysisCoverage coverageInput,
117 const GrAppliedClip* clip, const GrUserStencilSettings* userStencil,
118 bool hasMixedSampledCoverage, const GrCaps& caps, GrClampType clampType,
119 SkPMColor4f* overrideInputColor) {
120 SkASSERT(!this->isFinalized());
121
122 GrProcessorSet::Analysis analysis;
123 analysis.fCompatibleWithCoverageAsAlpha = GrProcessorAnalysisCoverage::kLCD != coverageInput;
124
125 GrColorFragmentProcessorAnalysis colorAnalysis(colorInput, &fColorFragmentProcessor,
126 this->hasColorFragmentProcessor() ? 1 : 0);
127 bool hasCoverageFP = this->hasCoverageFragmentProcessor();
128 bool coverageUsesLocalCoords = false;
129 if (hasCoverageFP) {
130 if (!fCoverageFragmentProcessor->compatibleWithCoverageAsAlpha()) {
131 analysis.fCompatibleWithCoverageAsAlpha = false;
132 }
133 coverageUsesLocalCoords |= fCoverageFragmentProcessor->usesVaryingCoords();
134 }
135 if (clip && clip->hasCoverageFragmentProcessor()) {
136 hasCoverageFP = true;
137 const GrFragmentProcessor* clipFP = clip->coverageFragmentProcessor();
138 analysis.fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha();
139 coverageUsesLocalCoords |= clipFP->usesVaryingCoords();
140 }
141 int colorFPsToEliminate = colorAnalysis.initialProcessorsToEliminate(overrideInputColor);
142 analysis.fInputColorType = static_cast<Analysis::PackedInputColorType>(
143 colorFPsToEliminate ? Analysis::kOverridden_InputColorType
144 : Analysis::kOriginal_InputColorType);
145
146 GrProcessorAnalysisCoverage outputCoverage;
147 if (GrProcessorAnalysisCoverage::kLCD == coverageInput) {
148 outputCoverage = GrProcessorAnalysisCoverage::kLCD;
149 } else if (hasCoverageFP || GrProcessorAnalysisCoverage::kSingleChannel == coverageInput) {
150 outputCoverage = GrProcessorAnalysisCoverage::kSingleChannel;
151 } else {
152 outputCoverage = GrProcessorAnalysisCoverage::kNone;
153 }
154
155 GrXPFactory::AnalysisProperties props = GrXPFactory::GetAnalysisProperties(
156 this->xpFactory(), colorAnalysis.outputColor(), outputCoverage, caps, clampType);
157 analysis.fRequiresDstTexture =
158 SkToBool(props & GrXPFactory::AnalysisProperties::kRequiresDstTexture);
159 analysis.fCompatibleWithCoverageAsAlpha &=
160 SkToBool(props & GrXPFactory::AnalysisProperties::kCompatibleWithCoverageAsAlpha);
161 analysis.fRequiresNonOverlappingDraws =
162 SkToBool(props & GrXPFactory::AnalysisProperties::kRequiresNonOverlappingDraws);
163 if (props & GrXPFactory::AnalysisProperties::kIgnoresInputColor) {
164 colorFPsToEliminate = this->hasColorFragmentProcessor() ? 1 : 0;
165 analysis.fInputColorType =
166 static_cast<Analysis::PackedInputColorType>(Analysis::kIgnored_InputColorType);
167 analysis.fUsesLocalCoords = coverageUsesLocalCoords;
168 } else {
169 analysis.fCompatibleWithCoverageAsAlpha &=
170 colorAnalysis.allProcessorsCompatibleWithCoverageAsAlpha();
171 analysis.fUsesLocalCoords = coverageUsesLocalCoords | colorAnalysis.usesLocalCoords();
172 }
173 if (colorFPsToEliminate) {
174 SkASSERT(colorFPsToEliminate == 1);
175 fColorFragmentProcessor = nullptr;
176 }
177 analysis.fHasColorFragmentProcessor = this->hasColorFragmentProcessor();
178
179 auto xp = GrXPFactory::MakeXferProcessor(this->xpFactory(), colorAnalysis.outputColor(),
180 outputCoverage, hasMixedSampledCoverage, caps,
181 clampType);
182 fXP.fProcessor = xp.release();
183
184 fFlags |= kFinalized_Flag;
185 analysis.fIsInitialized = true;
186#ifdef SK_DEBUG
187 bool hasXferBarrier =
188 fXP.fProcessor &&
189 GrXferBarrierType::kNone_GrXferBarrierType != fXP.fProcessor->xferBarrierType(caps);
190 bool needsNonOverlappingDraws = analysis.fRequiresDstTexture || hasXferBarrier;
191 SkASSERT(analysis.fRequiresNonOverlappingDraws == needsNonOverlappingDraws);
192#endif
193 return analysis;
194}
195
196void GrProcessorSet::visitProxies(const GrOp::VisitProxyFunc& func) const {
197 if (this->hasColorFragmentProcessor()) {
198 fColorFragmentProcessor->visitProxies(func);
199 }
200 if (this->hasCoverageFragmentProcessor()) {
201 fCoverageFragmentProcessor->visitProxies(func);
202 }
203}
204