blob: 98a5689d534b72425a5df85f6409b64fd0f11dc6 [file] [log] [blame]
egdaniel3658f382014-09-15 07:01:59 -07001/*
2 * Copyright 2014 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 "GrOptDrawState.h"
9
10#include "GrDrawState.h"
egdanielc0648242014-09-22 13:17:02 -070011#include "GrDrawTargetCaps.h"
12#include "GrGpu.h"
egdaniel3658f382014-09-15 07:01:59 -070013
egdaniel170f90b2014-09-16 12:54:40 -070014GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
15 BlendOptFlags blendOptFlags,
16 GrBlendCoeff optSrcCoeff,
egdanielc0648242014-09-22 13:17:02 -070017 GrBlendCoeff optDstCoeff,
egdaniel89af44a2014-09-26 06:15:04 -070018 const GrDrawTargetCaps& caps) {
19 fRenderTarget.set(SkSafeRef(drawState.getRenderTarget()),
20 GrIORef::kWrite_IOType);
egdaniel3658f382014-09-15 07:01:59 -070021 fColor = drawState.getColor();
22 fCoverage = drawState.getCoverage();
23 fViewMatrix = drawState.getViewMatrix();
24 fBlendConstant = drawState.getBlendConstant();
25 fFlagBits = drawState.getFlagBits();
26 fVAPtr = drawState.getVertexAttribs();
27 fVACount = drawState.getVertexAttribCount();
28 fVAStride = drawState.getVertexStride();
29 fStencilSettings = drawState.getStencil();
egdaniel89af44a2014-09-26 06:15:04 -070030 fDrawFace = (DrawFace)drawState.getDrawFace();
egdaniel170f90b2014-09-16 12:54:40 -070031 fBlendOptFlags = blendOptFlags;
32 fSrcBlend = optSrcCoeff;
33 fDstBlend = optDstCoeff;
egdaniel3658f382014-09-15 07:01:59 -070034
35 memcpy(fFixedFunctionVertexAttribIndices,
egdaniel89af44a2014-09-26 06:15:04 -070036 drawState.getFixedFunctionVertexAttribIndices(),
37 sizeof(fFixedFunctionVertexAttribIndices));
egdaniel3658f382014-09-15 07:01:59 -070038
egdaniel170f90b2014-09-16 12:54:40 -070039
egdaniel3658f382014-09-15 07:01:59 -070040 fInputColorIsUsed = true;
41 fInputCoverageIsUsed = true;
42
43 if (drawState.hasGeometryProcessor()) {
joshualittb0a8a372014-09-23 09:50:21 -070044 fGeometryProcessor.reset(SkNEW_ARGS(GrGeometryStage, (*drawState.getGeometryProcessor())));
egdaniel3658f382014-09-15 07:01:59 -070045 } else {
46 fGeometryProcessor.reset(NULL);
47 }
48
49 this->copyEffectiveColorStages(drawState);
50 this->copyEffectiveCoverageStages(drawState);
egdaniel170f90b2014-09-16 12:54:40 -070051 this->adjustFromBlendOpts();
egdaniela7dc0a82014-09-17 08:25:05 -070052 this->getStageStats();
egdanielc0648242014-09-22 13:17:02 -070053 this->setOutputStateInfo(caps);
egdaniel3658f382014-09-15 07:01:59 -070054};
55
egdanielc0648242014-09-22 13:17:02 -070056void GrOptDrawState::setOutputStateInfo(const GrDrawTargetCaps& caps) {
57 // Set this default and then possibly change our mind if there is coverage.
58 fPrimaryOutputType = kModulate_PrimaryOutputType;
59 fSecondaryOutputType = kNone_SecondaryOutputType;
60
61 // If we do have coverage determine whether it matters.
62 bool separateCoverageFromColor = this->hasGeometryProcessor();
63 if (!this->isCoverageDrawing() &&
64 (this->numCoverageStages() > 0 ||
65 this->hasGeometryProcessor() ||
66 this->hasCoverageVertexAttribute())) {
67
68 if (caps.dualSourceBlendingSupport()) {
69 if (kZero_GrBlendCoeff == fDstBlend) {
70 // write the coverage value to second color
71 fSecondaryOutputType = kCoverage_SecondaryOutputType;
72 separateCoverageFromColor = true;
73 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
74 } else if (kSA_GrBlendCoeff == fDstBlend) {
75 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
76 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
77 separateCoverageFromColor = true;
78 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
79 } else if (kSC_GrBlendCoeff == fDstBlend) {
80 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
81 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
82 separateCoverageFromColor = true;
83 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
84 }
85 } else if (fReadsDst &&
86 kOne_GrBlendCoeff == fSrcBlend &&
87 kZero_GrBlendCoeff == fDstBlend) {
88 fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
89 separateCoverageFromColor = true;
90 }
91 }
92
93 // TODO: Once we have flag to know if we only multiply on stages, only push coverage into color
94 // stages if everything is multipy
95 if (!separateCoverageFromColor) {
96 for (int s = 0; s < this->numCoverageStages(); ++s) {
97 fColorStages.push_back(this->getCoverageStage(s));
98 }
99 fCoverageStages.reset();
100 }
101}
102
egdaniel170f90b2014-09-16 12:54:40 -0700103void GrOptDrawState::adjustFromBlendOpts() {
104
105 switch (fBlendOptFlags) {
106 case kNone_BlendOpt:
107 case kSkipDraw_BlendOptFlag:
108 break;
109 case kCoverageAsAlpha_BlendOptFlag:
110 fFlagBits |= kCoverageDrawing_StateBit;
111 break;
112 case kEmitCoverage_BlendOptFlag:
113 fColor = 0xffffffff;
114 fInputColorIsUsed = true;
115 fColorStages.reset();
116 this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding);
117 break;
118 case kEmitTransBlack_BlendOptFlag:
119 fColor = 0;
120 fCoverage = 0xff;
121 fInputColorIsUsed = true;
122 fInputCoverageIsUsed = true;
123 fColorStages.reset();
124 fCoverageStages.reset();
125 this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding |
126 0x1 << kCoverage_GrVertexAttribBinding);
127 break;
128 default:
129 SkFAIL("Unknown BlendOptFlag");
130
131 }
132}
133
egdaniel3658f382014-09-15 07:01:59 -0700134void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag) {
135 int numToRemove = 0;
136 uint8_t maskCheck = 0x1;
137 // Count the number of vertex attributes that we will actually remove
138 for (int i = 0; i < kGrFixedFunctionVertexAttribBindingCnt; ++i) {
139 if ((maskCheck & removeVAFlag) && -1 != fFixedFunctionVertexAttribIndices[i]) {
140 ++numToRemove;
141 }
142 maskCheck <<= 1;
143 }
egdaniel170f90b2014-09-16 12:54:40 -0700144
egdaniel3658f382014-09-15 07:01:59 -0700145 fOptVA.reset(fVACount - numToRemove);
146
147 GrVertexAttrib* dst = fOptVA.get();
148 const GrVertexAttrib* src = fVAPtr;
149
150 for (int i = 0, newIdx = 0; i < fVACount; ++i, ++src) {
151 const GrVertexAttrib& currAttrib = *src;
152 if (currAttrib.fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
153 uint8_t maskCheck = 0x1 << currAttrib.fBinding;
154 if (maskCheck & removeVAFlag) {
155 SkASSERT(-1 != fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
156 fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
157 continue;
158 }
egdaniel170f90b2014-09-16 12:54:40 -0700159 fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
egdaniel3658f382014-09-15 07:01:59 -0700160 }
161 memcpy(dst, src, sizeof(GrVertexAttrib));
egdaniel3658f382014-09-15 07:01:59 -0700162 ++newIdx;
163 ++dst;
164 }
165 fVACount -= numToRemove;
166 fVAPtr = fOptVA.get();
167}
168
169void GrOptDrawState::copyEffectiveColorStages(const GrDrawState& ds) {
170 int firstColorStage = 0;
171
172 // Set up color and flags for ConstantColorComponent checks
173 GrColor color;
174 uint32_t validComponentFlags;
175 if (!this->hasColorVertexAttribute()) {
176 color = ds.getColor();
177 validComponentFlags = kRGBA_GrColorComponentFlags;
178 } else {
179 if (ds.vertexColorsAreOpaque()) {
180 color = 0xFF << GrColor_SHIFT_A;
181 validComponentFlags = kA_GrColorComponentFlag;
182 } else {
183 validComponentFlags = 0;
184 color = 0; // not strictly necessary but we get false alarms from tools about uninit.
185 }
186 }
187
188 for (int i = 0; i < ds.numColorStages(); ++i) {
joshualittb0a8a372014-09-23 09:50:21 -0700189 const GrFragmentProcessor* fp = ds.getColorStage(i).getFragmentProcessor();
190 if (!fp->willUseInputColor()) {
egdaniel3658f382014-09-15 07:01:59 -0700191 firstColorStage = i;
192 fInputColorIsUsed = false;
193 }
joshualittb0a8a372014-09-23 09:50:21 -0700194 fp->getConstantColorComponents(&color, &validComponentFlags);
egdaniel3658f382014-09-15 07:01:59 -0700195 if (kRGBA_GrColorComponentFlags == validComponentFlags) {
196 firstColorStage = i + 1;
197 fColor = color;
198 fInputColorIsUsed = true;
199 this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding);
200 }
201 }
202 if (firstColorStage < ds.numColorStages()) {
203 fColorStages.reset(&ds.getColorStage(firstColorStage),
204 ds.numColorStages() - firstColorStage);
205 } else {
206 fColorStages.reset();
207 }
208}
209
210void GrOptDrawState::copyEffectiveCoverageStages(const GrDrawState& ds) {
211 int firstCoverageStage = 0;
212
213 // We do not try to optimize out constantColor coverage effects here. It is extremely rare
214 // to have a coverage effect that returns a constant value for all four channels. Thus we
215 // save having to make extra virtual calls by not checking for it.
216
217 // Don't do any optimizations on coverage stages. It should not be the case where we do not use
218 // input coverage in an effect
219#ifdef OptCoverageStages
220 for (int i = 0; i < ds.numCoverageStages(); ++i) {
joshualittb0a8a372014-09-23 09:50:21 -0700221 const GrProcessor* processor = ds.getCoverageStage(i).getProcessor();
222 if (!processor->willUseInputColor()) {
egdaniel3658f382014-09-15 07:01:59 -0700223 firstCoverageStage = i;
224 fInputCoverageIsUsed = false;
225 }
226 }
227#endif
228 if (ds.numCoverageStages() > 0) {
229 fCoverageStages.reset(&ds.getCoverageStage(firstCoverageStage),
230 ds.numCoverageStages() - firstCoverageStage);
231 } else {
232 fCoverageStages.reset();
233 }
234}
235
joshualittb0a8a372014-09-23 09:50:21 -0700236static void get_stage_stats(const GrFragmentStage& stage, bool* readsDst, bool* readsFragPosition) {
237 if (stage.getFragmentProcessor()->willReadDstColor()) {
egdaniela7dc0a82014-09-17 08:25:05 -0700238 *readsDst = true;
239 }
joshualittb0a8a372014-09-23 09:50:21 -0700240 if (stage.getFragmentProcessor()->willReadFragmentPosition()) {
egdaniela7dc0a82014-09-17 08:25:05 -0700241 *readsFragPosition = true;
242 }
243}
joshualittb0a8a372014-09-23 09:50:21 -0700244
egdaniela7dc0a82014-09-17 08:25:05 -0700245void GrOptDrawState::getStageStats() {
246 // We will need a local coord attrib if there is one currently set on the optState and we are
247 // actually generating some effect code
248 fRequiresLocalCoordAttrib = this->hasLocalCoordAttribute() && this->numTotalStages() > 0;
249
egdaniela7dc0a82014-09-17 08:25:05 -0700250 fReadsDst = false;
251 fReadsFragPosition = false;
252
253 for (int s = 0; s < this->numColorStages(); ++s) {
joshualittb0a8a372014-09-23 09:50:21 -0700254 const GrFragmentStage& stage = this->getColorStage(s);
egdaniela7dc0a82014-09-17 08:25:05 -0700255 get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
256 }
257 for (int s = 0; s < this->numCoverageStages(); ++s) {
joshualittb0a8a372014-09-23 09:50:21 -0700258 const GrFragmentStage& stage = this->getCoverageStage(s);
egdaniela7dc0a82014-09-17 08:25:05 -0700259 get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
260 }
261 if (this->hasGeometryProcessor()) {
joshualittb0a8a372014-09-23 09:50:21 -0700262 const GrGeometryStage& stage = *this->getGeometryProcessor();
263 fReadsFragPosition = fReadsFragPosition || stage.getProcessor()->willReadFragmentPosition();
egdaniela7dc0a82014-09-17 08:25:05 -0700264 }
265}
266
egdaniel89af44a2014-09-26 06:15:04 -0700267////////////////////////////////////////////////////////////////////////////////
268
egdaniel3658f382014-09-15 07:01:59 -0700269bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
270 return this->isEqual(that);
271}
272
egdaniel89af44a2014-09-26 06:15:04 -0700273bool GrOptDrawState::isEqual(const GrOptDrawState& that) const {
274 bool usingVertexColors = this->hasColorVertexAttribute();
275 if (!usingVertexColors && this->fColor != that.fColor) {
276 return false;
277 }
278
279 if (this->getRenderTarget() != that.getRenderTarget() ||
280 this->fColorStages.count() != that.fColorStages.count() ||
281 this->fCoverageStages.count() != that.fCoverageStages.count() ||
282 !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
283 this->fSrcBlend != that.fSrcBlend ||
284 this->fDstBlend != that.fDstBlend ||
285 this->fBlendConstant != that.fBlendConstant ||
286 this->fFlagBits != that.fFlagBits ||
287 this->fVACount != that.fVACount ||
288 this->fVAStride != that.fVAStride ||
289 memcmp(this->fVAPtr, that.fVAPtr, this->fVACount * sizeof(GrVertexAttrib)) ||
290 this->fStencilSettings != that.fStencilSettings ||
291 this->fDrawFace != that.fDrawFace ||
292 this->fInputColorIsUsed != that.fInputColorIsUsed ||
293 this->fInputCoverageIsUsed != that.fInputCoverageIsUsed ||
294 this->fReadsDst != that.fReadsDst ||
295 this->fReadsFragPosition != that.fReadsFragPosition ||
296 this->fRequiresLocalCoordAttrib != that.fRequiresLocalCoordAttrib ||
297 this->fPrimaryOutputType != that.fPrimaryOutputType ||
298 this->fSecondaryOutputType != that.fSecondaryOutputType) {
299 return false;
300 }
301
302 bool usingVertexCoverage = this->hasCoverageVertexAttribute();
303 if (!usingVertexCoverage && this->fCoverage != that.fCoverage) {
304 return false;
305 }
306
307 bool explicitLocalCoords = this->hasLocalCoordAttribute();
308 if (this->hasGeometryProcessor()) {
309 if (!that.hasGeometryProcessor()) {
310 return false;
311 } else if (!GrProcessorStage::AreCompatible(*this->getGeometryProcessor(),
312 *that.getGeometryProcessor(),
313 explicitLocalCoords)) {
314 return false;
315 }
316 } else if (that.hasGeometryProcessor()) {
317 return false;
318 }
319
320 for (int i = 0; i < this->numColorStages(); i++) {
321 if (!GrProcessorStage::AreCompatible(this->getColorStage(i), that.getColorStage(i),
322 explicitLocalCoords)) {
323 return false;
324 }
325 }
326 for (int i = 0; i < this->numCoverageStages(); i++) {
327 if (!GrProcessorStage::AreCompatible(this->getCoverageStage(i), that.getCoverageStage(i),
328 explicitLocalCoords)) {
329 return false;
330 }
331 }
332
333 SkASSERT(0 == memcmp(this->fFixedFunctionVertexAttribIndices,
334 that.fFixedFunctionVertexAttribIndices,
335 sizeof(this->fFixedFunctionVertexAttribIndices)));
336
337 return true;
338}
339