2 * Copyright 2013 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 "GrGLProgramDesc.h"
9 #include "GrBackendEffectFactory.h"
10 #include "GrDrawEffect.h"
12 #include "GrGLShaderBuilder.h"
15 #include "SkChecksum.h"
18 inline GrGLEffect::EffectKey get_key_and_update_stats(const GrEffectStage& stage,
20 bool useExplicitLocalCoords,
21 bool* setTrueIfReadsDst,
22 bool* setTrueIfReadsPos,
23 bool* setTrueIfHasVertexCode) {
24 const GrEffectRef& effect = *stage.getEffect();
25 const GrBackendEffectFactory& factory = effect->getFactory();
26 GrDrawEffect drawEffect(stage, useExplicitLocalCoords);
27 if (effect->willReadDstColor()) {
28 *setTrueIfReadsDst = true;
30 if (effect->willReadFragmentPosition()) {
31 *setTrueIfReadsPos = true;
33 if (effect->hasVertexCode()) {
34 *setTrueIfHasVertexCode = true;
36 return factory.glEffectKey(drawEffect, caps);
39 void GrGLProgramDesc::Build(const GrDrawState& drawState,
41 GrDrawState::BlendOptFlags blendOpts,
42 GrBlendCoeff srcCoeff,
43 GrBlendCoeff dstCoeff,
45 const GrDeviceCoordTexture* dstCopy,
46 SkTArray<const GrEffectStage*, true>* colorStages,
47 SkTArray<const GrEffectStage*, true>* coverageStages,
48 GrGLProgramDesc* desc) {
50 coverageStages->reset();
52 // This should already have been caught
53 SkASSERT(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
55 bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
57 bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
58 GrDrawState::kEmitCoverage_BlendOptFlag));
59 int firstEffectiveColorStage = 0;
60 bool inputColorIsUsed = true;
62 firstEffectiveColorStage = drawState.numColorStages();
63 while (firstEffectiveColorStage > 0 && inputColorIsUsed) {
64 --firstEffectiveColorStage;
65 const GrEffect* effect = drawState.getColorStage(firstEffectiveColorStage).getEffect()->get();
66 inputColorIsUsed = effect->willUseInputColor();
70 int firstEffectiveCoverageStage = 0;
71 bool inputCoverageIsUsed = true;
73 firstEffectiveCoverageStage = drawState.numCoverageStages();
74 while (firstEffectiveCoverageStage > 0 && inputCoverageIsUsed) {
75 --firstEffectiveCoverageStage;
76 const GrEffect* effect = drawState.getCoverageStage(firstEffectiveCoverageStage).getEffect()->get();
77 inputCoverageIsUsed = effect->willUseInputColor();
81 // The descriptor is used as a cache key. Thus when a field of the
82 // descriptor will not affect program generation (because of the attribute
83 // bindings in use or other descriptor field settings) it should be set
84 // to a canonical value to avoid duplicate programs with different keys.
86 bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
87 bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
88 // we only need the local coords if we're actually going to generate effect code
89 bool requiresLocalCoordAttrib = !(skipCoverage && skipColor) &&
90 drawState.hasLocalCoordAttribute();
92 bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
93 bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
94 (!requiresColorAttrib && 0xffffffff == drawState.getColor()) ||
97 int numEffects = (skipColor ? 0 : (drawState.numColorStages() - firstEffectiveColorStage)) +
98 (skipCoverage ? 0 : (drawState.numCoverageStages() - firstEffectiveCoverageStage));
100 size_t newKeyLength = KeyLength(numEffects);
102 desc->fKey.reset(newKeyLength, SkAutoMalloc::kAlloc_OnShrink, &allocChanged);
103 if (allocChanged || !desc->fInitialized) {
104 // make sure any padding in the header is zero if we we haven't used this allocation before.
105 memset(desc->header(), 0, kHeaderSize);
107 // write the key length
108 *desc->atOffset<uint32_t, kLengthOffset>() = SkToU32(newKeyLength);
110 KeyHeader* header = desc->header();
111 EffectKey* effectKeys = desc->effectKeys();
113 int currEffectKey = 0;
114 bool readsDst = false;
115 bool readFragPosition = false;
116 bool hasVertexCode = false;
118 for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
119 effectKeys[currEffectKey++] =
120 get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
121 requiresLocalCoordAttrib, &readsDst, &readFragPosition,
126 for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
127 effectKeys[currEffectKey++] =
128 get_key_and_update_stats(drawState.getCoverageStage(s), gpu->glCaps(),
129 requiresLocalCoordAttrib, &readsDst, &readFragPosition,
134 header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib;
135 header->fEmitsPointSize = isPoints;
137 // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
138 // other than pass through values from the VS to the FS anyway).
139 #if GR_GL_EXPERIMENTAL_GS
141 header->fExperimentalGS = gpu->caps().geometryShaderSupport();
143 header->fExperimentalGS = false;
146 bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport();
148 if (colorIsTransBlack) {
149 header->fColorInput = kTransBlack_ColorInput;
150 } else if (colorIsSolidWhite) {
151 header->fColorInput = kSolidWhite_ColorInput;
152 } else if (defaultToUniformInputs && !requiresColorAttrib) {
153 header->fColorInput = kUniform_ColorInput;
155 header->fColorInput = kAttribute_ColorInput;
156 header->fHasVertexCode = true;
159 bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverageColor();
162 header->fCoverageInput = kTransBlack_ColorInput;
163 } else if (covIsSolidWhite || !inputCoverageIsUsed) {
164 header->fCoverageInput = kSolidWhite_ColorInput;
165 } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
166 header->fCoverageInput = kUniform_ColorInput;
168 header->fCoverageInput = kAttribute_ColorInput;
169 header->fHasVertexCode = true;
173 SkASSERT(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
174 const GrTexture* dstCopyTexture = NULL;
175 if (NULL != dstCopy) {
176 dstCopyTexture = dstCopy->texture();
178 header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
179 SkASSERT(0 != header->fDstReadKey);
181 header->fDstReadKey = 0;
184 if (readFragPosition) {
185 header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
188 header->fFragPosKey = 0;
191 // Record attribute indices
192 header->fPositionAttributeIndex = drawState.positionAttributeIndex();
193 header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();
195 // For constant color and coverage we need an attribute with an index beyond those already set
196 int availableAttributeIndex = drawState.getVertexAttribCount();
197 if (requiresColorAttrib) {
198 header->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
199 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
200 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
201 header->fColorAttributeIndex = availableAttributeIndex;
202 availableAttributeIndex++;
204 header->fColorAttributeIndex = -1;
207 if (requiresCoverageAttrib) {
208 header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
209 } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
210 SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
211 header->fCoverageAttributeIndex = availableAttributeIndex;
213 header->fCoverageAttributeIndex = -1;
216 // Here we deal with whether/how we handle color and coverage separately.
218 // Set this default and then possibly change our mind if there is coverage.
219 header->fCoverageOutput = kModulate_CoverageOutput;
221 // If we do have coverage determine whether it matters.
222 bool separateCoverageFromColor = false;
223 if (!drawState.isCoverageDrawing() && !skipCoverage &&
224 (drawState.numCoverageStages() > 0 || requiresCoverageAttrib)) {
226 if (gpu->caps()->dualSourceBlendingSupport() &&
227 !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
228 GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
229 if (kZero_GrBlendCoeff == dstCoeff) {
230 // write the coverage value to second color
231 header->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
232 separateCoverageFromColor = true;
233 } else if (kSA_GrBlendCoeff == dstCoeff) {
234 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
235 header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
236 separateCoverageFromColor = true;
237 } else if (kSC_GrBlendCoeff == dstCoeff) {
238 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
239 header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
240 separateCoverageFromColor = true;
242 } else if (readsDst &&
243 kOne_GrBlendCoeff == srcCoeff &&
244 kZero_GrBlendCoeff == dstCoeff) {
245 header->fCoverageOutput = kCombineWithDst_CoverageOutput;
246 separateCoverageFromColor = true;
250 for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
251 colorStages->push_back(&drawState.getColorStage(s));
255 SkTArray<const GrEffectStage*, true>* array;
256 if (separateCoverageFromColor) {
257 array = coverageStages;
261 for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
262 array->push_back(&drawState.getCoverageStage(s));
265 header->fColorEffectCnt = colorStages->count();
266 header->fCoverageEffectCnt = coverageStages->count();
268 *desc->checksum() = 0;
269 *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()),
271 desc->fInitialized = true;
274 GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
275 fInitialized = other.fInitialized;
277 size_t keyLength = other.keyLength();
278 fKey.reset(keyLength);
279 memcpy(fKey.get(), other.fKey.get(), keyLength);