blob: 4a6cd142eb08ee49756564eb294f5bb7f9af64bb [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
38 fInputColorIsUsed = true;
39 fInputCoverageIsUsed = true;
40
egdaniel9cf45bf2014-10-08 06:49:10 -070041 int firstColorStageIdx = 0;
42 int firstCoverageStageIdx = 0;
43 bool separateCoverageFromColor;
44
45 uint8_t fixedFunctionVAToRemove = 0;
46
47 this->computeEffectiveColorStages(drawState, &firstColorStageIdx, &fixedFunctionVAToRemove);
48 this->computeEffectiveCoverageStages(drawState, &firstCoverageStageIdx);
49 this->adjustFromBlendOpts(drawState, &firstColorStageIdx, &firstCoverageStageIdx,
50 &fixedFunctionVAToRemove);
51 // Should not be setting any more FFVA to be removed at this point
52 this->removeFixedFunctionVertexAttribs(fixedFunctionVAToRemove);
53 this->getStageStats(drawState, firstColorStageIdx, firstCoverageStageIdx);
54 this->setOutputStateInfo(drawState, caps, firstCoverageStageIdx, &separateCoverageFromColor);
55
56 // Copy GeometryProcesssor from DS or ODS
egdaniel3658f382014-09-15 07:01:59 -070057 if (drawState.hasGeometryProcessor()) {
joshualittb0a8a372014-09-23 09:50:21 -070058 fGeometryProcessor.reset(SkNEW_ARGS(GrGeometryStage, (*drawState.getGeometryProcessor())));
egdaniel3658f382014-09-15 07:01:59 -070059 } else {
60 fGeometryProcessor.reset(NULL);
61 }
62
egdaniel9cf45bf2014-10-08 06:49:10 -070063 // Copy Color Stages from DS to ODS
64 if (firstColorStageIdx < drawState.numColorStages()) {
65 fColorStages.reset(&drawState.getColorStage(firstColorStageIdx),
66 drawState.numColorStages() - firstColorStageIdx);
67 } else {
68 fColorStages.reset();
69 }
70
71 // Copy Coverage Stages from DS to ODS
72 if (drawState.numCoverageStages() > 0 && separateCoverageFromColor) {
73 fCoverageStages.reset(&drawState.getCoverageStage(firstCoverageStageIdx),
74 drawState.numCoverageStages() - firstCoverageStageIdx);
75 } else {
76 fCoverageStages.reset();
77 if (drawState.numCoverageStages() > 0) {
78 // TODO: Once we have flag to know if we only multiply on stages, only push coverage
79 // into color stages if everything is multiply
80 fColorStages.push_back_n(drawState.numCoverageStages() - firstCoverageStageIdx,
81 &drawState.getCoverageStage(firstCoverageStageIdx));
82 }
83 }
egdaniel3658f382014-09-15 07:01:59 -070084};
85
egdanielb109ac22014-10-07 06:45:44 -070086GrOptDrawState* GrOptDrawState::Create(const GrDrawState& drawState, const GrDrawTargetCaps& caps,
87 GrGpu::DrawType drawType) {
88 if (NULL == drawState.fCachedOptState || caps.getUniqueID() != drawState.fCachedCapsID) {
89 GrBlendCoeff srcCoeff;
90 GrBlendCoeff dstCoeff;
91 BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
92 &srcCoeff,
93 &dstCoeff);
94
95 // If our blend coeffs are set to 0,1 we know we will not end up drawing unless we are
96 // stenciling. When path rendering the stencil settings are not always set on the draw state
97 // so we must check the draw type. In cases where we will skip drawing we simply return a
98 // null GrOptDrawState.
99 if (kZero_GrBlendCoeff == srcCoeff && kOne_GrBlendCoeff == dstCoeff &&
100 !drawState.getStencil().doesWrite() && GrGpu::kStencilPath_DrawType != drawType) {
101 return NULL;
102 }
103
104 drawState.fCachedOptState = SkNEW_ARGS(GrOptDrawState, (drawState, blendFlags, srcCoeff,
105 dstCoeff, caps));
106 drawState.fCachedCapsID = caps.getUniqueID();
107 } else {
108#ifdef SK_DEBUG
109 GrBlendCoeff srcCoeff;
110 GrBlendCoeff dstCoeff;
111 BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
112 &srcCoeff,
113 &dstCoeff);
114 SkASSERT(GrOptDrawState(drawState, blendFlags, srcCoeff, dstCoeff, caps) ==
115 *drawState.fCachedOptState);
116#endif
117 }
118 drawState.fCachedOptState->ref();
119 return drawState.fCachedOptState;
120}
121
egdaniel9cf45bf2014-10-08 06:49:10 -0700122void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds,
123 const GrDrawTargetCaps& caps,
124 int firstCoverageStageIdx,
125 bool* separateCoverageFromColor) {
egdanielc0648242014-09-22 13:17:02 -0700126 // Set this default and then possibly change our mind if there is coverage.
127 fPrimaryOutputType = kModulate_PrimaryOutputType;
128 fSecondaryOutputType = kNone_SecondaryOutputType;
129
130 // If we do have coverage determine whether it matters.
egdaniel9cf45bf2014-10-08 06:49:10 -0700131 *separateCoverageFromColor = this->hasGeometryProcessor();
egdanielc0648242014-09-22 13:17:02 -0700132 if (!this->isCoverageDrawing() &&
egdaniel9cf45bf2014-10-08 06:49:10 -0700133 (ds.numCoverageStages() - firstCoverageStageIdx > 0 ||
134 ds.hasGeometryProcessor() ||
egdanielc0648242014-09-22 13:17:02 -0700135 this->hasCoverageVertexAttribute())) {
136
137 if (caps.dualSourceBlendingSupport()) {
138 if (kZero_GrBlendCoeff == fDstBlend) {
139 // write the coverage value to second color
140 fSecondaryOutputType = kCoverage_SecondaryOutputType;
egdaniel9cf45bf2014-10-08 06:49:10 -0700141 *separateCoverageFromColor = true;
egdanielc0648242014-09-22 13:17:02 -0700142 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
143 } else if (kSA_GrBlendCoeff == fDstBlend) {
144 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
145 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
egdaniel9cf45bf2014-10-08 06:49:10 -0700146 *separateCoverageFromColor = true;
egdanielc0648242014-09-22 13:17:02 -0700147 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
148 } else if (kSC_GrBlendCoeff == fDstBlend) {
149 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
150 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
egdaniel9cf45bf2014-10-08 06:49:10 -0700151 *separateCoverageFromColor = true;
egdanielc0648242014-09-22 13:17:02 -0700152 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
153 }
154 } else if (fReadsDst &&
155 kOne_GrBlendCoeff == fSrcBlend &&
156 kZero_GrBlendCoeff == fDstBlend) {
157 fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
egdaniel9cf45bf2014-10-08 06:49:10 -0700158 *separateCoverageFromColor = true;
egdanielc0648242014-09-22 13:17:02 -0700159 }
160 }
egdanielc0648242014-09-22 13:17:02 -0700161}
162
egdaniel9cf45bf2014-10-08 06:49:10 -0700163void GrOptDrawState::adjustFromBlendOpts(const GrDrawState& ds,
164 int* firstColorStageIdx,
165 int* firstCoverageStageIdx,
166 uint8_t* fixedFunctionVAToRemove) {
egdaniel170f90b2014-09-16 12:54:40 -0700167 switch (fBlendOptFlags) {
168 case kNone_BlendOpt:
169 case kSkipDraw_BlendOptFlag:
170 break;
171 case kCoverageAsAlpha_BlendOptFlag:
172 fFlagBits |= kCoverageDrawing_StateBit;
173 break;
174 case kEmitCoverage_BlendOptFlag:
175 fColor = 0xffffffff;
176 fInputColorIsUsed = true;
egdaniel9cf45bf2014-10-08 06:49:10 -0700177 *firstColorStageIdx = ds.numColorStages();
178 *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
egdaniel170f90b2014-09-16 12:54:40 -0700179 break;
180 case kEmitTransBlack_BlendOptFlag:
181 fColor = 0;
182 fCoverage = 0xff;
183 fInputColorIsUsed = true;
184 fInputCoverageIsUsed = true;
egdaniel9cf45bf2014-10-08 06:49:10 -0700185 *firstColorStageIdx = ds.numColorStages();
186 *firstCoverageStageIdx = ds.numCoverageStages();
187 *fixedFunctionVAToRemove |= (0x1 << kColor_GrVertexAttribBinding |
188 0x1 << kCoverage_GrVertexAttribBinding);
egdaniel170f90b2014-09-16 12:54:40 -0700189 break;
190 default:
191 SkFAIL("Unknown BlendOptFlag");
egdaniel170f90b2014-09-16 12:54:40 -0700192 }
193}
194
egdaniel3658f382014-09-15 07:01:59 -0700195void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag) {
196 int numToRemove = 0;
197 uint8_t maskCheck = 0x1;
198 // Count the number of vertex attributes that we will actually remove
199 for (int i = 0; i < kGrFixedFunctionVertexAttribBindingCnt; ++i) {
200 if ((maskCheck & removeVAFlag) && -1 != fFixedFunctionVertexAttribIndices[i]) {
201 ++numToRemove;
202 }
203 maskCheck <<= 1;
204 }
egdaniel170f90b2014-09-16 12:54:40 -0700205
egdaniel3658f382014-09-15 07:01:59 -0700206 fOptVA.reset(fVACount - numToRemove);
207
208 GrVertexAttrib* dst = fOptVA.get();
209 const GrVertexAttrib* src = fVAPtr;
210
211 for (int i = 0, newIdx = 0; i < fVACount; ++i, ++src) {
212 const GrVertexAttrib& currAttrib = *src;
213 if (currAttrib.fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
214 uint8_t maskCheck = 0x1 << currAttrib.fBinding;
215 if (maskCheck & removeVAFlag) {
216 SkASSERT(-1 != fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
217 fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
218 continue;
219 }
egdaniel170f90b2014-09-16 12:54:40 -0700220 fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
egdaniel3658f382014-09-15 07:01:59 -0700221 }
222 memcpy(dst, src, sizeof(GrVertexAttrib));
egdaniel3658f382014-09-15 07:01:59 -0700223 ++newIdx;
224 ++dst;
225 }
226 fVACount -= numToRemove;
227 fVAPtr = fOptVA.get();
228}
229
egdaniel9cf45bf2014-10-08 06:49:10 -0700230void GrOptDrawState::computeEffectiveColorStages(const GrDrawState& ds, int* firstColorStageIdx,
231 uint8_t* fixedFunctionVAToRemove) {
egdaniel3658f382014-09-15 07:01:59 -0700232 // Set up color and flags for ConstantColorComponent checks
egdaniel1a8ecdf2014-10-03 06:24:12 -0700233 GrProcessor::InvariantOutput inout;
234 inout.fIsSingleComponent = false;
egdaniel3658f382014-09-15 07:01:59 -0700235 if (!this->hasColorVertexAttribute()) {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700236 inout.fColor = ds.getColor();
237 inout.fValidFlags = kRGBA_GrColorComponentFlags;
egdaniel3658f382014-09-15 07:01:59 -0700238 } else {
239 if (ds.vertexColorsAreOpaque()) {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700240 inout.fColor = 0xFF << GrColor_SHIFT_A;
241 inout.fValidFlags = kA_GrColorComponentFlag;
egdaniel3658f382014-09-15 07:01:59 -0700242 } else {
egdaniel1a8ecdf2014-10-03 06:24:12 -0700243 inout.fValidFlags = 0;
244 // not strictly necessary but we get false alarms from tools about uninit.
245 inout.fColor = 0;
egdaniel3658f382014-09-15 07:01:59 -0700246 }
247 }
248
249 for (int i = 0; i < ds.numColorStages(); ++i) {
joshualitt47bb3822014-10-07 16:43:25 -0700250 const GrFragmentProcessor* fp = ds.getColorStage(i).getProcessor();
joshualittb0a8a372014-09-23 09:50:21 -0700251 if (!fp->willUseInputColor()) {
egdaniel9cf45bf2014-10-08 06:49:10 -0700252 *firstColorStageIdx = i;
egdaniel3658f382014-09-15 07:01:59 -0700253 fInputColorIsUsed = false;
254 }
egdaniel1a8ecdf2014-10-03 06:24:12 -0700255 fp->computeInvariantOutput(&inout);
256 if (kRGBA_GrColorComponentFlags == inout.fValidFlags) {
egdaniel9cf45bf2014-10-08 06:49:10 -0700257 *firstColorStageIdx = i + 1;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700258 fColor = inout.fColor;
egdaniel3658f382014-09-15 07:01:59 -0700259 fInputColorIsUsed = true;
egdaniel9cf45bf2014-10-08 06:49:10 -0700260 *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
egdaniel3658f382014-09-15 07:01:59 -0700261 }
262 }
egdaniel3658f382014-09-15 07:01:59 -0700263}
264
egdaniel9cf45bf2014-10-08 06:49:10 -0700265void GrOptDrawState::computeEffectiveCoverageStages(const GrDrawState& ds,
266 int* firstCoverageStageIdx) {
egdaniel3658f382014-09-15 07:01:59 -0700267 // We do not try to optimize out constantColor coverage effects here. It is extremely rare
268 // to have a coverage effect that returns a constant value for all four channels. Thus we
269 // save having to make extra virtual calls by not checking for it.
270
271 // Don't do any optimizations on coverage stages. It should not be the case where we do not use
272 // input coverage in an effect
273#ifdef OptCoverageStages
274 for (int i = 0; i < ds.numCoverageStages(); ++i) {
joshualittb0a8a372014-09-23 09:50:21 -0700275 const GrProcessor* processor = ds.getCoverageStage(i).getProcessor();
276 if (!processor->willUseInputColor()) {
egdaniel9cf45bf2014-10-08 06:49:10 -0700277 *firstCoverageStageIdx = i;
egdaniel3658f382014-09-15 07:01:59 -0700278 fInputCoverageIsUsed = false;
279 }
280 }
281#endif
egdaniel3658f382014-09-15 07:01:59 -0700282}
283
joshualittb0a8a372014-09-23 09:50:21 -0700284static void get_stage_stats(const GrFragmentStage& stage, bool* readsDst, bool* readsFragPosition) {
joshualitt47bb3822014-10-07 16:43:25 -0700285 if (stage.getProcessor()->willReadDstColor()) {
egdaniela7dc0a82014-09-17 08:25:05 -0700286 *readsDst = true;
287 }
joshualitt47bb3822014-10-07 16:43:25 -0700288 if (stage.getProcessor()->willReadFragmentPosition()) {
egdaniela7dc0a82014-09-17 08:25:05 -0700289 *readsFragPosition = true;
290 }
291}
joshualittb0a8a372014-09-23 09:50:21 -0700292
egdaniel9cf45bf2014-10-08 06:49:10 -0700293void GrOptDrawState::getStageStats(const GrDrawState& ds, int firstColorStageIdx,
294 int firstCoverageStageIdx) {
egdaniela7dc0a82014-09-17 08:25:05 -0700295 // We will need a local coord attrib if there is one currently set on the optState and we are
296 // actually generating some effect code
egdaniel9cf45bf2014-10-08 06:49:10 -0700297 fRequiresLocalCoordAttrib = this->hasLocalCoordAttribute() &&
298 ds.numTotalStages() - firstColorStageIdx - firstCoverageStageIdx > 0;
egdaniela7dc0a82014-09-17 08:25:05 -0700299
egdaniela7dc0a82014-09-17 08:25:05 -0700300 fReadsDst = false;
301 fReadsFragPosition = false;
302
egdaniel9cf45bf2014-10-08 06:49:10 -0700303 for (int s = firstColorStageIdx; s < ds.numColorStages(); ++s) {
304 const GrFragmentStage& stage = ds.getColorStage(s);
egdaniela7dc0a82014-09-17 08:25:05 -0700305 get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
306 }
egdaniel9cf45bf2014-10-08 06:49:10 -0700307 for (int s = firstCoverageStageIdx; s < ds.numCoverageStages(); ++s) {
308 const GrFragmentStage& stage = ds.getCoverageStage(s);
egdaniela7dc0a82014-09-17 08:25:05 -0700309 get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
310 }
egdaniel9cf45bf2014-10-08 06:49:10 -0700311 if (ds.hasGeometryProcessor()) {
312 const GrGeometryStage& stage = *ds.getGeometryProcessor();
joshualittb0a8a372014-09-23 09:50:21 -0700313 fReadsFragPosition = fReadsFragPosition || stage.getProcessor()->willReadFragmentPosition();
egdaniela7dc0a82014-09-17 08:25:05 -0700314 }
315}
316
egdaniel89af44a2014-09-26 06:15:04 -0700317////////////////////////////////////////////////////////////////////////////////
318
egdaniel3658f382014-09-15 07:01:59 -0700319bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
320 return this->isEqual(that);
321}
322
egdaniel89af44a2014-09-26 06:15:04 -0700323bool GrOptDrawState::isEqual(const GrOptDrawState& that) const {
324 bool usingVertexColors = this->hasColorVertexAttribute();
325 if (!usingVertexColors && this->fColor != that.fColor) {
326 return false;
327 }
328
329 if (this->getRenderTarget() != that.getRenderTarget() ||
330 this->fColorStages.count() != that.fColorStages.count() ||
331 this->fCoverageStages.count() != that.fCoverageStages.count() ||
332 !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
333 this->fSrcBlend != that.fSrcBlend ||
334 this->fDstBlend != that.fDstBlend ||
335 this->fBlendConstant != that.fBlendConstant ||
336 this->fFlagBits != that.fFlagBits ||
337 this->fVACount != that.fVACount ||
338 this->fVAStride != that.fVAStride ||
339 memcmp(this->fVAPtr, that.fVAPtr, this->fVACount * sizeof(GrVertexAttrib)) ||
340 this->fStencilSettings != that.fStencilSettings ||
341 this->fDrawFace != that.fDrawFace ||
342 this->fInputColorIsUsed != that.fInputColorIsUsed ||
343 this->fInputCoverageIsUsed != that.fInputCoverageIsUsed ||
344 this->fReadsDst != that.fReadsDst ||
345 this->fReadsFragPosition != that.fReadsFragPosition ||
346 this->fRequiresLocalCoordAttrib != that.fRequiresLocalCoordAttrib ||
347 this->fPrimaryOutputType != that.fPrimaryOutputType ||
348 this->fSecondaryOutputType != that.fSecondaryOutputType) {
349 return false;
350 }
351
352 bool usingVertexCoverage = this->hasCoverageVertexAttribute();
353 if (!usingVertexCoverage && this->fCoverage != that.fCoverage) {
354 return false;
355 }
356
357 bool explicitLocalCoords = this->hasLocalCoordAttribute();
358 if (this->hasGeometryProcessor()) {
359 if (!that.hasGeometryProcessor()) {
360 return false;
361 } else if (!GrProcessorStage::AreCompatible(*this->getGeometryProcessor(),
362 *that.getGeometryProcessor(),
363 explicitLocalCoords)) {
364 return false;
365 }
366 } else if (that.hasGeometryProcessor()) {
367 return false;
368 }
369
370 for (int i = 0; i < this->numColorStages(); i++) {
371 if (!GrProcessorStage::AreCompatible(this->getColorStage(i), that.getColorStage(i),
372 explicitLocalCoords)) {
373 return false;
374 }
375 }
376 for (int i = 0; i < this->numCoverageStages(); i++) {
377 if (!GrProcessorStage::AreCompatible(this->getCoverageStage(i), that.getCoverageStage(i),
378 explicitLocalCoords)) {
379 return false;
380 }
381 }
382
383 SkASSERT(0 == memcmp(this->fFixedFunctionVertexAttribIndices,
384 that.fFixedFunctionVertexAttribIndices,
385 sizeof(this->fFixedFunctionVertexAttribIndices)));
386
387 return true;
388}
389