blob: c476f64fd69875cede13ad1307a4559beac4382e [file] [log] [blame]
Brian Salomon92ce5942017-01-18 11:01:10 -05001/*
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 "GrProcessorSet.h"
Brian Salomon5298dc82017-02-22 11:52:03 -05009#include "GrAppliedClip.h"
10#include "GrCaps.h"
Brian Salomon31853842017-03-28 16:32:05 -040011#include "GrXferProcessor.h"
Brian Salomon477d0ef2017-07-14 10:12:26 -040012#include "SkBlendModePriv.h"
Brian Salomon48d1b4c2017-04-08 07:38:53 -040013#include "effects/GrPorterDuffXferProcessor.h"
Brian Salomon92ce5942017-01-18 11:01:10 -050014
Brian Salomon292bf7a2017-05-17 09:43:55 -040015const GrProcessorSet& GrProcessorSet::EmptySet() {
16 static const GrProcessorSet gEmpty(GrProcessorSet::Empty::kEmpty);
17 return gEmpty;
18}
Brian Salomon6d4b65e2017-05-03 17:06:09 -040019
Brian Salomon48d1b4c2017-04-08 07:38:53 -040020GrProcessorSet::GrProcessorSet(GrPaint&& paint) : fXP(paint.getXPFactory()) {
Brian Salomonf87e2b92017-01-19 11:31:50 -050021 fFlags = 0;
Brian Salomon8d2f90b2017-03-13 09:11:58 -040022 if (paint.numColorFragmentProcessors() <= kMaxColorProcessors) {
23 fColorFragmentProcessorCnt = paint.numColorFragmentProcessors();
24 fFragmentProcessors.reset(paint.numTotalFragmentProcessors());
25 int i = 0;
26 for (auto& fp : paint.fColorFragmentProcessors) {
Brian Salomon5f970fe2017-06-16 17:30:59 -040027 SkASSERT(fp.get());
Brian Salomon8d2f90b2017-03-13 09:11:58 -040028 fFragmentProcessors[i++] = fp.release();
29 }
30 for (auto& fp : paint.fCoverageFragmentProcessors) {
Brian Salomon5f970fe2017-06-16 17:30:59 -040031 SkASSERT(fp.get());
Brian Salomon8d2f90b2017-03-13 09:11:58 -040032 fFragmentProcessors[i++] = fp.release();
33 }
Brian Salomon8d2f90b2017-03-13 09:11:58 -040034 } else {
35 SkDebugf("Insane number of color fragment processors in paint. Dropping all processors.");
36 fColorFragmentProcessorCnt = 0;
Brian Salomonf87e2b92017-01-19 11:31:50 -050037 }
Brian Salomon92ce5942017-01-18 11:01:10 -050038}
Brian Salomon5298dc82017-02-22 11:52:03 -050039
Brian Salomon477d0ef2017-07-14 10:12:26 -040040GrProcessorSet::GrProcessorSet(SkBlendMode mode)
41 : fXP(SkBlendMode_AsXPFactory(mode))
42 , fColorFragmentProcessorCnt(0)
43 , fFragmentProcessorOffset(0)
44 , fFlags(0) {}
45
Brian Salomon82ddc942017-07-14 12:00:13 -040046GrProcessorSet::GrProcessorSet(sk_sp<GrFragmentProcessor> colorFP)
47 : fFragmentProcessors(1)
48 , fXP((const GrXPFactory*)nullptr)
49 , fColorFragmentProcessorCnt(1)
50 , fFragmentProcessorOffset(0)
51 , fFlags(0) {
52 SkASSERT(colorFP);
53 fFragmentProcessors[0] = colorFP.release();
54}
55
Brian Salomon54d212e2017-03-21 14:22:38 -040056GrProcessorSet::~GrProcessorSet() {
Brian Salomon70288c02017-03-24 12:27:17 -040057 for (int i = fFragmentProcessorOffset; i < fFragmentProcessors.count(); ++i) {
Brian Salomon48d1b4c2017-04-08 07:38:53 -040058 if (this->isFinalized()) {
Brian Salomon70288c02017-03-24 12:27:17 -040059 fFragmentProcessors[i]->completedExecution();
60 } else {
61 fFragmentProcessors[i]->unref();
Brian Salomon54d212e2017-03-21 14:22:38 -040062 }
63 }
Brian Salomon48d1b4c2017-04-08 07:38:53 -040064 if (this->isFinalized() && this->xferProcessor()) {
Brian Salomond61c9d92017-04-10 10:54:25 -040065 this->xferProcessor()->unref();
Brian Salomon54d212e2017-03-21 14:22:38 -040066 }
67}
68
Brian Salomon82dfd3d2017-06-14 12:30:35 -040069SkString dump_fragment_processor_tree(const GrFragmentProcessor* fp, int indentCnt) {
70 SkString result;
71 SkString indentString;
72 for (int i = 0; i < indentCnt; ++i) {
73 indentString.append(" ");
74 }
75 result.appendf("%s%s %s \n", indentString.c_str(), fp->name(), fp->dumpInfo().c_str());
76 if (fp->numChildProcessors()) {
77 for (int i = 0; i < fp->numChildProcessors(); ++i) {
78 result += dump_fragment_processor_tree(&fp->childProcessor(i), indentCnt + 1);
79 }
80 }
81 return result;
82}
83
84SkString GrProcessorSet::dumpProcessors() const {
85 SkString result;
86 if (this->numFragmentProcessors()) {
87 if (this->numColorFragmentProcessors()) {
88 result.append("Color Fragment Processors:\n");
89 for (int i = 0; i < this->numColorFragmentProcessors(); ++i) {
90 result += dump_fragment_processor_tree(this->colorFragmentProcessor(i), 1);
91 }
92 } else {
93 result.append("No color fragment processors.\n");
94 }
95 if (this->numCoverageFragmentProcessors()) {
96 result.append("Coverage Fragment Processors:\n");
97 for (int i = 0; i < this->numColorFragmentProcessors(); ++i) {
98 result += dump_fragment_processor_tree(this->coverageFragmentProcessor(i), 1);
99 }
100 } else {
101 result.append("No coverage fragment processors.\n");
102 }
103 } else {
104 result.append("No color or coverage fragment processors.\n");
105 }
106 if (this->isFinalized()) {
107 result.append("Xfer Processor: ");
108 if (this->xferProcessor()) {
109 result.appendf("%s\n", this->xferProcessor()->name());
110 } else {
111 result.append("SrcOver\n");
112 }
113 } else {
114 result.append("XP Factory dumping not implemented.\n");
115 }
116 return result;
117}
118
Brian Salomon54d212e2017-03-21 14:22:38 -0400119bool GrProcessorSet::operator==(const GrProcessorSet& that) const {
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400120 SkASSERT(this->isFinalized());
121 SkASSERT(that.isFinalized());
Brian Salomon70288c02017-03-24 12:27:17 -0400122 int fpCount = this->numFragmentProcessors();
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400123 if (((fFlags ^ that.fFlags) & ~kFinalized_Flag) || fpCount != that.numFragmentProcessors() ||
Brian Salomon54d212e2017-03-21 14:22:38 -0400124 fColorFragmentProcessorCnt != that.fColorFragmentProcessorCnt) {
125 return false;
126 }
Brian Salomon70288c02017-03-24 12:27:17 -0400127
128 for (int i = 0; i < fpCount; ++i) {
129 int a = i + fFragmentProcessorOffset;
130 int b = i + that.fFragmentProcessorOffset;
131 if (!fFragmentProcessors[a]->isEqual(*that.fFragmentProcessors[b])) {
Brian Salomon54d212e2017-03-21 14:22:38 -0400132 return false;
133 }
134 }
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400135 // Most of the time both of these are null
136 if (!this->xferProcessor() && !that.xferProcessor()) {
137 return true;
Brian Salomon54d212e2017-03-21 14:22:38 -0400138 }
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400139 const GrXferProcessor& thisXP = this->xferProcessor()
140 ? *this->xferProcessor()
141 : GrPorterDuffXPFactory::SimpleSrcOverXP();
142 const GrXferProcessor& thatXP = that.xferProcessor()
143 ? *that.xferProcessor()
144 : GrPorterDuffXPFactory::SimpleSrcOverXP();
145 return thisXP.isEqual(thatXP);
Brian Salomon54d212e2017-03-21 14:22:38 -0400146}
147
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400148GrProcessorSet::Analysis GrProcessorSet::finalize(const GrProcessorAnalysisColor& colorInput,
149 const GrProcessorAnalysisCoverage coverageInput,
150 const GrAppliedClip* clip, bool isMixedSamples,
151 const GrCaps& caps, GrColor* overrideInputColor) {
152 SkASSERT(!this->isFinalized());
153 SkASSERT(!fFragmentProcessorOffset);
Brian Salomon5298dc82017-02-22 11:52:03 -0500154
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400155 GrProcessorSet::Analysis analysis;
Brian Salomon5298dc82017-02-22 11:52:03 -0500156
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400157 const GrFragmentProcessor* clipFP = clip ? clip->clipCoverageFragmentProcessor() : nullptr;
158 GrColorFragmentProcessorAnalysis colorAnalysis(colorInput);
159 analysis.fCompatibleWithCoverageAsAlpha = GrProcessorAnalysisCoverage::kLCD != coverageInput;
160
161 const GrFragmentProcessor* const* fps = fFragmentProcessors.get() + fFragmentProcessorOffset;
162 colorAnalysis.analyzeProcessors(fps, fColorFragmentProcessorCnt);
163 analysis.fCompatibleWithCoverageAsAlpha &=
164 colorAnalysis.allProcessorsCompatibleWithCoverageAsAlpha();
165 fps += fColorFragmentProcessorCnt;
166 int n = this->numCoverageFragmentProcessors();
Brian Salomon5298dc82017-02-22 11:52:03 -0500167 bool hasCoverageFP = n > 0;
Brian Salomon31853842017-03-28 16:32:05 -0400168 bool coverageUsesLocalCoords = false;
Brian Salomonbfafcba2017-03-02 08:49:19 -0500169 for (int i = 0; i < n; ++i) {
Brian Salomon5298dc82017-02-22 11:52:03 -0500170 if (!fps[i]->compatibleWithCoverageAsAlpha()) {
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400171 analysis.fCompatibleWithCoverageAsAlpha = false;
Brian Salomon5298dc82017-02-22 11:52:03 -0500172 // Other than tests that exercise atypical behavior we expect all coverage FPs to be
173 // compatible with the coverage-as-alpha optimization.
174 GrCapsDebugf(&caps, "Coverage FP is not compatible with coverage as alpha.\n");
Brian Salomon5298dc82017-02-22 11:52:03 -0500175 }
Brian Salomon31853842017-03-28 16:32:05 -0400176 coverageUsesLocalCoords |= fps[i]->usesLocalCoords();
Brian Salomon5298dc82017-02-22 11:52:03 -0500177 }
178
179 if (clipFP) {
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400180 analysis.fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha();
Brian Salomon31853842017-03-28 16:32:05 -0400181 coverageUsesLocalCoords |= clipFP->usesLocalCoords();
Brian Salomon5298dc82017-02-22 11:52:03 -0500182 hasCoverageFP = true;
183 }
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400184 int colorFPsToEliminate = colorAnalysis.initialProcessorsToEliminate(overrideInputColor);
185 analysis.fInputColorType = static_cast<Analysis::PackedInputColorType>(
186 colorFPsToEliminate ? Analysis::kOverridden_InputColorType
187 : Analysis::kOriginal_InputColorType);
Brian Salomon5298dc82017-02-22 11:52:03 -0500188
Brian Salomona811b122017-03-30 08:21:32 -0400189 GrProcessorAnalysisCoverage outputCoverage;
190 if (GrProcessorAnalysisCoverage::kLCD == coverageInput) {
191 outputCoverage = GrProcessorAnalysisCoverage::kLCD;
192 } else if (hasCoverageFP || GrProcessorAnalysisCoverage::kSingleChannel == coverageInput) {
193 outputCoverage = GrProcessorAnalysisCoverage::kSingleChannel;
Brian Salomon5298dc82017-02-22 11:52:03 -0500194 } else {
Brian Salomona811b122017-03-30 08:21:32 -0400195 outputCoverage = GrProcessorAnalysisCoverage::kNone;
Brian Salomon31853842017-03-28 16:32:05 -0400196 }
Brian Salomon31853842017-03-28 16:32:05 -0400197
198 GrXPFactory::AnalysisProperties props = GrXPFactory::GetAnalysisProperties(
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400199 this->xpFactory(), colorAnalysis.outputColor(), outputCoverage, caps);
200 if (!this->numCoverageFragmentProcessors() &&
Brian Salomona811b122017-03-30 08:21:32 -0400201 GrProcessorAnalysisCoverage::kNone == coverageInput) {
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400202 analysis.fCanCombineOverlappedStencilAndCover = SkToBool(
Brian Salomon31853842017-03-28 16:32:05 -0400203 props & GrXPFactory::AnalysisProperties::kCanCombineOverlappedStencilAndCover);
204 } else {
205 // If we have non-clipping coverage processors we don't try to merge stencil steps as its
206 // unclear whether it will be correct. We don't expect this to happen in practice.
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400207 analysis.fCanCombineOverlappedStencilAndCover = false;
Brian Salomon31853842017-03-28 16:32:05 -0400208 }
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400209 analysis.fRequiresDstTexture =
210 SkToBool(props & GrXPFactory::AnalysisProperties::kRequiresDstTexture);
211 analysis.fCompatibleWithCoverageAsAlpha &=
Brian Salomon31853842017-03-28 16:32:05 -0400212 SkToBool(props & GrXPFactory::AnalysisProperties::kCompatibleWithAlphaAsCoverage);
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400213 analysis.fRequiresBarrierBetweenOverlappingDraws = SkToBool(
Brian Salomon4fc77402017-03-30 16:48:26 -0400214 props & GrXPFactory::AnalysisProperties::kRequiresBarrierBetweenOverlappingDraws);
Brian Salomon31853842017-03-28 16:32:05 -0400215 if (props & GrXPFactory::AnalysisProperties::kIgnoresInputColor) {
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400216 colorFPsToEliminate = this->numColorFragmentProcessors();
217 analysis.fInputColorType =
218 static_cast<Analysis::PackedInputColorType>(Analysis::kIgnored_InputColorType);
219 analysis.fUsesLocalCoords = coverageUsesLocalCoords;
Brian Salomon31853842017-03-28 16:32:05 -0400220 } else {
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400221 analysis.fUsesLocalCoords = coverageUsesLocalCoords | colorAnalysis.usesLocalCoords();
Brian Salomon5298dc82017-02-22 11:52:03 -0500222 }
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400223 for (int i = 0; i < colorFPsToEliminate; ++i) {
224 fFragmentProcessors[i]->unref();
225 fFragmentProcessors[i] = nullptr;
Brian Salomon5dac9b32017-04-08 02:53:30 +0000226 }
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400227 for (int i = colorFPsToEliminate; i < fFragmentProcessors.count(); ++i) {
228 fFragmentProcessors[i]->addPendingExecution();
229 fFragmentProcessors[i]->unref();
230 }
231 fFragmentProcessorOffset = colorFPsToEliminate;
232 fColorFragmentProcessorCnt -= colorFPsToEliminate;
233
234 auto xp = GrXPFactory::MakeXferProcessor(this->xpFactory(), colorAnalysis.outputColor(),
235 outputCoverage, isMixedSamples, caps);
Brian Salomond61c9d92017-04-10 10:54:25 -0400236 fXP.fProcessor = xp.release();
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400237
Brian Salomond61c9d92017-04-10 10:54:25 -0400238 fFlags |= kFinalized_Flag;
Brian Salomon48d1b4c2017-04-08 07:38:53 -0400239 analysis.fIsInitialized = true;
240 return analysis;
Brian Salomon70288c02017-03-24 12:27:17 -0400241}