blob: b3d90f7310204f7958a2a29fb42050e640c11a0c [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) {
bsalomonbcf0a522014-10-08 08:40:09 -070018 fRenderTarget.set(SkSafeRef(drawState.getRenderTarget()), kWrite_GrIOType);
egdaniel3658f382014-09-15 07:01:59 -070019 fColor = drawState.getColor();
20 fCoverage = drawState.getCoverage();
21 fViewMatrix = drawState.getViewMatrix();
22 fBlendConstant = drawState.getBlendConstant();
23 fFlagBits = drawState.getFlagBits();
24 fVAPtr = drawState.getVertexAttribs();
25 fVACount = drawState.getVertexAttribCount();
26 fVAStride = drawState.getVertexStride();
27 fStencilSettings = drawState.getStencil();
egdaniel89af44a2014-09-26 06:15:04 -070028 fDrawFace = (DrawFace)drawState.getDrawFace();
egdaniel170f90b2014-09-16 12:54:40 -070029 fBlendOptFlags = blendOptFlags;
30 fSrcBlend = optSrcCoeff;
31 fDstBlend = optDstCoeff;
egdaniel3658f382014-09-15 07:01:59 -070032
33 memcpy(fFixedFunctionVertexAttribIndices,
egdaniel89af44a2014-09-26 06:15:04 -070034 drawState.getFixedFunctionVertexAttribIndices(),
35 sizeof(fFixedFunctionVertexAttribIndices));
egdaniel3658f382014-09-15 07:01:59 -070036
37 fInputColorIsUsed = true;
38 fInputCoverageIsUsed = true;
39
egdaniel9cf45bf2014-10-08 06:49:10 -070040 int firstColorStageIdx = 0;
41 int firstCoverageStageIdx = 0;
42 bool separateCoverageFromColor;
43
44 uint8_t fixedFunctionVAToRemove = 0;
45
46 this->computeEffectiveColorStages(drawState, &firstColorStageIdx, &fixedFunctionVAToRemove);
47 this->computeEffectiveCoverageStages(drawState, &firstCoverageStageIdx);
48 this->adjustFromBlendOpts(drawState, &firstColorStageIdx, &firstCoverageStageIdx,
49 &fixedFunctionVAToRemove);
50 // Should not be setting any more FFVA to be removed at this point
51 this->removeFixedFunctionVertexAttribs(fixedFunctionVAToRemove);
52 this->getStageStats(drawState, firstColorStageIdx, firstCoverageStageIdx);
53 this->setOutputStateInfo(drawState, caps, firstCoverageStageIdx, &separateCoverageFromColor);
54
55 // Copy GeometryProcesssor from DS or ODS
egdaniel3658f382014-09-15 07:01:59 -070056 if (drawState.hasGeometryProcessor()) {
joshualittb0a8a372014-09-23 09:50:21 -070057 fGeometryProcessor.reset(SkNEW_ARGS(GrGeometryStage, (*drawState.getGeometryProcessor())));
egdaniel3658f382014-09-15 07:01:59 -070058 } else {
59 fGeometryProcessor.reset(NULL);
60 }
61
egdaniel9cf45bf2014-10-08 06:49:10 -070062 // Copy Color Stages from DS to ODS
63 if (firstColorStageIdx < drawState.numColorStages()) {
egdanield9aa2182014-10-09 13:47:05 -070064 fFragmentStages.reset(&drawState.getColorStage(firstColorStageIdx),
65 drawState.numColorStages() - firstColorStageIdx);
egdaniel9cf45bf2014-10-08 06:49:10 -070066 } else {
egdanield9aa2182014-10-09 13:47:05 -070067 fFragmentStages.reset();
egdaniel9cf45bf2014-10-08 06:49:10 -070068 }
69
egdanield9aa2182014-10-09 13:47:05 -070070 fNumColorStages = fFragmentStages.count();
71
egdaniel9cf45bf2014-10-08 06:49:10 -070072 // Copy Coverage Stages from DS to ODS
egdanield9aa2182014-10-09 13:47:05 -070073 if (firstCoverageStageIdx < drawState.numCoverageStages()) {
74 fFragmentStages.push_back_n(drawState.numCoverageStages() - firstCoverageStageIdx,
75 &drawState.getCoverageStage(firstCoverageStageIdx));
76 if (!separateCoverageFromColor) {
77 fNumColorStages = fFragmentStages.count();
egdaniel9cf45bf2014-10-08 06:49:10 -070078 }
79 }
egdaniel3658f382014-09-15 07:01:59 -070080};
81
egdanielb109ac22014-10-07 06:45:44 -070082GrOptDrawState* GrOptDrawState::Create(const GrDrawState& drawState, const GrDrawTargetCaps& caps,
83 GrGpu::DrawType drawType) {
84 if (NULL == drawState.fCachedOptState || caps.getUniqueID() != drawState.fCachedCapsID) {
85 GrBlendCoeff srcCoeff;
86 GrBlendCoeff dstCoeff;
87 BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
88 &srcCoeff,
89 &dstCoeff);
90
91 // If our blend coeffs are set to 0,1 we know we will not end up drawing unless we are
92 // stenciling. When path rendering the stencil settings are not always set on the draw state
93 // so we must check the draw type. In cases where we will skip drawing we simply return a
94 // null GrOptDrawState.
95 if (kZero_GrBlendCoeff == srcCoeff && kOne_GrBlendCoeff == dstCoeff &&
96 !drawState.getStencil().doesWrite() && GrGpu::kStencilPath_DrawType != drawType) {
97 return NULL;
98 }
99
100 drawState.fCachedOptState = SkNEW_ARGS(GrOptDrawState, (drawState, blendFlags, srcCoeff,
101 dstCoeff, caps));
102 drawState.fCachedCapsID = caps.getUniqueID();
103 } else {
104#ifdef SK_DEBUG
105 GrBlendCoeff srcCoeff;
106 GrBlendCoeff dstCoeff;
107 BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
108 &srcCoeff,
109 &dstCoeff);
110 SkASSERT(GrOptDrawState(drawState, blendFlags, srcCoeff, dstCoeff, caps) ==
111 *drawState.fCachedOptState);
112#endif
113 }
114 drawState.fCachedOptState->ref();
115 return drawState.fCachedOptState;
116}
117
egdaniel9cf45bf2014-10-08 06:49:10 -0700118void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds,
119 const GrDrawTargetCaps& caps,
120 int firstCoverageStageIdx,
121 bool* separateCoverageFromColor) {
egdanielc0648242014-09-22 13:17:02 -0700122 // Set this default and then possibly change our mind if there is coverage.
123 fPrimaryOutputType = kModulate_PrimaryOutputType;
124 fSecondaryOutputType = kNone_SecondaryOutputType;
125
126 // If we do have coverage determine whether it matters.
egdaniel9cf45bf2014-10-08 06:49:10 -0700127 *separateCoverageFromColor = this->hasGeometryProcessor();
egdanielc0648242014-09-22 13:17:02 -0700128 if (!this->isCoverageDrawing() &&
egdaniel9cf45bf2014-10-08 06:49:10 -0700129 (ds.numCoverageStages() - firstCoverageStageIdx > 0 ||
130 ds.hasGeometryProcessor() ||
egdanielc0648242014-09-22 13:17:02 -0700131 this->hasCoverageVertexAttribute())) {
132
133 if (caps.dualSourceBlendingSupport()) {
134 if (kZero_GrBlendCoeff == fDstBlend) {
135 // write the coverage value to second color
136 fSecondaryOutputType = kCoverage_SecondaryOutputType;
egdaniel9cf45bf2014-10-08 06:49:10 -0700137 *separateCoverageFromColor = true;
egdanielc0648242014-09-22 13:17:02 -0700138 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
139 } else if (kSA_GrBlendCoeff == fDstBlend) {
140 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
141 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
egdaniel9cf45bf2014-10-08 06:49:10 -0700142 *separateCoverageFromColor = true;
egdanielc0648242014-09-22 13:17:02 -0700143 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
144 } else if (kSC_GrBlendCoeff == fDstBlend) {
145 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
146 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
egdaniel9cf45bf2014-10-08 06:49:10 -0700147 *separateCoverageFromColor = true;
egdanielc0648242014-09-22 13:17:02 -0700148 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
149 }
150 } else if (fReadsDst &&
151 kOne_GrBlendCoeff == fSrcBlend &&
152 kZero_GrBlendCoeff == fDstBlend) {
153 fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
egdaniel9cf45bf2014-10-08 06:49:10 -0700154 *separateCoverageFromColor = true;
egdanielc0648242014-09-22 13:17:02 -0700155 }
156 }
egdanielc0648242014-09-22 13:17:02 -0700157}
158
egdaniel9cf45bf2014-10-08 06:49:10 -0700159void GrOptDrawState::adjustFromBlendOpts(const GrDrawState& ds,
160 int* firstColorStageIdx,
161 int* firstCoverageStageIdx,
162 uint8_t* fixedFunctionVAToRemove) {
egdaniel170f90b2014-09-16 12:54:40 -0700163 switch (fBlendOptFlags) {
164 case kNone_BlendOpt:
165 case kSkipDraw_BlendOptFlag:
166 break;
167 case kCoverageAsAlpha_BlendOptFlag:
168 fFlagBits |= kCoverageDrawing_StateBit;
169 break;
170 case kEmitCoverage_BlendOptFlag:
171 fColor = 0xffffffff;
172 fInputColorIsUsed = true;
egdaniel9cf45bf2014-10-08 06:49:10 -0700173 *firstColorStageIdx = ds.numColorStages();
174 *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
egdaniel170f90b2014-09-16 12:54:40 -0700175 break;
176 case kEmitTransBlack_BlendOptFlag:
177 fColor = 0;
178 fCoverage = 0xff;
179 fInputColorIsUsed = true;
180 fInputCoverageIsUsed = true;
egdaniel9cf45bf2014-10-08 06:49:10 -0700181 *firstColorStageIdx = ds.numColorStages();
182 *firstCoverageStageIdx = ds.numCoverageStages();
183 *fixedFunctionVAToRemove |= (0x1 << kColor_GrVertexAttribBinding |
184 0x1 << kCoverage_GrVertexAttribBinding);
egdaniel170f90b2014-09-16 12:54:40 -0700185 break;
186 default:
187 SkFAIL("Unknown BlendOptFlag");
egdaniel170f90b2014-09-16 12:54:40 -0700188 }
189}
190
egdaniel3658f382014-09-15 07:01:59 -0700191void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag) {
192 int numToRemove = 0;
193 uint8_t maskCheck = 0x1;
194 // Count the number of vertex attributes that we will actually remove
195 for (int i = 0; i < kGrFixedFunctionVertexAttribBindingCnt; ++i) {
196 if ((maskCheck & removeVAFlag) && -1 != fFixedFunctionVertexAttribIndices[i]) {
197 ++numToRemove;
198 }
199 maskCheck <<= 1;
200 }
egdaniel170f90b2014-09-16 12:54:40 -0700201
egdaniel3658f382014-09-15 07:01:59 -0700202 fOptVA.reset(fVACount - numToRemove);
203
204 GrVertexAttrib* dst = fOptVA.get();
205 const GrVertexAttrib* src = fVAPtr;
206
207 for (int i = 0, newIdx = 0; i < fVACount; ++i, ++src) {
208 const GrVertexAttrib& currAttrib = *src;
209 if (currAttrib.fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
210 uint8_t maskCheck = 0x1 << currAttrib.fBinding;
211 if (maskCheck & removeVAFlag) {
212 SkASSERT(-1 != fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
213 fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
214 continue;
215 }
egdaniel170f90b2014-09-16 12:54:40 -0700216 fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
egdaniel3658f382014-09-15 07:01:59 -0700217 }
218 memcpy(dst, src, sizeof(GrVertexAttrib));
egdaniel3658f382014-09-15 07:01:59 -0700219 ++newIdx;
220 ++dst;
221 }
222 fVACount -= numToRemove;
223 fVAPtr = fOptVA.get();
224}
225
egdaniel9cf45bf2014-10-08 06:49:10 -0700226void GrOptDrawState::computeEffectiveColorStages(const GrDrawState& ds, int* firstColorStageIdx,
227 uint8_t* fixedFunctionVAToRemove) {
egdaniel3658f382014-09-15 07:01:59 -0700228 // Set up color and flags for ConstantColorComponent checks
egdaniel1a8ecdf2014-10-03 06:24:12 -0700229 GrProcessor::InvariantOutput inout;
230 inout.fIsSingleComponent = false;
egdaniel3658f382014-09-15 07:01:59 -0700231 if (!this->hasColorVertexAttribute()) {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700232 inout.fColor = ds.getColor();
233 inout.fValidFlags = kRGBA_GrColorComponentFlags;
egdaniel3658f382014-09-15 07:01:59 -0700234 } else {
235 if (ds.vertexColorsAreOpaque()) {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700236 inout.fColor = 0xFF << GrColor_SHIFT_A;
237 inout.fValidFlags = kA_GrColorComponentFlag;
egdaniel3658f382014-09-15 07:01:59 -0700238 } else {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700239 inout.fValidFlags = 0;
240 // not strictly necessary but we get false alarms from tools about uninit.
241 inout.fColor = 0;
egdaniel3658f382014-09-15 07:01:59 -0700242 }
243 }
244
245 for (int i = 0; i < ds.numColorStages(); ++i) {
joshualitt47bb3822014-10-07 16:43:25 -0700246 const GrFragmentProcessor* fp = ds.getColorStage(i).getProcessor();
joshualittb0a8a372014-09-23 09:50:21 -0700247 if (!fp->willUseInputColor()) {
egdaniel9cf45bf2014-10-08 06:49:10 -0700248 *firstColorStageIdx = i;
egdaniel3658f382014-09-15 07:01:59 -0700249 fInputColorIsUsed = false;
250 }
egdaniel1a8ecdf2014-10-03 06:24:12 -0700251 fp->computeInvariantOutput(&inout);
252 if (kRGBA_GrColorComponentFlags == inout.fValidFlags) {
egdaniel9cf45bf2014-10-08 06:49:10 -0700253 *firstColorStageIdx = i + 1;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700254 fColor = inout.fColor;
egdaniel3658f382014-09-15 07:01:59 -0700255 fInputColorIsUsed = true;
egdaniel9cf45bf2014-10-08 06:49:10 -0700256 *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
egdaniel3658f382014-09-15 07:01:59 -0700257 }
258 }
egdaniel3658f382014-09-15 07:01:59 -0700259}
260
egdaniel9cf45bf2014-10-08 06:49:10 -0700261void GrOptDrawState::computeEffectiveCoverageStages(const GrDrawState& ds,
262 int* firstCoverageStageIdx) {
egdaniel3658f382014-09-15 07:01:59 -0700263 // We do not try to optimize out constantColor coverage effects here. It is extremely rare
264 // to have a coverage effect that returns a constant value for all four channels. Thus we
265 // save having to make extra virtual calls by not checking for it.
266
267 // Don't do any optimizations on coverage stages. It should not be the case where we do not use
268 // input coverage in an effect
269#ifdef OptCoverageStages
270 for (int i = 0; i < ds.numCoverageStages(); ++i) {
joshualittb0a8a372014-09-23 09:50:21 -0700271 const GrProcessor* processor = ds.getCoverageStage(i).getProcessor();
272 if (!processor->willUseInputColor()) {
egdaniel9cf45bf2014-10-08 06:49:10 -0700273 *firstCoverageStageIdx = i;
egdaniel3658f382014-09-15 07:01:59 -0700274 fInputCoverageIsUsed = false;
275 }
276 }
277#endif
egdaniel3658f382014-09-15 07:01:59 -0700278}
279
joshualittb0a8a372014-09-23 09:50:21 -0700280static void get_stage_stats(const GrFragmentStage& stage, bool* readsDst, bool* readsFragPosition) {
joshualitt47bb3822014-10-07 16:43:25 -0700281 if (stage.getProcessor()->willReadDstColor()) {
egdaniela7dc0a82014-09-17 08:25:05 -0700282 *readsDst = true;
283 }
joshualitt47bb3822014-10-07 16:43:25 -0700284 if (stage.getProcessor()->willReadFragmentPosition()) {
egdaniela7dc0a82014-09-17 08:25:05 -0700285 *readsFragPosition = true;
286 }
287}
joshualittb0a8a372014-09-23 09:50:21 -0700288
egdaniel9cf45bf2014-10-08 06:49:10 -0700289void GrOptDrawState::getStageStats(const GrDrawState& ds, int firstColorStageIdx,
290 int firstCoverageStageIdx) {
egdaniela7dc0a82014-09-17 08:25:05 -0700291 // We will need a local coord attrib if there is one currently set on the optState and we are
292 // actually generating some effect code
egdaniel9cf45bf2014-10-08 06:49:10 -0700293 fRequiresLocalCoordAttrib = this->hasLocalCoordAttribute() &&
294 ds.numTotalStages() - firstColorStageIdx - firstCoverageStageIdx > 0;
egdaniela7dc0a82014-09-17 08:25:05 -0700295
egdaniela7dc0a82014-09-17 08:25:05 -0700296 fReadsDst = false;
297 fReadsFragPosition = false;
298
egdaniel9cf45bf2014-10-08 06:49:10 -0700299 for (int s = firstColorStageIdx; s < ds.numColorStages(); ++s) {
300 const GrFragmentStage& stage = ds.getColorStage(s);
egdaniela7dc0a82014-09-17 08:25:05 -0700301 get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
302 }
egdaniel9cf45bf2014-10-08 06:49:10 -0700303 for (int s = firstCoverageStageIdx; s < ds.numCoverageStages(); ++s) {
304 const GrFragmentStage& stage = ds.getCoverageStage(s);
egdaniela7dc0a82014-09-17 08:25:05 -0700305 get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
306 }
egdaniel9cf45bf2014-10-08 06:49:10 -0700307 if (ds.hasGeometryProcessor()) {
308 const GrGeometryStage& stage = *ds.getGeometryProcessor();
joshualittb0a8a372014-09-23 09:50:21 -0700309 fReadsFragPosition = fReadsFragPosition || stage.getProcessor()->willReadFragmentPosition();
egdaniela7dc0a82014-09-17 08:25:05 -0700310 }
311}
312
egdaniel89af44a2014-09-26 06:15:04 -0700313////////////////////////////////////////////////////////////////////////////////
314
egdaniel3658f382014-09-15 07:01:59 -0700315bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
316 return this->isEqual(that);
317}
318
egdaniel89af44a2014-09-26 06:15:04 -0700319bool GrOptDrawState::isEqual(const GrOptDrawState& that) const {
320 bool usingVertexColors = this->hasColorVertexAttribute();
321 if (!usingVertexColors && this->fColor != that.fColor) {
322 return false;
323 }
324
325 if (this->getRenderTarget() != that.getRenderTarget() ||
egdanield9aa2182014-10-09 13:47:05 -0700326 this->fFragmentStages.count() != that.fFragmentStages.count() ||
327 this->fNumColorStages != that.fNumColorStages ||
egdaniel89af44a2014-09-26 06:15:04 -0700328 !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
329 this->fSrcBlend != that.fSrcBlend ||
330 this->fDstBlend != that.fDstBlend ||
331 this->fBlendConstant != that.fBlendConstant ||
332 this->fFlagBits != that.fFlagBits ||
333 this->fVACount != that.fVACount ||
334 this->fVAStride != that.fVAStride ||
335 memcmp(this->fVAPtr, that.fVAPtr, this->fVACount * sizeof(GrVertexAttrib)) ||
336 this->fStencilSettings != that.fStencilSettings ||
337 this->fDrawFace != that.fDrawFace ||
338 this->fInputColorIsUsed != that.fInputColorIsUsed ||
339 this->fInputCoverageIsUsed != that.fInputCoverageIsUsed ||
340 this->fReadsDst != that.fReadsDst ||
341 this->fReadsFragPosition != that.fReadsFragPosition ||
342 this->fRequiresLocalCoordAttrib != that.fRequiresLocalCoordAttrib ||
343 this->fPrimaryOutputType != that.fPrimaryOutputType ||
344 this->fSecondaryOutputType != that.fSecondaryOutputType) {
345 return false;
346 }
347
348 bool usingVertexCoverage = this->hasCoverageVertexAttribute();
349 if (!usingVertexCoverage && this->fCoverage != that.fCoverage) {
350 return false;
351 }
352
353 bool explicitLocalCoords = this->hasLocalCoordAttribute();
354 if (this->hasGeometryProcessor()) {
355 if (!that.hasGeometryProcessor()) {
356 return false;
357 } else if (!GrProcessorStage::AreCompatible(*this->getGeometryProcessor(),
358 *that.getGeometryProcessor(),
359 explicitLocalCoords)) {
360 return false;
361 }
362 } else if (that.hasGeometryProcessor()) {
363 return false;
364 }
365
egdanield9aa2182014-10-09 13:47:05 -0700366 for (int i = 0; i < this->numFragmentStages(); i++) {
367 if (!GrProcessorStage::AreCompatible(this->getFragmentStage(i), that.getFragmentStage(i),
egdaniel89af44a2014-09-26 06:15:04 -0700368 explicitLocalCoords)) {
369 return false;
370 }
371 }
372
373 SkASSERT(0 == memcmp(this->fFixedFunctionVertexAttribIndices,
374 that.fFixedFunctionVertexAttribIndices,
375 sizeof(this->fFixedFunctionVertexAttribIndices)));
376
377 return true;
378}
379