blob: 802713e21bdc10a1960ededb548aca707eb1f57c [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"
egdaniel3658f382014-09-15 07:01:59 -070012
egdaniel170f90b2014-09-16 12:54:40 -070013GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
14 BlendOptFlags blendOptFlags,
15 GrBlendCoeff optSrcCoeff,
egdanielc0648242014-09-22 13:17:02 -070016 GrBlendCoeff optDstCoeff,
egdaniel89af44a2014-09-26 06:15:04 -070017 const GrDrawTargetCaps& caps) {
18 fRenderTarget.set(SkSafeRef(drawState.getRenderTarget()),
19 GrIORef::kWrite_IOType);
egdaniel3658f382014-09-15 07:01:59 -070020 fColor = drawState.getColor();
21 fCoverage = drawState.getCoverage();
22 fViewMatrix = drawState.getViewMatrix();
23 fBlendConstant = drawState.getBlendConstant();
24 fFlagBits = drawState.getFlagBits();
25 fVAPtr = drawState.getVertexAttribs();
26 fVACount = drawState.getVertexAttribCount();
27 fVAStride = drawState.getVertexStride();
28 fStencilSettings = drawState.getStencil();
egdaniel89af44a2014-09-26 06:15:04 -070029 fDrawFace = (DrawFace)drawState.getDrawFace();
egdaniel170f90b2014-09-16 12:54:40 -070030 fBlendOptFlags = blendOptFlags;
31 fSrcBlend = optSrcCoeff;
32 fDstBlend = optDstCoeff;
egdaniel3658f382014-09-15 07:01:59 -070033
34 memcpy(fFixedFunctionVertexAttribIndices,
egdaniel89af44a2014-09-26 06:15:04 -070035 drawState.getFixedFunctionVertexAttribIndices(),
36 sizeof(fFixedFunctionVertexAttribIndices));
egdaniel3658f382014-09-15 07:01:59 -070037
egdaniel170f90b2014-09-16 12:54:40 -070038
egdaniel3658f382014-09-15 07:01:59 -070039 fInputColorIsUsed = true;
40 fInputCoverageIsUsed = true;
41
42 if (drawState.hasGeometryProcessor()) {
joshualittb0a8a372014-09-23 09:50:21 -070043 fGeometryProcessor.reset(SkNEW_ARGS(GrGeometryStage, (*drawState.getGeometryProcessor())));
egdaniel3658f382014-09-15 07:01:59 -070044 } else {
45 fGeometryProcessor.reset(NULL);
46 }
47
48 this->copyEffectiveColorStages(drawState);
49 this->copyEffectiveCoverageStages(drawState);
egdaniel170f90b2014-09-16 12:54:40 -070050 this->adjustFromBlendOpts();
egdaniela7dc0a82014-09-17 08:25:05 -070051 this->getStageStats();
egdanielc0648242014-09-22 13:17:02 -070052 this->setOutputStateInfo(caps);
egdaniel3658f382014-09-15 07:01:59 -070053};
54
egdanielb109ac22014-10-07 06:45:44 -070055GrOptDrawState* GrOptDrawState::Create(const GrDrawState& drawState, const GrDrawTargetCaps& caps,
56 GrGpu::DrawType drawType) {
57 if (NULL == drawState.fCachedOptState || caps.getUniqueID() != drawState.fCachedCapsID) {
58 GrBlendCoeff srcCoeff;
59 GrBlendCoeff dstCoeff;
60 BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
61 &srcCoeff,
62 &dstCoeff);
63
64 // If our blend coeffs are set to 0,1 we know we will not end up drawing unless we are
65 // stenciling. When path rendering the stencil settings are not always set on the draw state
66 // so we must check the draw type. In cases where we will skip drawing we simply return a
67 // null GrOptDrawState.
68 if (kZero_GrBlendCoeff == srcCoeff && kOne_GrBlendCoeff == dstCoeff &&
69 !drawState.getStencil().doesWrite() && GrGpu::kStencilPath_DrawType != drawType) {
70 return NULL;
71 }
72
73 drawState.fCachedOptState = SkNEW_ARGS(GrOptDrawState, (drawState, blendFlags, srcCoeff,
74 dstCoeff, caps));
75 drawState.fCachedCapsID = caps.getUniqueID();
76 } else {
77#ifdef SK_DEBUG
78 GrBlendCoeff srcCoeff;
79 GrBlendCoeff dstCoeff;
80 BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
81 &srcCoeff,
82 &dstCoeff);
83 SkASSERT(GrOptDrawState(drawState, blendFlags, srcCoeff, dstCoeff, caps) ==
84 *drawState.fCachedOptState);
85#endif
86 }
87 drawState.fCachedOptState->ref();
88 return drawState.fCachedOptState;
89}
90
egdanielc0648242014-09-22 13:17:02 -070091void GrOptDrawState::setOutputStateInfo(const GrDrawTargetCaps& caps) {
92 // Set this default and then possibly change our mind if there is coverage.
93 fPrimaryOutputType = kModulate_PrimaryOutputType;
94 fSecondaryOutputType = kNone_SecondaryOutputType;
95
96 // If we do have coverage determine whether it matters.
97 bool separateCoverageFromColor = this->hasGeometryProcessor();
98 if (!this->isCoverageDrawing() &&
99 (this->numCoverageStages() > 0 ||
100 this->hasGeometryProcessor() ||
101 this->hasCoverageVertexAttribute())) {
102
103 if (caps.dualSourceBlendingSupport()) {
104 if (kZero_GrBlendCoeff == fDstBlend) {
105 // write the coverage value to second color
106 fSecondaryOutputType = kCoverage_SecondaryOutputType;
107 separateCoverageFromColor = true;
108 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
109 } else if (kSA_GrBlendCoeff == fDstBlend) {
110 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
111 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
112 separateCoverageFromColor = true;
113 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
114 } else if (kSC_GrBlendCoeff == fDstBlend) {
115 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
116 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
117 separateCoverageFromColor = true;
118 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
119 }
120 } else if (fReadsDst &&
121 kOne_GrBlendCoeff == fSrcBlend &&
122 kZero_GrBlendCoeff == fDstBlend) {
123 fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
124 separateCoverageFromColor = true;
125 }
126 }
127
128 // TODO: Once we have flag to know if we only multiply on stages, only push coverage into color
129 // stages if everything is multipy
130 if (!separateCoverageFromColor) {
131 for (int s = 0; s < this->numCoverageStages(); ++s) {
132 fColorStages.push_back(this->getCoverageStage(s));
133 }
134 fCoverageStages.reset();
135 }
136}
137
egdaniel170f90b2014-09-16 12:54:40 -0700138void GrOptDrawState::adjustFromBlendOpts() {
139
140 switch (fBlendOptFlags) {
141 case kNone_BlendOpt:
142 case kSkipDraw_BlendOptFlag:
143 break;
144 case kCoverageAsAlpha_BlendOptFlag:
145 fFlagBits |= kCoverageDrawing_StateBit;
146 break;
147 case kEmitCoverage_BlendOptFlag:
148 fColor = 0xffffffff;
149 fInputColorIsUsed = true;
150 fColorStages.reset();
151 this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding);
152 break;
153 case kEmitTransBlack_BlendOptFlag:
154 fColor = 0;
155 fCoverage = 0xff;
156 fInputColorIsUsed = true;
157 fInputCoverageIsUsed = true;
158 fColorStages.reset();
159 fCoverageStages.reset();
160 this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding |
161 0x1 << kCoverage_GrVertexAttribBinding);
162 break;
163 default:
164 SkFAIL("Unknown BlendOptFlag");
165
166 }
167}
168
egdaniel3658f382014-09-15 07:01:59 -0700169void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag) {
170 int numToRemove = 0;
171 uint8_t maskCheck = 0x1;
172 // Count the number of vertex attributes that we will actually remove
173 for (int i = 0; i < kGrFixedFunctionVertexAttribBindingCnt; ++i) {
174 if ((maskCheck & removeVAFlag) && -1 != fFixedFunctionVertexAttribIndices[i]) {
175 ++numToRemove;
176 }
177 maskCheck <<= 1;
178 }
egdaniel170f90b2014-09-16 12:54:40 -0700179
egdaniel3658f382014-09-15 07:01:59 -0700180 fOptVA.reset(fVACount - numToRemove);
181
182 GrVertexAttrib* dst = fOptVA.get();
183 const GrVertexAttrib* src = fVAPtr;
184
185 for (int i = 0, newIdx = 0; i < fVACount; ++i, ++src) {
186 const GrVertexAttrib& currAttrib = *src;
187 if (currAttrib.fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
188 uint8_t maskCheck = 0x1 << currAttrib.fBinding;
189 if (maskCheck & removeVAFlag) {
190 SkASSERT(-1 != fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
191 fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
192 continue;
193 }
egdaniel170f90b2014-09-16 12:54:40 -0700194 fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
egdaniel3658f382014-09-15 07:01:59 -0700195 }
196 memcpy(dst, src, sizeof(GrVertexAttrib));
egdaniel3658f382014-09-15 07:01:59 -0700197 ++newIdx;
198 ++dst;
199 }
200 fVACount -= numToRemove;
201 fVAPtr = fOptVA.get();
202}
203
204void GrOptDrawState::copyEffectiveColorStages(const GrDrawState& ds) {
205 int firstColorStage = 0;
206
207 // Set up color and flags for ConstantColorComponent checks
egdaniel1a8ecdf2014-10-03 06:24:12 -0700208 GrProcessor::InvariantOutput inout;
209 inout.fIsSingleComponent = false;
egdaniel3658f382014-09-15 07:01:59 -0700210 if (!this->hasColorVertexAttribute()) {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700211 inout.fColor = ds.getColor();
212 inout.fValidFlags = kRGBA_GrColorComponentFlags;
egdaniel3658f382014-09-15 07:01:59 -0700213 } else {
214 if (ds.vertexColorsAreOpaque()) {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700215 inout.fColor = 0xFF << GrColor_SHIFT_A;
216 inout.fValidFlags = kA_GrColorComponentFlag;
egdaniel3658f382014-09-15 07:01:59 -0700217 } else {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700218 inout.fValidFlags = 0;
219 // not strictly necessary but we get false alarms from tools about uninit.
220 inout.fColor = 0;
egdaniel3658f382014-09-15 07:01:59 -0700221 }
222 }
223
224 for (int i = 0; i < ds.numColorStages(); ++i) {
joshualittb0a8a372014-09-23 09:50:21 -0700225 const GrFragmentProcessor* fp = ds.getColorStage(i).getFragmentProcessor();
226 if (!fp->willUseInputColor()) {
egdaniel3658f382014-09-15 07:01:59 -0700227 firstColorStage = i;
228 fInputColorIsUsed = false;
229 }
egdaniel1a8ecdf2014-10-03 06:24:12 -0700230 fp->computeInvariantOutput(&inout);
231 if (kRGBA_GrColorComponentFlags == inout.fValidFlags) {
egdaniel3658f382014-09-15 07:01:59 -0700232 firstColorStage = i + 1;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700233 fColor = inout.fColor;
egdaniel3658f382014-09-15 07:01:59 -0700234 fInputColorIsUsed = true;
235 this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding);
236 }
237 }
238 if (firstColorStage < ds.numColorStages()) {
239 fColorStages.reset(&ds.getColorStage(firstColorStage),
240 ds.numColorStages() - firstColorStage);
241 } else {
242 fColorStages.reset();
243 }
244}
245
246void GrOptDrawState::copyEffectiveCoverageStages(const GrDrawState& ds) {
247 int firstCoverageStage = 0;
248
249 // We do not try to optimize out constantColor coverage effects here. It is extremely rare
250 // to have a coverage effect that returns a constant value for all four channels. Thus we
251 // save having to make extra virtual calls by not checking for it.
252
253 // Don't do any optimizations on coverage stages. It should not be the case where we do not use
254 // input coverage in an effect
255#ifdef OptCoverageStages
256 for (int i = 0; i < ds.numCoverageStages(); ++i) {
joshualittb0a8a372014-09-23 09:50:21 -0700257 const GrProcessor* processor = ds.getCoverageStage(i).getProcessor();
258 if (!processor->willUseInputColor()) {
egdaniel3658f382014-09-15 07:01:59 -0700259 firstCoverageStage = i;
260 fInputCoverageIsUsed = false;
261 }
262 }
263#endif
264 if (ds.numCoverageStages() > 0) {
265 fCoverageStages.reset(&ds.getCoverageStage(firstCoverageStage),
266 ds.numCoverageStages() - firstCoverageStage);
267 } else {
268 fCoverageStages.reset();
269 }
270}
271
joshualittb0a8a372014-09-23 09:50:21 -0700272static void get_stage_stats(const GrFragmentStage& stage, bool* readsDst, bool* readsFragPosition) {
273 if (stage.getFragmentProcessor()->willReadDstColor()) {
egdaniela7dc0a82014-09-17 08:25:05 -0700274 *readsDst = true;
275 }
joshualittb0a8a372014-09-23 09:50:21 -0700276 if (stage.getFragmentProcessor()->willReadFragmentPosition()) {
egdaniela7dc0a82014-09-17 08:25:05 -0700277 *readsFragPosition = true;
278 }
279}
joshualittb0a8a372014-09-23 09:50:21 -0700280
egdaniela7dc0a82014-09-17 08:25:05 -0700281void GrOptDrawState::getStageStats() {
282 // We will need a local coord attrib if there is one currently set on the optState and we are
283 // actually generating some effect code
284 fRequiresLocalCoordAttrib = this->hasLocalCoordAttribute() && this->numTotalStages() > 0;
285
egdaniela7dc0a82014-09-17 08:25:05 -0700286 fReadsDst = false;
287 fReadsFragPosition = false;
288
289 for (int s = 0; s < this->numColorStages(); ++s) {
joshualittb0a8a372014-09-23 09:50:21 -0700290 const GrFragmentStage& stage = this->getColorStage(s);
egdaniela7dc0a82014-09-17 08:25:05 -0700291 get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
292 }
293 for (int s = 0; s < this->numCoverageStages(); ++s) {
joshualittb0a8a372014-09-23 09:50:21 -0700294 const GrFragmentStage& stage = this->getCoverageStage(s);
egdaniela7dc0a82014-09-17 08:25:05 -0700295 get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
296 }
297 if (this->hasGeometryProcessor()) {
joshualittb0a8a372014-09-23 09:50:21 -0700298 const GrGeometryStage& stage = *this->getGeometryProcessor();
299 fReadsFragPosition = fReadsFragPosition || stage.getProcessor()->willReadFragmentPosition();
egdaniela7dc0a82014-09-17 08:25:05 -0700300 }
301}
302
egdaniel89af44a2014-09-26 06:15:04 -0700303////////////////////////////////////////////////////////////////////////////////
304
egdaniel3658f382014-09-15 07:01:59 -0700305bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
306 return this->isEqual(that);
307}
308
egdaniel89af44a2014-09-26 06:15:04 -0700309bool GrOptDrawState::isEqual(const GrOptDrawState& that) const {
310 bool usingVertexColors = this->hasColorVertexAttribute();
311 if (!usingVertexColors && this->fColor != that.fColor) {
312 return false;
313 }
314
315 if (this->getRenderTarget() != that.getRenderTarget() ||
316 this->fColorStages.count() != that.fColorStages.count() ||
317 this->fCoverageStages.count() != that.fCoverageStages.count() ||
318 !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
319 this->fSrcBlend != that.fSrcBlend ||
320 this->fDstBlend != that.fDstBlend ||
321 this->fBlendConstant != that.fBlendConstant ||
322 this->fFlagBits != that.fFlagBits ||
323 this->fVACount != that.fVACount ||
324 this->fVAStride != that.fVAStride ||
325 memcmp(this->fVAPtr, that.fVAPtr, this->fVACount * sizeof(GrVertexAttrib)) ||
326 this->fStencilSettings != that.fStencilSettings ||
327 this->fDrawFace != that.fDrawFace ||
328 this->fInputColorIsUsed != that.fInputColorIsUsed ||
329 this->fInputCoverageIsUsed != that.fInputCoverageIsUsed ||
330 this->fReadsDst != that.fReadsDst ||
331 this->fReadsFragPosition != that.fReadsFragPosition ||
332 this->fRequiresLocalCoordAttrib != that.fRequiresLocalCoordAttrib ||
333 this->fPrimaryOutputType != that.fPrimaryOutputType ||
334 this->fSecondaryOutputType != that.fSecondaryOutputType) {
335 return false;
336 }
337
338 bool usingVertexCoverage = this->hasCoverageVertexAttribute();
339 if (!usingVertexCoverage && this->fCoverage != that.fCoverage) {
340 return false;
341 }
342
343 bool explicitLocalCoords = this->hasLocalCoordAttribute();
344 if (this->hasGeometryProcessor()) {
345 if (!that.hasGeometryProcessor()) {
346 return false;
347 } else if (!GrProcessorStage::AreCompatible(*this->getGeometryProcessor(),
348 *that.getGeometryProcessor(),
349 explicitLocalCoords)) {
350 return false;
351 }
352 } else if (that.hasGeometryProcessor()) {
353 return false;
354 }
355
356 for (int i = 0; i < this->numColorStages(); i++) {
357 if (!GrProcessorStage::AreCompatible(this->getColorStage(i), that.getColorStage(i),
358 explicitLocalCoords)) {
359 return false;
360 }
361 }
362 for (int i = 0; i < this->numCoverageStages(); i++) {
363 if (!GrProcessorStage::AreCompatible(this->getCoverageStage(i), that.getCoverageStage(i),
364 explicitLocalCoords)) {
365 return false;
366 }
367 }
368
369 SkASSERT(0 == memcmp(this->fFixedFunctionVertexAttribIndices,
370 that.fFixedFunctionVertexAttribIndices,
371 sizeof(this->fFixedFunctionVertexAttribIndices)));
372
373 return true;
374}
375