|
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 |
|
17 namespace { |
|
18 inline GrGLEffect::EffectKey get_key_and_update_stats(const GrEffectStage& stage, |
|
19 const GrGLCaps& caps, |
|
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; |
|
29 } |
|
30 if (effect->willReadFragmentPosition()) { |
|
31 *setTrueIfReadsPos = true; |
|
32 } |
|
33 if (effect->hasVertexCode()) { |
|
34 *setTrueIfHasVertexCode = true; |
|
35 } |
|
36 return factory.glEffectKey(drawEffect, caps); |
|
37 } |
|
38 } |
|
39 void GrGLProgramDesc::Build(const GrDrawState& drawState, |
|
40 bool isPoints, |
|
41 GrDrawState::BlendOptFlags blendOpts, |
|
42 GrBlendCoeff srcCoeff, |
|
43 GrBlendCoeff dstCoeff, |
|
44 const GrGpuGL* gpu, |
|
45 const GrDeviceCoordTexture* dstCopy, |
|
46 SkTArray<const GrEffectStage*, true>* colorStages, |
|
47 SkTArray<const GrEffectStage*, true>* coverageStages, |
|
48 GrGLProgramDesc* desc) { |
|
49 colorStages->reset(); |
|
50 coverageStages->reset(); |
|
51 |
|
52 // This should already have been caught |
|
53 SkASSERT(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts)); |
|
54 |
|
55 bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag); |
|
56 |
|
57 bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag | |
|
58 GrDrawState::kEmitCoverage_BlendOptFlag)); |
|
59 int firstEffectiveColorStage = 0; |
|
60 bool inputColorIsUsed = true; |
|
61 if (!skipColor) { |
|
62 firstEffectiveColorStage = drawState.numColorStages(); |
|
63 while (firstEffectiveColorStage > 0 && inputColorIsUsed) { |
|
64 --firstEffectiveColorStage; |
|
65 const GrEffect* effect = drawState.getColorStage(firstEffectiveColorStage).getEffect()->get(); |
|
66 inputColorIsUsed = effect->willUseInputColor(); |
|
67 } |
|
68 } |
|
69 |
|
70 int firstEffectiveCoverageStage = 0; |
|
71 bool inputCoverageIsUsed = true; |
|
72 if (!skipCoverage) { |
|
73 firstEffectiveCoverageStage = drawState.numCoverageStages(); |
|
74 while (firstEffectiveCoverageStage > 0 && inputCoverageIsUsed) { |
|
75 --firstEffectiveCoverageStage; |
|
76 const GrEffect* effect = drawState.getCoverageStage(firstEffectiveCoverageStage).getEffect()->get(); |
|
77 inputCoverageIsUsed = effect->willUseInputColor(); |
|
78 } |
|
79 } |
|
80 |
|
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. |
|
85 |
|
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(); |
|
91 |
|
92 bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag); |
|
93 bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) || |
|
94 (!requiresColorAttrib && 0xffffffff == drawState.getColor()) || |
|
95 (!inputColorIsUsed); |
|
96 |
|
97 int numEffects = (skipColor ? 0 : (drawState.numColorStages() - firstEffectiveColorStage)) + |
|
98 (skipCoverage ? 0 : (drawState.numCoverageStages() - firstEffectiveCoverageStage)); |
|
99 |
|
100 size_t newKeyLength = KeyLength(numEffects); |
|
101 bool allocChanged; |
|
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); |
|
106 } |
|
107 // write the key length |
|
108 *desc->atOffset<uint32_t, kLengthOffset>() = SkToU32(newKeyLength); |
|
109 |
|
110 KeyHeader* header = desc->header(); |
|
111 EffectKey* effectKeys = desc->effectKeys(); |
|
112 |
|
113 int currEffectKey = 0; |
|
114 bool readsDst = false; |
|
115 bool readFragPosition = false; |
|
116 bool hasVertexCode = false; |
|
117 if (!skipColor) { |
|
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, |
|
122 &hasVertexCode); |
|
123 } |
|
124 } |
|
125 if (!skipCoverage) { |
|
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, |
|
130 &hasVertexCode); |
|
131 } |
|
132 } |
|
133 |
|
134 header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib; |
|
135 header->fEmitsPointSize = isPoints; |
|
136 |
|
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 |
|
140 #if 0 |
|
141 header->fExperimentalGS = gpu->caps().geometryShaderSupport(); |
|
142 #else |
|
143 header->fExperimentalGS = false; |
|
144 #endif |
|
145 #endif |
|
146 bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport(); |
|
147 |
|
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; |
|
154 } else { |
|
155 header->fColorInput = kAttribute_ColorInput; |
|
156 header->fHasVertexCode = true; |
|
157 } |
|
158 |
|
159 bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverageColor(); |
|
160 |
|
161 if (skipCoverage) { |
|
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; |
|
167 } else { |
|
168 header->fCoverageInput = kAttribute_ColorInput; |
|
169 header->fHasVertexCode = true; |
|
170 } |
|
171 |
|
172 if (readsDst) { |
|
173 SkASSERT(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport()); |
|
174 const GrTexture* dstCopyTexture = NULL; |
|
175 if (NULL != dstCopy) { |
|
176 dstCopyTexture = dstCopy->texture(); |
|
177 } |
|
178 header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps()); |
|
179 SkASSERT(0 != header->fDstReadKey); |
|
180 } else { |
|
181 header->fDstReadKey = 0; |
|
182 } |
|
183 |
|
184 if (readFragPosition) { |
|
185 header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(), |
|
186 gpu->glCaps()); |
|
187 } else { |
|
188 header->fFragPosKey = 0; |
|
189 } |
|
190 |
|
191 // Record attribute indices |
|
192 header->fPositionAttributeIndex = drawState.positionAttributeIndex(); |
|
193 header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex(); |
|
194 |
|
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++; |
|
203 } else { |
|
204 header->fColorAttributeIndex = -1; |
|
205 } |
|
206 |
|
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; |
|
212 } else { |
|
213 header->fCoverageAttributeIndex = -1; |
|
214 } |
|
215 |
|
216 // Here we deal with whether/how we handle color and coverage separately. |
|
217 |
|
218 // Set this default and then possibly change our mind if there is coverage. |
|
219 header->fCoverageOutput = kModulate_CoverageOutput; |
|
220 |
|
221 // If we do have coverage determine whether it matters. |
|
222 bool separateCoverageFromColor = false; |
|
223 if (!drawState.isCoverageDrawing() && !skipCoverage && |
|
224 (drawState.numCoverageStages() > 0 || requiresCoverageAttrib)) { |
|
225 |
|
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; |
|
241 } |
|
242 } else if (readsDst && |
|
243 kOne_GrBlendCoeff == srcCoeff && |
|
244 kZero_GrBlendCoeff == dstCoeff) { |
|
245 header->fCoverageOutput = kCombineWithDst_CoverageOutput; |
|
246 separateCoverageFromColor = true; |
|
247 } |
|
248 } |
|
249 if (!skipColor) { |
|
250 for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) { |
|
251 colorStages->push_back(&drawState.getColorStage(s)); |
|
252 } |
|
253 } |
|
254 if (!skipCoverage) { |
|
255 SkTArray<const GrEffectStage*, true>* array; |
|
256 if (separateCoverageFromColor) { |
|
257 array = coverageStages; |
|
258 } else { |
|
259 array = colorStages; |
|
260 } |
|
261 for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) { |
|
262 array->push_back(&drawState.getCoverageStage(s)); |
|
263 } |
|
264 } |
|
265 header->fColorEffectCnt = colorStages->count(); |
|
266 header->fCoverageEffectCnt = coverageStages->count(); |
|
267 |
|
268 *desc->checksum() = 0; |
|
269 *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()), |
|
270 newKeyLength); |
|
271 desc->fInitialized = true; |
|
272 } |
|
273 |
|
274 GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) { |
|
275 fInitialized = other.fInitialized; |
|
276 if (fInitialized) { |
|
277 size_t keyLength = other.keyLength(); |
|
278 fKey.reset(keyLength); |
|
279 memcpy(fKey.get(), other.fKey.get(), keyLength); |
|
280 } |
|
281 return *this; |
|
282 } |