1 /* 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" 11 #include "GrDrawTargetCaps.h" 12 #include "GrGpu.h" 13 14 GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, 15 BlendOptFlags blendOptFlags, 16 GrBlendCoeff optSrcCoeff, 17 GrBlendCoeff optDstCoeff, 18 const GrDrawTargetCaps& caps) : INHERITED(drawState) { 19 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(); 28 fDrawFace = drawState.getDrawFace(); 29 fBlendOptFlags = blendOptFlags; 30 fSrcBlend = optSrcCoeff; 31 fDstBlend = optDstCoeff; 32 33 memcpy(fFixedFunctionVertexAttribIndices, 34 drawState.getFixedFunctionVertexAttribIndices(), 35 sizeof(fFixedFunctionVertexAttribIndices)); 36 37 38 fInputColorIsUsed = true; 39 fInputCoverageIsUsed = true; 40 41 if (drawState.hasGeometryProcessor()) { 42 fGeometryProcessor.reset(SkNEW_ARGS(GrGeometryStage, (*drawState.getGeometryProcessor()))); 43 } else { 44 fGeometryProcessor.reset(NULL); 45 } 46 47 this->copyEffectiveColorStages(drawState); 48 this->copyEffectiveCoverageStages(drawState); 49 this->adjustFromBlendOpts(); 50 this->getStageStats(); 51 this->setOutputStateInfo(caps); 52 }; 53 54 void GrOptDrawState::setOutputStateInfo(const GrDrawTargetCaps& caps) { 55 // Set this default and then possibly change our mind if there is coverage. 56 fPrimaryOutputType = kModulate_PrimaryOutputType; 57 fSecondaryOutputType = kNone_SecondaryOutputType; 58 59 // If we do have coverage determine whether it matters. 60 bool separateCoverageFromColor = this->hasGeometryProcessor(); 61 if (!this->isCoverageDrawing() && 62 (this->numCoverageStages() > 0 || 63 this->hasGeometryProcessor() || 64 this->hasCoverageVertexAttribute())) { 65 66 if (caps.dualSourceBlendingSupport()) { 67 if (kZero_GrBlendCoeff == fDstBlend) { 68 // write the coverage value to second color 69 fSecondaryOutputType = kCoverage_SecondaryOutputType; 70 separateCoverageFromColor = true; 71 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; 72 } else if (kSA_GrBlendCoeff == fDstBlend) { 73 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. 74 fSecondaryOutputType = kCoverageISA_SecondaryOutputType; 75 separateCoverageFromColor = true; 76 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; 77 } else if (kSC_GrBlendCoeff == fDstBlend) { 78 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. 79 fSecondaryOutputType = kCoverageISC_SecondaryOutputType; 80 separateCoverageFromColor = true; 81 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; 82 } 83 } else if (fReadsDst && 84 kOne_GrBlendCoeff == fSrcBlend && 85 kZero_GrBlendCoeff == fDstBlend) { 86 fPrimaryOutputType = kCombineWithDst_PrimaryOutputType; 87 separateCoverageFromColor = true; 88 } 89 } 90 91 // TODO: Once we have flag to know if we only multiply on stages, only push coverage into color 92 // stages if everything is multipy 93 if (!separateCoverageFromColor) { 94 for (int s = 0; s < this->numCoverageStages(); ++s) { 95 fColorStages.push_back(this->getCoverageStage(s)); 96 } 97 fCoverageStages.reset(); 98 } 99 } 100 101 void GrOptDrawState::adjustFromBlendOpts() { 102 103 switch (fBlendOptFlags) { 104 case kNone_BlendOpt: 105 case kSkipDraw_BlendOptFlag: 106 break; 107 case kCoverageAsAlpha_BlendOptFlag: 108 fFlagBits |= kCoverageDrawing_StateBit; 109 break; 110 case kEmitCoverage_BlendOptFlag: 111 fColor = 0xffffffff; 112 fInputColorIsUsed = true; 113 fColorStages.reset(); 114 this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding); 115 break; 116 case kEmitTransBlack_BlendOptFlag: 117 fColor = 0; 118 fCoverage = 0xff; 119 fInputColorIsUsed = true; 120 fInputCoverageIsUsed = true; 121 fColorStages.reset(); 122 fCoverageStages.reset(); 123 this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding | 124 0x1 << kCoverage_GrVertexAttribBinding); 125 break; 126 default: 127 SkFAIL("Unknown BlendOptFlag"); 128 129 } 130 } 131 132 void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag) { 133 int numToRemove = 0; 134 uint8_t maskCheck = 0x1; 135 // Count the number of vertex attributes that we will actually remove 136 for (int i = 0; i < kGrFixedFunctionVertexAttribBindingCnt; ++i) { 137 if ((maskCheck & removeVAFlag) && -1 != fFixedFunctionVertexAttribIndices[i]) { 138 ++numToRemove; 139 } 140 maskCheck <<= 1; 141 } 142 143 fOptVA.reset(fVACount - numToRemove); 144 145 GrVertexAttrib* dst = fOptVA.get(); 146 const GrVertexAttrib* src = fVAPtr; 147 148 for (int i = 0, newIdx = 0; i < fVACount; ++i, ++src) { 149 const GrVertexAttrib& currAttrib = *src; 150 if (currAttrib.fBinding < kGrFixedFunctionVertexAttribBindingCnt) { 151 uint8_t maskCheck = 0x1 << currAttrib.fBinding; 152 if (maskCheck & removeVAFlag) { 153 SkASSERT(-1 != fFixedFunctionVertexAttribIndices[currAttrib.fBinding]); 154 fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1; 155 continue; 156 } 157 fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx; 158 } 159 memcpy(dst, src, sizeof(GrVertexAttrib)); 160 ++newIdx; 161 ++dst; 162 } 163 fVACount -= numToRemove; 164 fVAPtr = fOptVA.get(); 165 } 166 167 void GrOptDrawState::copyEffectiveColorStages(const GrDrawState& ds) { 168 int firstColorStage = 0; 169 170 // Set up color and flags for ConstantColorComponent checks 171 GrColor color; 172 uint32_t validComponentFlags; 173 if (!this->hasColorVertexAttribute()) { 174 color = ds.getColor(); 175 validComponentFlags = kRGBA_GrColorComponentFlags; 176 } else { 177 if (ds.vertexColorsAreOpaque()) { 178 color = 0xFF << GrColor_SHIFT_A; 179 validComponentFlags = kA_GrColorComponentFlag; 180 } else { 181 validComponentFlags = 0; 182 color = 0; // not strictly necessary but we get false alarms from tools about uninit. 183 } 184 } 185 186 for (int i = 0; i < ds.numColorStages(); ++i) { 187 const GrFragmentProcessor* fp = ds.getColorStage(i).getFragmentProcessor(); 188 if (!fp->willUseInputColor()) { 189 firstColorStage = i; 190 fInputColorIsUsed = false; 191 } 192 fp->getConstantColorComponents(&color, &validComponentFlags); 193 if (kRGBA_GrColorComponentFlags == validComponentFlags) { 194 firstColorStage = i + 1; 195 fColor = color; 196 fInputColorIsUsed = true; 197 this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding); 198 } 199 } 200 if (firstColorStage < ds.numColorStages()) { 201 fColorStages.reset(&ds.getColorStage(firstColorStage), 202 ds.numColorStages() - firstColorStage); 203 } else { 204 fColorStages.reset(); 205 } 206 } 207 208 void GrOptDrawState::copyEffectiveCoverageStages(const GrDrawState& ds) { 209 int firstCoverageStage = 0; 210 211 // We do not try to optimize out constantColor coverage effects here. It is extremely rare 212 // to have a coverage effect that returns a constant value for all four channels. Thus we 213 // save having to make extra virtual calls by not checking for it. 214 215 // Don't do any optimizations on coverage stages. It should not be the case where we do not use 216 // input coverage in an effect 217 #ifdef OptCoverageStages 218 for (int i = 0; i < ds.numCoverageStages(); ++i) { 219 const GrProcessor* processor = ds.getCoverageStage(i).getProcessor(); 220 if (!processor->willUseInputColor()) { 221 firstCoverageStage = i; 222 fInputCoverageIsUsed = false; 223 } 224 } 225 #endif 226 if (ds.numCoverageStages() > 0) { 227 fCoverageStages.reset(&ds.getCoverageStage(firstCoverageStage), 228 ds.numCoverageStages() - firstCoverageStage); 229 } else { 230 fCoverageStages.reset(); 231 } 232 } 233 234 static void get_stage_stats(const GrFragmentStage& stage, bool* readsDst, bool* readsFragPosition) { 235 if (stage.getFragmentProcessor()->willReadDstColor()) { 236 *readsDst = true; 237 } 238 if (stage.getFragmentProcessor()->willReadFragmentPosition()) { 239 *readsFragPosition = true; 240 } 241 } 242 243 void GrOptDrawState::getStageStats() { 244 // We will need a local coord attrib if there is one currently set on the optState and we are 245 // actually generating some effect code 246 fRequiresLocalCoordAttrib = this->hasLocalCoordAttribute() && this->numTotalStages() > 0; 247 248 fReadsDst = false; 249 fReadsFragPosition = false; 250 251 for (int s = 0; s < this->numColorStages(); ++s) { 252 const GrFragmentStage& stage = this->getColorStage(s); 253 get_stage_stats(stage, &fReadsDst, &fReadsFragPosition); 254 } 255 for (int s = 0; s < this->numCoverageStages(); ++s) { 256 const GrFragmentStage& stage = this->getCoverageStage(s); 257 get_stage_stats(stage, &fReadsDst, &fReadsFragPosition); 258 } 259 if (this->hasGeometryProcessor()) { 260 const GrGeometryStage& stage = *this->getGeometryProcessor(); 261 fReadsFragPosition = fReadsFragPosition || stage.getProcessor()->willReadFragmentPosition(); 262 } 263 } 264 265 bool GrOptDrawState::operator== (const GrOptDrawState& that) const { 266 return this->isEqual(that); 267 } 268 269