blob: 0350ba57586f0b1cbf6b054336310ef36c6a6b69 [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 Salomonc0b642c2017-03-27 13:09:36 -040011#include "GrPipelineAnalysis.h"
Brian Salomon31853842017-03-28 16:32:05 -040012#include "GrXferProcessor.h"
Brian Salomon92ce5942017-01-18 11:01:10 -050013
14GrProcessorSet::GrProcessorSet(GrPaint&& paint) {
15 fXPFactory = paint.fXPFactory;
Brian Salomonf87e2b92017-01-19 11:31:50 -050016 fFlags = 0;
Brian Salomon8d2f90b2017-03-13 09:11:58 -040017 if (paint.numColorFragmentProcessors() <= kMaxColorProcessors) {
18 fColorFragmentProcessorCnt = paint.numColorFragmentProcessors();
19 fFragmentProcessors.reset(paint.numTotalFragmentProcessors());
20 int i = 0;
21 for (auto& fp : paint.fColorFragmentProcessors) {
22 fFragmentProcessors[i++] = fp.release();
23 }
24 for (auto& fp : paint.fCoverageFragmentProcessors) {
25 fFragmentProcessors[i++] = fp.release();
26 }
27 if (paint.usesDistanceVectorField()) {
28 fFlags |= kUseDistanceVectorField_Flag;
29 }
30 } else {
31 SkDebugf("Insane number of color fragment processors in paint. Dropping all processors.");
32 fColorFragmentProcessorCnt = 0;
Brian Salomonf87e2b92017-01-19 11:31:50 -050033 }
34 if (paint.getDisableOutputConversionToSRGB()) {
35 fFlags |= kDisableOutputConversionToSRGB_Flag;
36 }
37 if (paint.getAllowSRGBInputs()) {
38 fFlags |= kAllowSRGBInputs_Flag;
39 }
Brian Salomon92ce5942017-01-18 11:01:10 -050040}
Brian Salomon5298dc82017-02-22 11:52:03 -050041
Brian Salomon54d212e2017-03-21 14:22:38 -040042GrProcessorSet::~GrProcessorSet() {
Brian Salomon70288c02017-03-24 12:27:17 -040043 for (int i = fFragmentProcessorOffset; i < fFragmentProcessors.count(); ++i) {
44 if (this->isPendingExecution()) {
45 fFragmentProcessors[i]->completedExecution();
46 } else {
47 fFragmentProcessors[i]->unref();
Brian Salomon54d212e2017-03-21 14:22:38 -040048 }
49 }
50}
51
52void GrProcessorSet::makePendingExecution() {
53 SkASSERT(!(kPendingExecution_Flag & fFlags));
54 fFlags |= kPendingExecution_Flag;
Brian Salomon70288c02017-03-24 12:27:17 -040055 for (int i = fFragmentProcessorOffset; i < fFragmentProcessors.count(); ++i) {
Brian Salomon54d212e2017-03-21 14:22:38 -040056 fFragmentProcessors[i]->addPendingExecution();
57 fFragmentProcessors[i]->unref();
58 }
59}
60
61bool GrProcessorSet::operator==(const GrProcessorSet& that) const {
Brian Salomon70288c02017-03-24 12:27:17 -040062 int fpCount = this->numFragmentProcessors();
Brian Salomon54d212e2017-03-21 14:22:38 -040063 if (((fFlags ^ that.fFlags) & ~kPendingExecution_Flag) ||
Brian Salomon70288c02017-03-24 12:27:17 -040064 fpCount != that.numFragmentProcessors() ||
Brian Salomon54d212e2017-03-21 14:22:38 -040065 fColorFragmentProcessorCnt != that.fColorFragmentProcessorCnt) {
66 return false;
67 }
Brian Salomon70288c02017-03-24 12:27:17 -040068
69 for (int i = 0; i < fpCount; ++i) {
70 int a = i + fFragmentProcessorOffset;
71 int b = i + that.fFragmentProcessorOffset;
72 if (!fFragmentProcessors[a]->isEqual(*that.fFragmentProcessors[b])) {
Brian Salomon54d212e2017-03-21 14:22:38 -040073 return false;
74 }
75 }
76 if (fXPFactory != that.fXPFactory) {
77 return false;
78 }
79 return true;
80}
81
Brian Salomon5298dc82017-02-22 11:52:03 -050082//////////////////////////////////////////////////////////////////////////////
83
Brian Salomonc0b642c2017-03-27 13:09:36 -040084void GrProcessorSet::FragmentProcessorAnalysis::internalInit(
85 const GrPipelineAnalysisColor& colorInput,
86 const GrPipelineAnalysisCoverage coverageInput,
87 const GrProcessorSet& processors,
88 const GrFragmentProcessor* clipFP,
89 const GrCaps& caps) {
90 GrColorFragmentProcessorAnalysis colorInfo(colorInput);
91 fCompatibleWithCoverageAsAlpha = GrPipelineAnalysisCoverage::kLCD != coverageInput;
Brian Salomon8d2f90b2017-03-13 09:11:58 -040092 fValidInputColor = colorInput.isConstant(&fInputColor);
Brian Salomon5298dc82017-02-22 11:52:03 -050093
Brian Salomon70288c02017-03-24 12:27:17 -040094 const GrFragmentProcessor* const* fps =
95 processors.fFragmentProcessors.get() + processors.fFragmentProcessorOffset;
Brian Salomon5298dc82017-02-22 11:52:03 -050096 colorInfo.analyzeProcessors(fps, processors.fColorFragmentProcessorCnt);
97 fCompatibleWithCoverageAsAlpha &= colorInfo.allProcessorsCompatibleWithCoverageAsAlpha();
98 fps += processors.fColorFragmentProcessorCnt;
99 int n = processors.numCoverageFragmentProcessors();
100 bool hasCoverageFP = n > 0;
Brian Salomon31853842017-03-28 16:32:05 -0400101 bool coverageUsesLocalCoords = false;
Brian Salomonbfafcba2017-03-02 08:49:19 -0500102 for (int i = 0; i < n; ++i) {
Brian Salomon5298dc82017-02-22 11:52:03 -0500103 if (!fps[i]->compatibleWithCoverageAsAlpha()) {
104 fCompatibleWithCoverageAsAlpha = false;
105 // Other than tests that exercise atypical behavior we expect all coverage FPs to be
106 // compatible with the coverage-as-alpha optimization.
107 GrCapsDebugf(&caps, "Coverage FP is not compatible with coverage as alpha.\n");
Brian Salomon5298dc82017-02-22 11:52:03 -0500108 }
Brian Salomon31853842017-03-28 16:32:05 -0400109 coverageUsesLocalCoords |= fps[i]->usesLocalCoords();
Brian Salomon5298dc82017-02-22 11:52:03 -0500110 }
111
112 if (clipFP) {
113 fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha();
Brian Salomon31853842017-03-28 16:32:05 -0400114 coverageUsesLocalCoords |= clipFP->usesLocalCoords();
Brian Salomon5298dc82017-02-22 11:52:03 -0500115 hasCoverageFP = true;
116 }
Brian Salomon8d2f90b2017-03-13 09:11:58 -0400117 fInitialColorProcessorsToEliminate = colorInfo.initialProcessorsToEliminate(&fInputColor);
118 fValidInputColor |= SkToBool(fInitialColorProcessorsToEliminate);
Brian Salomon5298dc82017-02-22 11:52:03 -0500119
Brian Salomonc0b642c2017-03-27 13:09:36 -0400120 GrPipelineAnalysisColor outputColor = colorInfo.outputColor();
121 if (outputColor.isConstant(&fKnownOutputColor)) {
122 fOutputColorType = static_cast<unsigned>(outputColor.isOpaque() ? ColorType::kOpaqueConstant
123 : ColorType::kConstant);
124 } else if (outputColor.isOpaque()) {
Brian Salomon8d2f90b2017-03-13 09:11:58 -0400125 fOutputColorType = static_cast<unsigned>(ColorType::kOpaque);
Brian Salomon5298dc82017-02-22 11:52:03 -0500126 } else {
Brian Salomon8d2f90b2017-03-13 09:11:58 -0400127 fOutputColorType = static_cast<unsigned>(ColorType::kUnknown);
Brian Salomon5298dc82017-02-22 11:52:03 -0500128 }
129
Brian Salomon31853842017-03-28 16:32:05 -0400130 GrPipelineAnalysisCoverage outputCoverage;
Brian Salomonc0b642c2017-03-27 13:09:36 -0400131 if (GrPipelineAnalysisCoverage::kLCD == coverageInput) {
Brian Salomon31853842017-03-28 16:32:05 -0400132 outputCoverage = GrPipelineAnalysisCoverage::kLCD;
Brian Salomonc0b642c2017-03-27 13:09:36 -0400133 } else if (hasCoverageFP || GrPipelineAnalysisCoverage::kSingleChannel == coverageInput) {
Brian Salomon31853842017-03-28 16:32:05 -0400134 outputCoverage = GrPipelineAnalysisCoverage::kSingleChannel;
Brian Salomon5298dc82017-02-22 11:52:03 -0500135 } else {
Brian Salomon31853842017-03-28 16:32:05 -0400136 outputCoverage = GrPipelineAnalysisCoverage::kNone;
137 }
138 fOutputCoverageType = static_cast<unsigned>(outputCoverage);
139
140 GrXPFactory::AnalysisProperties props = GrXPFactory::GetAnalysisProperties(
141 processors.fXPFactory, colorInfo.outputColor(), outputCoverage, caps);
142 if (!processors.numCoverageFragmentProcessors() &&
143 GrPipelineAnalysisCoverage::kNone == coverageInput) {
144 fCanCombineOverlappedStencilAndCover = SkToBool(
145 props & GrXPFactory::AnalysisProperties::kCanCombineOverlappedStencilAndCover);
146 } else {
147 // If we have non-clipping coverage processors we don't try to merge stencil steps as its
148 // unclear whether it will be correct. We don't expect this to happen in practice.
149 fCanCombineOverlappedStencilAndCover = false;
150 }
151 fRequiresDstTexture = SkToBool(props & GrXPFactory::AnalysisProperties::kRequiresDstTexture);
152 fIgnoresInputColor = SkToBool(props & GrXPFactory::AnalysisProperties::kIgnoresInputColor);
153 fCompatibleWithCoverageAsAlpha &=
154 SkToBool(props & GrXPFactory::AnalysisProperties::kCompatibleWithAlphaAsCoverage);
155 if (props & GrXPFactory::AnalysisProperties::kIgnoresInputColor) {
156 fInitialColorProcessorsToEliminate = processors.numColorFragmentProcessors();
157 // If the output of the last color stage is known then the kIgnoresInputColor optimization
158 // may depend upon it being the input to the xp.
159 if (!outputColor.isConstant(&fInputColor)) {
160 // Otherwise, the only property the XP factory could have relied upon to compute
161 // kIgnoresInputColor is opaqueness.
162 fInputColor = GrColor_WHITE;
163 }
164 fValidInputColor = true;
165 fUsesLocalCoords = coverageUsesLocalCoords;
166 } else {
167 fUsesLocalCoords = coverageUsesLocalCoords | colorInfo.usesLocalCoords();
Brian Salomon5298dc82017-02-22 11:52:03 -0500168 }
169}
170
Brian Salomonc0b642c2017-03-27 13:09:36 -0400171void GrProcessorSet::FragmentProcessorAnalysis::init(const GrPipelineAnalysisColor& colorInput,
172 const GrPipelineAnalysisCoverage coverageInput,
Brian Salomon8d2f90b2017-03-13 09:11:58 -0400173 const GrProcessorSet& processors,
174 const GrAppliedClip* appliedClip,
175 const GrCaps& caps) {
176 const GrFragmentProcessor* clipFP =
177 appliedClip ? appliedClip->clipCoverageFragmentProcessor() : nullptr;
178 this->internalInit(colorInput, coverageInput, processors, clipFP, caps);
179 fIsInitializedWithProcessorSet = true;
Brian Salomon5298dc82017-02-22 11:52:03 -0500180}
181
182GrProcessorSet::FragmentProcessorAnalysis::FragmentProcessorAnalysis(
Brian Salomonc0b642c2017-03-27 13:09:36 -0400183 const GrPipelineAnalysisColor& colorInput,
184 const GrPipelineAnalysisCoverage coverageInput,
Brian Salomon31853842017-03-28 16:32:05 -0400185 const GrXPFactory* factory,
Brian Salomonc0b642c2017-03-27 13:09:36 -0400186 const GrCaps& caps)
Brian Salomon5298dc82017-02-22 11:52:03 -0500187 : FragmentProcessorAnalysis() {
Brian Salomon31853842017-03-28 16:32:05 -0400188 GrPaint paint;
189 paint.setXPFactory(factory);
190 this->internalInit(colorInput, coverageInput, GrProcessorSet(std::move(paint)), nullptr, caps);
Brian Salomon5298dc82017-02-22 11:52:03 -0500191}
Brian Salomon70288c02017-03-24 12:27:17 -0400192
Brian Salomonc0b642c2017-03-27 13:09:36 -0400193void GrProcessorSet::analyzeAndEliminateFragmentProcessors(
194 FragmentProcessorAnalysis* analysis,
195 const GrPipelineAnalysisColor& colorInput,
196 const GrPipelineAnalysisCoverage coverageInput,
197 const GrAppliedClip* clip,
198 const GrCaps& caps) {
Brian Salomon70288c02017-03-24 12:27:17 -0400199 analysis->init(colorInput, coverageInput, *this, clip, caps);
200 if (analysis->fInitialColorProcessorsToEliminate > 0) {
201 for (unsigned i = 0; i < analysis->fInitialColorProcessorsToEliminate; ++i) {
202 if (this->isPendingExecution()) {
203 fFragmentProcessors[i + fFragmentProcessorOffset]->completedExecution();
204 } else {
205 fFragmentProcessors[i + fFragmentProcessorOffset]->unref();
206 }
207 fFragmentProcessors[i + fFragmentProcessorOffset] = nullptr;
208 }
209 fFragmentProcessorOffset += analysis->fInitialColorProcessorsToEliminate;
210 fColorFragmentProcessorCnt -= analysis->fInitialColorProcessorsToEliminate;
211 SkASSERT(fFragmentProcessorOffset + fColorFragmentProcessorCnt <=
212 fFragmentProcessors.count());
213 analysis->fInitialColorProcessorsToEliminate = 0;
214 }
215}