• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
get_key_and_update_stats(const GrEffectStage & stage,const GrGLCaps & caps,bool useExplicitLocalCoords,bool * setTrueIfReadsDst,bool * setTrueIfReadsPos,bool * setTrueIfHasVertexCode)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 }
Build(const GrDrawState & drawState,GrGpu::DrawType drawType,GrDrawState::BlendOptFlags blendOpts,GrBlendCoeff srcCoeff,GrBlendCoeff dstCoeff,const GrGpuGL * gpu,const GrDeviceCoordTexture * dstCopy,SkTArray<const GrEffectStage *,true> * colorStages,SkTArray<const GrEffectStage *,true> * coverageStages,GrGLProgramDesc * desc)39 void GrGLProgramDesc::Build(const GrDrawState& drawState,
40                             GrGpu::DrawType drawType,
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     // We use vertexshader-less shader programs only when drawing paths.
117     bool hasVertexCode = !(GrGpu::kDrawPath_DrawType == drawType ||
118                            GrGpu::kDrawPaths_DrawType == drawType);
119 
120     if (!skipColor) {
121         for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
122             effectKeys[currEffectKey++] =
123                 get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
124                                          requiresLocalCoordAttrib, &readsDst, &readFragPosition,
125                                          &hasVertexCode);
126         }
127     }
128     if (!skipCoverage) {
129         for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
130             effectKeys[currEffectKey++] =
131                 get_key_and_update_stats(drawState.getCoverageStage(s), gpu->glCaps(),
132                                          requiresLocalCoordAttrib, &readsDst, &readFragPosition,
133                                          &hasVertexCode);
134         }
135     }
136 
137     header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib;
138     header->fEmitsPointSize = GrGpu::kDrawPoints_DrawType == drawType;
139 
140     // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
141     // other than pass through values from the VS to the FS anyway).
142 #if GR_GL_EXPERIMENTAL_GS
143 #if 0
144     header->fExperimentalGS = gpu->caps().geometryShaderSupport();
145 #else
146     header->fExperimentalGS = false;
147 #endif
148 #endif
149     bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport();
150 
151     if (colorIsTransBlack) {
152         header->fColorInput = kTransBlack_ColorInput;
153     } else if (colorIsSolidWhite) {
154         header->fColorInput = kSolidWhite_ColorInput;
155     } else if (defaultToUniformInputs && !requiresColorAttrib) {
156         header->fColorInput = kUniform_ColorInput;
157     } else {
158         header->fColorInput = kAttribute_ColorInput;
159         header->fHasVertexCode = true;
160     }
161 
162     bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverageColor();
163 
164     if (skipCoverage) {
165         header->fCoverageInput = kTransBlack_ColorInput;
166     } else if (covIsSolidWhite || !inputCoverageIsUsed) {
167         header->fCoverageInput = kSolidWhite_ColorInput;
168     } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
169         header->fCoverageInput = kUniform_ColorInput;
170     } else {
171         header->fCoverageInput = kAttribute_ColorInput;
172         header->fHasVertexCode = true;
173     }
174 
175     if (readsDst) {
176         SkASSERT(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
177         const GrTexture* dstCopyTexture = NULL;
178         if (NULL != dstCopy) {
179             dstCopyTexture = dstCopy->texture();
180         }
181         header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
182         SkASSERT(0 != header->fDstReadKey);
183     } else {
184         header->fDstReadKey = 0;
185     }
186 
187     if (readFragPosition) {
188         header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
189                                                                       gpu->glCaps());
190     } else {
191         header->fFragPosKey = 0;
192     }
193 
194     // Record attribute indices
195     header->fPositionAttributeIndex = drawState.positionAttributeIndex();
196     header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();
197 
198     // For constant color and coverage we need an attribute with an index beyond those already set
199     int availableAttributeIndex = drawState.getVertexAttribCount();
200     if (requiresColorAttrib) {
201         header->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
202     } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
203         SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
204         header->fColorAttributeIndex = availableAttributeIndex;
205         availableAttributeIndex++;
206     } else {
207         header->fColorAttributeIndex = -1;
208     }
209 
210     if (requiresCoverageAttrib) {
211         header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
212     } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
213         SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
214         header->fCoverageAttributeIndex = availableAttributeIndex;
215     } else {
216         header->fCoverageAttributeIndex = -1;
217     }
218 
219     // Here we deal with whether/how we handle color and coverage separately.
220 
221     // Set this default and then possibly change our mind if there is coverage.
222     header->fCoverageOutput = kModulate_CoverageOutput;
223 
224     // If we do have coverage determine whether it matters.
225     bool separateCoverageFromColor = false;
226     if (!drawState.isCoverageDrawing() && !skipCoverage &&
227         (drawState.numCoverageStages() > 0 || requiresCoverageAttrib)) {
228 
229         if (gpu->caps()->dualSourceBlendingSupport() &&
230             !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
231                            GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
232             if (kZero_GrBlendCoeff == dstCoeff) {
233                 // write the coverage value to second color
234                 header->fCoverageOutput =  kSecondaryCoverage_CoverageOutput;
235                 separateCoverageFromColor = true;
236             } else if (kSA_GrBlendCoeff == dstCoeff) {
237                 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
238                 header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
239                 separateCoverageFromColor = true;
240             } else if (kSC_GrBlendCoeff == dstCoeff) {
241                 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
242                 header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
243                 separateCoverageFromColor = true;
244             }
245         } else if (readsDst &&
246                    kOne_GrBlendCoeff == srcCoeff &&
247                    kZero_GrBlendCoeff == dstCoeff) {
248             header->fCoverageOutput = kCombineWithDst_CoverageOutput;
249             separateCoverageFromColor = true;
250         }
251     }
252     if (!skipColor) {
253         for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
254             colorStages->push_back(&drawState.getColorStage(s));
255         }
256     }
257     if (!skipCoverage) {
258         SkTArray<const GrEffectStage*, true>* array;
259         if (separateCoverageFromColor) {
260             array = coverageStages;
261         } else {
262             array = colorStages;
263         }
264         for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
265             array->push_back(&drawState.getCoverageStage(s));
266         }
267     }
268     header->fColorEffectCnt = colorStages->count();
269     header->fCoverageEffectCnt = coverageStages->count();
270 
271     *desc->checksum() = 0;
272     *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()),
273                                             newKeyLength);
274     desc->fInitialized = true;
275 }
276 
operator =(const GrGLProgramDesc & other)277 GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
278     fInitialized = other.fInitialized;
279     if (fInitialized) {
280         size_t keyLength = other.keyLength();
281         fKey.reset(keyLength);
282         memcpy(fKey.get(), other.fKey.get(), keyLength);
283     }
284     return *this;
285 }
286