1/* 2 * Copyright 2013 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 "GrGLProgramDesc.h" 9#include "GrBackendEffectFactory.h" 10#include "GrDrawEffect.h" 11#include "GrEffect.h" 12#include "GrGLShaderBuilder.h" 13#include "GrGpuGL.h" 14 15#include "SkChecksum.h" 16 17namespace { 18inline GrGLEffect::EffectKey get_key_and_update_stats(const GrEffectStage& stage, 19 const GrGLCaps& caps, 20 bool useExplicitLocalCoords, 21 bool* setTrueIfReadsDst, 22 bool* setTrueIfReadsPos) { 23 const GrEffectRef& effect = *stage.getEffect(); 24 const GrBackendEffectFactory& factory = effect->getFactory(); 25 GrDrawEffect drawEffect(stage, useExplicitLocalCoords); 26 if (effect->willReadDstColor()) { 27 *setTrueIfReadsDst = true; 28 } 29 if (effect->willReadFragmentPosition()) { 30 *setTrueIfReadsPos = true; 31 } 32 return factory.glEffectKey(drawEffect, caps); 33} 34} 35void GrGLProgramDesc::Build(const GrDrawState& drawState, 36 bool isPoints, 37 GrDrawState::BlendOptFlags blendOpts, 38 GrBlendCoeff srcCoeff, 39 GrBlendCoeff dstCoeff, 40 const GrGpuGL* gpu, 41 const GrDeviceCoordTexture* dstCopy, 42 SkTArray<const GrEffectStage*, true>* colorStages, 43 SkTArray<const GrEffectStage*, true>* coverageStages, 44 GrGLProgramDesc* desc) { 45 colorStages->reset(); 46 coverageStages->reset(); 47 48 // This should already have been caught 49 GrAssert(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts)); 50 51 bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag); 52 53 bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag | 54 GrDrawState::kEmitCoverage_BlendOptFlag)); 55 56 // The descriptor is used as a cache key. Thus when a field of the 57 // descriptor will not affect program generation (because of the attribute 58 // bindings in use or other descriptor field settings) it should be set 59 // to a canonical value to avoid duplicate programs with different keys. 60 61 bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute(); 62 bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute(); 63 // we only need the local coords if we're actually going to generate effect code 64 bool requiresLocalCoordAttrib = !(skipCoverage && skipColor) && 65 drawState.hasLocalCoordAttribute(); 66 67 bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag); 68 bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) || 69 (!requiresColorAttrib && 0xffffffff == drawState.getColor()); 70 71 int numEffects = (skipColor ? 0 : drawState.numColorStages()) + 72 (skipCoverage ? 0 : drawState.numCoverageStages()); 73 74 size_t newKeyLength = KeyLength(numEffects); 75 bool allocChanged; 76 desc->fKey.reset(newKeyLength, SkAutoMalloc::kAlloc_OnShrink, &allocChanged); 77 if (allocChanged || !desc->fInitialized) { 78 // make sure any padding in the header is zero if we we haven't used this allocation before. 79 memset(desc->header(), 0, kHeaderSize); 80 } 81 // write the key length 82 *desc->atOffset<uint32_t, kLengthOffset>() = newKeyLength; 83 84 KeyHeader* header = desc->header(); 85 EffectKey* effectKeys = desc->effectKeys(); 86 87 int currEffectKey = 0; 88 bool readsDst = false; 89 bool readFragPosition = false; 90 if (!skipColor) { 91 for (int s = 0; s < drawState.numColorStages(); ++s) { 92 effectKeys[currEffectKey++] = 93 get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(), 94 requiresLocalCoordAttrib, &readsDst, &readFragPosition); 95 } 96 } 97 if (!skipCoverage) { 98 for (int s = 0; s < drawState.numCoverageStages(); ++s) { 99 effectKeys[currEffectKey++] = 100 get_key_and_update_stats(drawState.getCoverageStage(s), gpu->glCaps(), 101 requiresLocalCoordAttrib, &readsDst, &readFragPosition); 102 } 103 } 104 105 header->fEmitsPointSize = isPoints; 106 header->fColorFilterXfermode = skipColor ? SkXfermode::kDst_Mode : drawState.getColorFilterMode(); 107 108 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything 109 // other than pass through values from the VS to the FS anyway). 110#if GR_GL_EXPERIMENTAL_GS 111#if 0 112 header->fExperimentalGS = gpu->caps().geometryShaderSupport(); 113#else 114 header->fExperimentalGS = false; 115#endif 116#endif 117 if (colorIsTransBlack) { 118 header->fColorInput = kTransBlack_ColorInput; 119 } else if (colorIsSolidWhite) { 120 header->fColorInput = kSolidWhite_ColorInput; 121 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresColorAttrib) { 122 header->fColorInput = kUniform_ColorInput; 123 } else { 124 header->fColorInput = kAttribute_ColorInput; 125 } 126 127 bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverage(); 128 129 if (skipCoverage) { 130 header->fCoverageInput = kTransBlack_ColorInput; 131 } else if (covIsSolidWhite) { 132 header->fCoverageInput = kSolidWhite_ColorInput; 133 } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresCoverageAttrib) { 134 header->fCoverageInput = kUniform_ColorInput; 135 } else { 136 header->fCoverageInput = kAttribute_ColorInput; 137 } 138 139 if (readsDst) { 140 GrAssert(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport()); 141 const GrTexture* dstCopyTexture = NULL; 142 if (NULL != dstCopy) { 143 dstCopyTexture = dstCopy->texture(); 144 } 145 header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps()); 146 GrAssert(0 != header->fDstReadKey); 147 } else { 148 header->fDstReadKey = 0; 149 } 150 151 if (readFragPosition) { 152 header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(), 153 gpu->glCaps()); 154 } else { 155 header->fFragPosKey = 0; 156 } 157 158 // Record attribute indices 159 header->fPositionAttributeIndex = drawState.positionAttributeIndex(); 160 header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex(); 161 162 // For constant color and coverage we need an attribute with an index beyond those already set 163 int availableAttributeIndex = drawState.getVertexAttribCount(); 164 if (requiresColorAttrib) { 165 header->fColorAttributeIndex = drawState.colorVertexAttributeIndex(); 166 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) { 167 GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt); 168 header->fColorAttributeIndex = availableAttributeIndex; 169 availableAttributeIndex++; 170 } else { 171 header->fColorAttributeIndex = -1; 172 } 173 174 if (requiresCoverageAttrib) { 175 header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex(); 176 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) { 177 GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt); 178 header->fCoverageAttributeIndex = availableAttributeIndex; 179 } else { 180 header->fCoverageAttributeIndex = -1; 181 } 182 183 // Here we deal with whether/how we handle color and coverage separately. 184 185 // Set these defaults and then possibly change our mind if there is coverage. 186 header->fDiscardIfZeroCoverage = false; 187 header->fCoverageOutput = kModulate_CoverageOutput; 188 189 // If we do have coverage determine whether it matters. 190 bool separateCoverageFromColor = false; 191 if (!drawState.isCoverageDrawing() && !skipCoverage && 192 (drawState.numCoverageStages() > 0 || requiresCoverageAttrib)) { 193 // color filter is applied between color/coverage computation 194 if (SkXfermode::kDst_Mode != header->fColorFilterXfermode) { 195 separateCoverageFromColor = true; 196 } 197 198 // If we're stenciling then we want to discard samples that have zero coverage 199 if (drawState.getStencil().doesWrite()) { 200 header->fDiscardIfZeroCoverage = true; 201 separateCoverageFromColor = true; 202 } 203 204 if (gpu->caps()->dualSourceBlendingSupport() && 205 !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag | 206 GrDrawState::kCoverageAsAlpha_BlendOptFlag))) { 207 if (kZero_GrBlendCoeff == dstCoeff) { 208 // write the coverage value to second color 209 header->fCoverageOutput = kSecondaryCoverage_CoverageOutput; 210 separateCoverageFromColor = true; 211 } else if (kSA_GrBlendCoeff == dstCoeff) { 212 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. 213 header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput; 214 separateCoverageFromColor = true; 215 } else if (kSC_GrBlendCoeff == dstCoeff) { 216 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. 217 header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput; 218 separateCoverageFromColor = true; 219 } 220 } else if (readsDst && 221 kOne_GrBlendCoeff == srcCoeff && 222 kZero_GrBlendCoeff == dstCoeff) { 223 header->fCoverageOutput = kCombineWithDst_CoverageOutput; 224 separateCoverageFromColor = true; 225 } 226 } 227 if (!skipColor) { 228 for (int s = 0; s < drawState.numColorStages(); ++s) { 229 colorStages->push_back(&drawState.getColorStage(s)); 230 } 231 header->fColorEffectCnt = drawState.numColorStages(); 232 } 233 if (!skipCoverage) { 234 SkTArray<const GrEffectStage*, true>* array; 235 if (separateCoverageFromColor) { 236 array = coverageStages; 237 header->fCoverageEffectCnt = drawState.numCoverageStages(); 238 } else { 239 array = colorStages; 240 header->fColorEffectCnt += drawState.numCoverageStages(); 241 } 242 for (int s = 0; s < drawState.numCoverageStages(); ++s) { 243 array->push_back(&drawState.getCoverageStage(s)); 244 } 245 } 246 247 *desc->checksum() = 0; 248 *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()), 249 newKeyLength); 250 desc->fInitialized = true; 251} 252 253GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) { 254 fInitialized = other.fInitialized; 255 if (fInitialized) { 256 size_t keyLength = other.keyLength(); 257 fKey.reset(keyLength); 258 memcpy(fKey.get(), other.fKey.get(), keyLength); 259 } 260 return *this; 261} 262