2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "GrOptDrawState.h"
10 #include "GrDrawState.h"
11 #include "GrDrawTargetCaps.h"
12 #include "gl/GrGpuGL.h"
14 GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
15 BlendOptFlags blendOptFlags,
16 GrBlendCoeff optSrcCoeff,
17 GrBlendCoeff optDstCoeff,
19 const GrDeviceCoordTexture* dstCopy,
20 GrGpu::DrawType drawType) {
21 fRenderTarget.set(SkSafeRef(drawState.getRenderTarget()), kWrite_GrIOType);
22 fColor = drawState.getColor();
23 fCoverage = drawState.getCoverage();
24 fViewMatrix = drawState.getViewMatrix();
25 fBlendConstant = drawState.getBlendConstant();
26 fFlagBits = drawState.getFlagBits();
27 fVAPtr = drawState.getVertexAttribs();
28 fVACount = drawState.getVertexAttribCount();
29 fVAStride = drawState.getVertexStride();
30 fStencilSettings = drawState.getStencil();
31 fDrawFace = (DrawFace)drawState.getDrawFace();
32 fBlendOptFlags = blendOptFlags;
33 fSrcBlend = optSrcCoeff;
34 fDstBlend = optDstCoeff;
35 GrProgramDesc::DescInfo descInfo;
37 memcpy(descInfo.fFixedFunctionVertexAttribIndices,
38 drawState.getFixedFunctionVertexAttribIndices(),
39 sizeof(descInfo.fFixedFunctionVertexAttribIndices));
41 descInfo.fInputColorIsUsed = true;
42 descInfo.fInputCoverageIsUsed = true;
44 int firstColorStageIdx = 0;
45 int firstCoverageStageIdx = 0;
46 bool separateCoverageFromColor;
48 uint8_t fixedFunctionVAToRemove = 0;
50 this->computeEffectiveColorStages(drawState, &descInfo, &firstColorStageIdx,
51 &fixedFunctionVAToRemove);
52 this->computeEffectiveCoverageStages(drawState, &descInfo, &firstCoverageStageIdx);
53 this->adjustFromBlendOpts(drawState, &descInfo, &firstColorStageIdx, &firstCoverageStageIdx,
54 &fixedFunctionVAToRemove);
55 // Should not be setting any more FFVA to be removed at this point
56 if (0 != fixedFunctionVAToRemove) {
57 this->removeFixedFunctionVertexAttribs(fixedFunctionVAToRemove, &descInfo);
59 this->getStageStats(drawState, firstColorStageIdx, firstCoverageStageIdx, &descInfo);
60 this->setOutputStateInfo(drawState, *gpu->caps(), firstCoverageStageIdx, &descInfo,
61 &separateCoverageFromColor);
63 // Copy GeometryProcesssor from DS or ODS
64 if (drawState.hasGeometryProcessor()) {
65 fGeometryProcessor.initAndRef(drawState.fGeometryProcessor);
67 fGeometryProcessor.reset(NULL);
70 // Copy Color Stages from DS to ODS
71 if (firstColorStageIdx < drawState.numColorStages()) {
72 fFragmentStages.reset(&drawState.getColorStage(firstColorStageIdx),
73 drawState.numColorStages() - firstColorStageIdx);
75 fFragmentStages.reset();
78 fNumColorStages = fFragmentStages.count();
80 // Copy Coverage Stages from DS to ODS
81 if (firstCoverageStageIdx < drawState.numCoverageStages()) {
82 fFragmentStages.push_back_n(drawState.numCoverageStages() - firstCoverageStageIdx,
83 &drawState.getCoverageStage(firstCoverageStageIdx));
84 if (!separateCoverageFromColor) {
85 fNumColorStages = fFragmentStages.count();
90 gpu->buildProgramDesc(*this, descInfo, drawType, dstCopy, &fDesc);
93 GrOptDrawState* GrOptDrawState::Create(const GrDrawState& drawState,
95 const GrDeviceCoordTexture* dstCopy,
96 GrGpu::DrawType drawType) {
97 const GrDrawTargetCaps& caps = *gpu->caps();
98 if (NULL == drawState.fCachedOptState || caps.getUniqueID() != drawState.fCachedCapsID) {
99 GrBlendCoeff srcCoeff;
100 GrBlendCoeff dstCoeff;
101 BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
105 // If our blend coeffs are set to 0,1 we know we will not end up drawing unless we are
106 // stenciling. When path rendering the stencil settings are not always set on the draw state
107 // so we must check the draw type. In cases where we will skip drawing we simply return a
108 // null GrOptDrawState.
109 if (kZero_GrBlendCoeff == srcCoeff && kOne_GrBlendCoeff == dstCoeff &&
110 !drawState.getStencil().doesWrite() && GrGpu::kStencilPath_DrawType != drawType) {
114 drawState.fCachedOptState = SkNEW_ARGS(GrOptDrawState, (drawState, blendFlags, srcCoeff,
115 dstCoeff, gpu, dstCopy, drawType));
116 drawState.fCachedCapsID = caps.getUniqueID();
119 GrBlendCoeff srcCoeff;
120 GrBlendCoeff dstCoeff;
121 BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
124 SkASSERT(GrOptDrawState(drawState, blendFlags, srcCoeff, dstCoeff, gpu, dstCopy,
125 drawType) == *drawState.fCachedOptState);
128 drawState.fCachedOptState->ref();
129 return drawState.fCachedOptState;
132 void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds,
133 const GrDrawTargetCaps& caps,
134 int firstCoverageStageIdx,
135 GrProgramDesc::DescInfo* descInfo,
136 bool* separateCoverageFromColor) {
137 // Set this default and then possibly change our mind if there is coverage.
138 descInfo->fPrimaryOutputType = GrProgramDesc::kModulate_PrimaryOutputType;
139 descInfo->fSecondaryOutputType = GrProgramDesc::kNone_SecondaryOutputType;
141 // If we do have coverage determine whether it matters.
142 *separateCoverageFromColor = this->hasGeometryProcessor();
143 if (!this->isCoverageDrawing() &&
144 (ds.numCoverageStages() - firstCoverageStageIdx > 0 ||
145 ds.hasGeometryProcessor() ||
146 descInfo->hasCoverageVertexAttribute())) {
148 if (caps.dualSourceBlendingSupport()) {
149 if (kZero_GrBlendCoeff == fDstBlend) {
150 // write the coverage value to second color
151 descInfo->fSecondaryOutputType = GrProgramDesc::kCoverage_SecondaryOutputType;
152 *separateCoverageFromColor = true;
153 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
154 } else if (kSA_GrBlendCoeff == fDstBlend) {
155 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
156 descInfo->fSecondaryOutputType = GrProgramDesc::kCoverageISA_SecondaryOutputType;
157 *separateCoverageFromColor = true;
158 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
159 } else if (kSC_GrBlendCoeff == fDstBlend) {
160 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
161 descInfo->fSecondaryOutputType = GrProgramDesc::kCoverageISC_SecondaryOutputType;
162 *separateCoverageFromColor = true;
163 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
165 } else if (descInfo->fReadsDst &&
166 kOne_GrBlendCoeff == fSrcBlend &&
167 kZero_GrBlendCoeff == fDstBlend) {
168 descInfo->fPrimaryOutputType = GrProgramDesc::kCombineWithDst_PrimaryOutputType;
169 *separateCoverageFromColor = true;
174 void GrOptDrawState::adjustFromBlendOpts(const GrDrawState& ds,
175 GrProgramDesc::DescInfo* descInfo,
176 int* firstColorStageIdx,
177 int* firstCoverageStageIdx,
178 uint8_t* fixedFunctionVAToRemove) {
179 switch (fBlendOptFlags) {
181 case kSkipDraw_BlendOptFlag:
183 case kCoverageAsAlpha_BlendOptFlag:
184 fFlagBits |= kCoverageDrawing_StateBit;
186 case kEmitCoverage_BlendOptFlag:
188 descInfo->fInputColorIsUsed = true;
189 *firstColorStageIdx = ds.numColorStages();
190 *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
192 case kEmitTransBlack_BlendOptFlag:
195 descInfo->fInputColorIsUsed = true;
196 descInfo->fInputCoverageIsUsed = true;
197 *firstColorStageIdx = ds.numColorStages();
198 *firstCoverageStageIdx = ds.numCoverageStages();
199 *fixedFunctionVAToRemove |= (0x1 << kColor_GrVertexAttribBinding |
200 0x1 << kCoverage_GrVertexAttribBinding);
203 SkFAIL("Unknown BlendOptFlag");
207 void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag,
208 GrProgramDesc::DescInfo* descInfo) {
210 uint8_t maskCheck = 0x1;
211 // Count the number of vertex attributes that we will actually remove
212 for (int i = 0; i < kGrFixedFunctionVertexAttribBindingCnt; ++i) {
213 if ((maskCheck & removeVAFlag) && -1 != descInfo->fFixedFunctionVertexAttribIndices[i]) {
219 fOptVA.reset(fVACount - numToRemove);
221 GrVertexAttrib* dst = fOptVA.get();
222 const GrVertexAttrib* src = fVAPtr;
224 for (int i = 0, newIdx = 0; i < fVACount; ++i, ++src) {
225 const GrVertexAttrib& currAttrib = *src;
226 if (currAttrib.fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
227 uint8_t maskCheck = 0x1 << currAttrib.fBinding;
228 if (maskCheck & removeVAFlag) {
229 SkASSERT(-1 != descInfo->fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
230 descInfo->fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
233 descInfo->fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
235 memcpy(dst, src, sizeof(GrVertexAttrib));
239 fVACount -= numToRemove;
240 fVAPtr = fOptVA.get();
243 void GrOptDrawState::computeEffectiveColorStages(const GrDrawState& ds,
244 GrProgramDesc::DescInfo* descInfo,
245 int* firstColorStageIdx,
246 uint8_t* fixedFunctionVAToRemove) {
247 // Set up color and flags for ConstantColorComponent checks
248 GrProcessor::InvariantOutput inout;
249 inout.fIsSingleComponent = false;
250 if (!descInfo->hasColorVertexAttribute()) {
251 inout.fColor = ds.getColor();
252 inout.fValidFlags = kRGBA_GrColorComponentFlags;
254 if (ds.vertexColorsAreOpaque()) {
255 inout.fColor = 0xFF << GrColor_SHIFT_A;
256 inout.fValidFlags = kA_GrColorComponentFlag;
258 inout.fValidFlags = 0;
259 // not strictly necessary but we get false alarms from tools about uninit.
264 for (int i = 0; i < ds.numColorStages(); ++i) {
265 const GrFragmentProcessor* fp = ds.getColorStage(i).getProcessor();
266 fp->computeInvariantOutput(&inout);
267 if (!inout.fWillUseInputColor) {
268 *firstColorStageIdx = i;
269 descInfo->fInputColorIsUsed = false;
271 if (kRGBA_GrColorComponentFlags == inout.fValidFlags) {
272 *firstColorStageIdx = i + 1;
273 fColor = inout.fColor;
274 descInfo->fInputColorIsUsed = true;
275 *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
276 // Since we are clearing all previous color stages we are in a state where we have found
277 // zero stages that don't multiply the inputColor.
278 inout.fNonMulStageFound = false;
283 void GrOptDrawState::computeEffectiveCoverageStages(const GrDrawState& ds,
284 GrProgramDesc::DescInfo* descInfo,
285 int* firstCoverageStageIdx) {
286 // We do not try to optimize out constantColor coverage effects here. It is extremely rare
287 // to have a coverage effect that returns a constant value for all four channels. Thus we
288 // save having to make extra virtual calls by not checking for it.
290 // Don't do any optimizations on coverage stages. It should not be the case where we do not use
291 // input coverage in an effect
292 #ifdef OptCoverageStages
293 GrProcessor::InvariantOutput inout;
294 for (int i = 0; i < ds.numCoverageStages(); ++i) {
295 const GrFragmentProcessor* fp = ds.getCoverageStage(i).getProcessor();
296 fp->computeInvariantOutput(&inout);
297 if (!inout.fWillUseInputColor) {
298 *firstCoverageStageIdx = i;
299 descInfo->fInputCoverageIsUsed = false;
305 static void get_stage_stats(const GrFragmentStage& stage, bool* readsDst, bool* readsFragPosition) {
306 if (stage.getProcessor()->willReadDstColor()) {
309 if (stage.getProcessor()->willReadFragmentPosition()) {
310 *readsFragPosition = true;
314 void GrOptDrawState::getStageStats(const GrDrawState& ds, int firstColorStageIdx,
315 int firstCoverageStageIdx, GrProgramDesc::DescInfo* descInfo) {
316 // We will need a local coord attrib if there is one currently set on the optState and we are
317 // actually generating some effect code
318 descInfo->fRequiresLocalCoordAttrib = descInfo->hasLocalCoordAttribute() &&
319 ds.numTotalStages() - firstColorStageIdx - firstCoverageStageIdx > 0;
321 descInfo->fReadsDst = false;
322 descInfo->fReadsFragPosition = false;
324 for (int s = firstColorStageIdx; s < ds.numColorStages(); ++s) {
325 const GrFragmentStage& stage = ds.getColorStage(s);
326 get_stage_stats(stage, &descInfo->fReadsDst, &descInfo->fReadsFragPosition);
328 for (int s = firstCoverageStageIdx; s < ds.numCoverageStages(); ++s) {
329 const GrFragmentStage& stage = ds.getCoverageStage(s);
330 get_stage_stats(stage, &descInfo->fReadsDst, &descInfo->fReadsFragPosition);
332 if (ds.hasGeometryProcessor()) {
333 const GrGeometryProcessor& gp = *ds.getGeometryProcessor();
334 descInfo->fReadsFragPosition = descInfo->fReadsFragPosition || gp.willReadFragmentPosition();
338 ////////////////////////////////////////////////////////////////////////////////
340 bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
341 return this->isEqual(that);
344 bool GrOptDrawState::isEqual(const GrOptDrawState& that) const {
345 if (this->fDesc != that.fDesc) {
348 bool usingVertexColors = that.fDesc.header().fColorAttributeIndex != -1;
349 if (!usingVertexColors && this->fColor != that.fColor) {
353 if (this->getRenderTarget() != that.getRenderTarget() ||
354 !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
355 this->fSrcBlend != that.fSrcBlend ||
356 this->fDstBlend != that.fDstBlend ||
357 this->fBlendConstant != that.fBlendConstant ||
358 this->fFlagBits != that.fFlagBits ||
359 this->fVACount != that.fVACount ||
360 this->fVAStride != that.fVAStride ||
361 memcmp(this->fVAPtr, that.fVAPtr, this->fVACount * sizeof(GrVertexAttrib)) ||
362 this->fStencilSettings != that.fStencilSettings ||
363 this->fDrawFace != that.fDrawFace) {
367 bool usingVertexCoverage = this->fDesc.header().fCoverageAttributeIndex != -1;
368 if (!usingVertexCoverage && this->fCoverage != that.fCoverage) {
372 if (this->hasGeometryProcessor()) {
373 if (!that.hasGeometryProcessor()) {
375 } else if (!this->getGeometryProcessor()->isEqual(*that.getGeometryProcessor())) {
378 } else if (that.hasGeometryProcessor()) {
382 bool explicitLocalCoords = this->fDesc.header().fLocalCoordAttributeIndex != -1;
383 for (int i = 0; i < this->numFragmentStages(); i++) {
384 if (!GrFragmentStage::AreCompatible(this->getFragmentStage(i), that.getFragmentStage(i),
385 explicitLocalCoords)) {