• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 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 "GrGpuGL.h"
9 
10 #include "GrEffect.h"
11 #include "GrGLEffect.h"
12 #include "GrGpuVertex.h"
13 
14 typedef GrGLUniformManager::UniformHandle UniformHandle;
15 static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
16 
17 #define SKIP_CACHE_CHECK    true
18 #define GR_UINT32_MAX   static_cast<uint32_t>(-1)
19 
ProgramCache(const GrGLContextInfo & gl)20 GrGpuGL::ProgramCache::ProgramCache(const GrGLContextInfo& gl)
21     : fCount(0)
22     , fCurrLRUStamp(0)
23     , fGL(gl) {
24 }
25 
abandon()26 void GrGpuGL::ProgramCache::abandon() {
27     for (int i = 0; i < fCount; ++i) {
28         GrAssert(NULL != fEntries[i].fProgram.get());
29         fEntries[i].fProgram->abandon();
30         fEntries[i].fProgram.reset(NULL);
31     }
32     fCount = 0;
33 }
34 
getProgram(const ProgramDesc & desc,const GrEffectStage * stages[])35 GrGLProgram* GrGpuGL::ProgramCache::getProgram(const ProgramDesc& desc,
36                                                const GrEffectStage* stages[]) {
37     Entry newEntry;
38     newEntry.fKey.setKeyData(desc.asKey());
39 
40     Entry* entry = fHashCache.find(newEntry.fKey);
41     if (NULL == entry) {
42         newEntry.fProgram.reset(GrGLProgram::Create(fGL, desc, stages));
43         if (NULL == newEntry.fProgram.get()) {
44             return NULL;
45         }
46         if (fCount < kMaxEntries) {
47             entry = fEntries + fCount;
48             ++fCount;
49         } else {
50             GrAssert(kMaxEntries == fCount);
51             entry = fEntries;
52             for (int i = 1; i < kMaxEntries; ++i) {
53                 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
54                     entry = fEntries + i;
55                 }
56             }
57             fHashCache.remove(entry->fKey, entry);
58         }
59         *entry = newEntry;
60         fHashCache.insert(entry->fKey, entry);
61     }
62 
63     entry->fLRUStamp = fCurrLRUStamp;
64     if (GR_UINT32_MAX == fCurrLRUStamp) {
65         // wrap around! just trash our LRU, one time hit.
66         for (int i = 0; i < fCount; ++i) {
67             fEntries[i].fLRUStamp = 0;
68         }
69     }
70     ++fCurrLRUStamp;
71     return entry->fProgram;
72 }
73 
74 ////////////////////////////////////////////////////////////////////////////////
75 
abandonResources()76 void GrGpuGL::abandonResources(){
77     INHERITED::abandonResources();
78     fProgramCache->abandon();
79     fHWProgramID = 0;
80 }
81 
82 ////////////////////////////////////////////////////////////////////////////////
83 
84 #define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
85 
flushViewMatrix(DrawType type)86 void GrGpuGL::flushViewMatrix(DrawType type) {
87     const GrGLRenderTarget* rt = static_cast<const GrGLRenderTarget*>(this->getDrawState().getRenderTarget());
88     SkISize viewportSize;
89     const GrGLIRect& viewport = rt->getViewport();
90     viewportSize.set(viewport.fWidth, viewport.fHeight);
91 
92     const SkMatrix& vm = this->getDrawState().getViewMatrix();
93 
94     if (kStencilPath_DrawType == type) {
95         if (fHWPathMatrixState.fViewMatrix != vm ||
96             fHWPathMatrixState.fRTSize != viewportSize) {
97             // rescale the coords from skia's "device" coords to GL's normalized coords,
98             // and perform a y-flip.
99             SkMatrix m;
100             m.setScale(SkIntToScalar(2) / rt->width(), SkIntToScalar(-2) / rt->height());
101             m.postTranslate(-SK_Scalar1, SK_Scalar1);
102             m.preConcat(vm);
103 
104             // GL wants a column-major 4x4.
105             GrGLfloat mv[]  = {
106                 // col 0
107                 SkScalarToFloat(m[SkMatrix::kMScaleX]),
108                 SkScalarToFloat(m[SkMatrix::kMSkewY]),
109                 0,
110                 SkScalarToFloat(m[SkMatrix::kMPersp0]),
111 
112                 // col 1
113                 SkScalarToFloat(m[SkMatrix::kMSkewX]),
114                 SkScalarToFloat(m[SkMatrix::kMScaleY]),
115                 0,
116                 SkScalarToFloat(m[SkMatrix::kMPersp1]),
117 
118                 // col 2
119                 0, 0, 0, 0,
120 
121                 // col3
122                 SkScalarToFloat(m[SkMatrix::kMTransX]),
123                 SkScalarToFloat(m[SkMatrix::kMTransY]),
124                 0.0f,
125                 SkScalarToFloat(m[SkMatrix::kMPersp2])
126             };
127             GL_CALL(MatrixMode(GR_GL_PROJECTION));
128             GL_CALL(LoadMatrixf(mv));
129             fHWPathMatrixState.fViewMatrix = vm;
130             fHWPathMatrixState.fRTSize = viewportSize;
131         }
132     } else if (!fCurrentProgram->fViewMatrix.cheapEqualTo(vm) ||
133                fCurrentProgram->fViewportSize != viewportSize) {
134         SkMatrix m;
135         m.setAll(
136             SkIntToScalar(2) / viewportSize.fWidth, 0, -SK_Scalar1,
137             0,-SkIntToScalar(2) / viewportSize.fHeight, SK_Scalar1,
138             0, 0, SkMatrix::I()[8]);
139         m.setConcat(m, vm);
140 
141         // ES doesn't allow you to pass true to the transpose param,
142         // so do our own transpose
143         GrGLfloat mt[]  = {
144             SkScalarToFloat(m[SkMatrix::kMScaleX]),
145             SkScalarToFloat(m[SkMatrix::kMSkewY]),
146             SkScalarToFloat(m[SkMatrix::kMPersp0]),
147             SkScalarToFloat(m[SkMatrix::kMSkewX]),
148             SkScalarToFloat(m[SkMatrix::kMScaleY]),
149             SkScalarToFloat(m[SkMatrix::kMPersp1]),
150             SkScalarToFloat(m[SkMatrix::kMTransX]),
151             SkScalarToFloat(m[SkMatrix::kMTransY]),
152             SkScalarToFloat(m[SkMatrix::kMPersp2])
153         };
154         fCurrentProgram->fUniformManager.setMatrix3f(
155                                             fCurrentProgram->fUniformHandles.fViewMatrixUni,
156                                             mt);
157         fCurrentProgram->fViewMatrix = vm;
158         fCurrentProgram->fViewportSize = viewportSize;
159     }
160 }
161 
162 ///////////////////////////////////////////////////////////////////////////////
163 
flushColor(GrColor color)164 void GrGpuGL::flushColor(GrColor color) {
165     const ProgramDesc& desc = fCurrentProgram->getDesc();
166     const GrDrawState& drawState = this->getDrawState();
167 
168     if (this->getVertexLayout() & GrDrawState::kColor_VertexLayoutBit) {
169         // color will be specified per-vertex as an attribute
170         // invalidate the const vertex attrib color
171         fHWConstAttribColor = GrColor_ILLEGAL;
172     } else {
173         switch (desc.fColorInput) {
174             case ProgramDesc::kAttribute_ColorInput:
175                 if (fHWConstAttribColor != color) {
176                     // OpenGL ES only supports the float varieties of glVertexAttrib
177                     GrGLfloat c[4];
178                     GrColorToRGBAFloat(color, c);
179                     GL_CALL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
180                     fHWConstAttribColor = color;
181                 }
182                 break;
183             case ProgramDesc::kUniform_ColorInput:
184                 if (fCurrentProgram->fColor != color) {
185                     // OpenGL ES doesn't support unsigned byte varieties of glUniform
186                     GrGLfloat c[4];
187                     GrColorToRGBAFloat(color, c);
188                     GrAssert(kInvalidUniformHandle !=  fCurrentProgram->fUniformHandles.fColorUni);
189                     fCurrentProgram->fUniformManager.set4fv(
190                                                         fCurrentProgram->fUniformHandles.fColorUni,
191                                                         0, 1, c);
192                     fCurrentProgram->fColor = color;
193                 }
194                 break;
195             case ProgramDesc::kSolidWhite_ColorInput:
196             case ProgramDesc::kTransBlack_ColorInput:
197                 break;
198             default:
199                 GrCrash("Unknown color type.");
200         }
201     }
202     UniformHandle filterColorUni = fCurrentProgram->fUniformHandles.fColorFilterUni;
203     if (kInvalidUniformHandle != filterColorUni &&
204         fCurrentProgram->fColorFilterColor != drawState.getColorFilterColor()) {
205         GrGLfloat c[4];
206         GrColorToRGBAFloat(drawState.getColorFilterColor(), c);
207         fCurrentProgram->fUniformManager.set4fv(filterColorUni, 0, 1, c);
208         fCurrentProgram->fColorFilterColor = drawState.getColorFilterColor();
209     }
210 }
211 
flushCoverage(GrColor coverage)212 void GrGpuGL::flushCoverage(GrColor coverage) {
213     const ProgramDesc& desc = fCurrentProgram->getDesc();
214     // const GrDrawState& drawState = this->getDrawState();
215 
216 
217     if (this->getVertexLayout() & GrDrawState::kCoverage_VertexLayoutBit) {
218         // coverage will be specified per-vertex as an attribute
219         // invalidate the const vertex attrib coverage
220         fHWConstAttribCoverage = GrColor_ILLEGAL;
221     } else {
222         switch (desc.fCoverageInput) {
223             case ProgramDesc::kAttribute_ColorInput:
224                 if (fHWConstAttribCoverage != coverage) {
225                     // OpenGL ES only supports the float varieties of
226                     // glVertexAttrib
227                     GrGLfloat c[4];
228                     GrColorToRGBAFloat(coverage, c);
229                     GL_CALL(VertexAttrib4fv(GrGLProgram::CoverageAttributeIdx(),
230                                             c));
231                     fHWConstAttribCoverage = coverage;
232                 }
233                 break;
234             case ProgramDesc::kUniform_ColorInput:
235                 if (fCurrentProgram->fCoverage != coverage) {
236                     // OpenGL ES doesn't support unsigned byte varieties of
237                     // glUniform
238                     GrGLfloat c[4];
239                     GrColorToRGBAFloat(coverage, c);
240                     GrAssert(kInvalidUniformHandle !=
241                              fCurrentProgram->fUniformHandles.fCoverageUni);
242                     fCurrentProgram->fUniformManager.set4fv(
243                                                     fCurrentProgram->fUniformHandles.fCoverageUni,
244                                                     0, 1, c);
245                     fCurrentProgram->fCoverage = coverage;
246                 }
247                 break;
248             case ProgramDesc::kSolidWhite_ColorInput:
249             case ProgramDesc::kTransBlack_ColorInput:
250                 break;
251             default:
252                 GrCrash("Unknown coverage type.");
253         }
254     }
255 }
256 
flushGraphicsState(DrawType type)257 bool GrGpuGL::flushGraphicsState(DrawType type) {
258     const GrDrawState& drawState = this->getDrawState();
259 
260     // GrGpu::setupClipAndFlushState should have already checked this
261     // and bailed if not true.
262     GrAssert(NULL != drawState.getRenderTarget());
263 
264     if (kStencilPath_DrawType != type) {
265         this->flushMiscFixedFunctionState();
266 
267         GrBlendCoeff srcCoeff;
268         GrBlendCoeff dstCoeff;
269         BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff);
270         if (kSkipDraw_BlendOptFlag & blendOpts) {
271             return false;
272         }
273 
274         const GrEffectStage* stages[GrDrawState::kNumStages];
275         for (int i = 0; i < GrDrawState::kNumStages; ++i) {
276             stages[i] = drawState.isStageEnabled(i) ? &drawState.getStage(i) : NULL;
277         }
278         GrGLProgram::Desc desc;
279         this->buildProgram(kDrawPoints_DrawType == type, blendOpts, dstCoeff, &desc);
280 
281         fCurrentProgram.reset(fProgramCache->getProgram(desc, stages));
282         if (NULL == fCurrentProgram.get()) {
283             GrAssert(!"Failed to create program!");
284             return false;
285         }
286         fCurrentProgram.get()->ref();
287 
288         if (fHWProgramID != fCurrentProgram->fProgramID) {
289             GL_CALL(UseProgram(fCurrentProgram->fProgramID));
290             fHWProgramID = fCurrentProgram->fProgramID;
291         }
292         fCurrentProgram->overrideBlend(&srcCoeff, &dstCoeff);
293         this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff);
294 
295         GrColor color;
296         GrColor coverage;
297         if (blendOpts & kEmitTransBlack_BlendOptFlag) {
298             color = 0;
299             coverage = 0;
300         } else if (blendOpts & kEmitCoverage_BlendOptFlag) {
301             color = 0xffffffff;
302             coverage = drawState.getCoverage();
303         } else {
304             color = drawState.getColor();
305             coverage = drawState.getCoverage();
306         }
307         this->flushColor(color);
308         this->flushCoverage(coverage);
309 
310         fCurrentProgram->setData(this);
311     }
312     this->flushStencil(type);
313     this->flushViewMatrix(type);
314     this->flushScissor();
315     this->flushAAState(type);
316 
317     GrIRect* devRect = NULL;
318     GrIRect devClipBounds;
319     if (drawState.isClipState()) {
320         this->getClip()->getConservativeBounds(drawState.getRenderTarget(), &devClipBounds);
321         devRect = &devClipBounds;
322     }
323     // This must come after textures are flushed because a texture may need
324     // to be msaa-resolved (which will modify bound FBO state).
325     this->flushRenderTarget(devRect);
326 
327     return true;
328 }
329 
330 #if GR_TEXT_SCALAR_IS_USHORT
331     #define TEXT_COORDS_GL_TYPE          GR_GL_UNSIGNED_SHORT
332     #define TEXT_COORDS_ARE_NORMALIZED   1
333 #elif GR_TEXT_SCALAR_IS_FLOAT
334     #define TEXT_COORDS_GL_TYPE          GR_GL_FLOAT
335     #define TEXT_COORDS_ARE_NORMALIZED   0
336 #elif GR_TEXT_SCALAR_IS_FIXED
337     #define TEXT_COORDS_GL_TYPE          GR_GL_FIXED
338     #define TEXT_COORDS_ARE_NORMALIZED   0
339 #else
340     #error "unknown GR_TEXT_SCALAR type"
341 #endif
342 
setupGeometry(const DrawInfo & info,int * startIndexOffset)343 void GrGpuGL::setupGeometry(const DrawInfo& info, int* startIndexOffset) {
344 
345     int newColorOffset;
346     int newCoverageOffset;
347     int newTexCoordOffsets[GrDrawState::kMaxTexCoords];
348     int newEdgeOffset;
349 
350     GrVertexLayout currLayout = this->getVertexLayout();
351 
352     GrGLsizei newStride = GrDrawState::VertexSizeAndOffsetsByIdx(currLayout,
353                                                                  newTexCoordOffsets,
354                                                                  &newColorOffset,
355                                                                  &newCoverageOffset,
356                                                                  &newEdgeOffset);
357     int oldColorOffset;
358     int oldCoverageOffset;
359     int oldTexCoordOffsets[GrDrawState::kMaxTexCoords];
360     int oldEdgeOffset;
361 
362     GrGLsizei oldStride = GrDrawState::VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
363                                                                  oldTexCoordOffsets,
364                                                                  &oldColorOffset,
365                                                                  &oldCoverageOffset,
366                                                                  &oldEdgeOffset);
367 
368     int extraVertexOffset;
369     this->setBuffers(info.isIndexed(), &extraVertexOffset, startIndexOffset);
370 
371     GrGLenum scalarType;
372     bool texCoordNorm;
373     if (currLayout & GrDrawState::kTextFormat_VertexLayoutBit) {
374         scalarType = TEXT_COORDS_GL_TYPE;
375         texCoordNorm = SkToBool(TEXT_COORDS_ARE_NORMALIZED);
376     } else {
377         scalarType = GR_GL_FLOAT;
378         texCoordNorm = false;
379     }
380 
381     size_t vertexOffset = (info.startVertex() + extraVertexOffset) * newStride;
382 
383     // all the Pointers must be set if any of these are true
384     bool allOffsetsChange =  fHWGeometryState.fArrayPtrsDirty ||
385                              vertexOffset != fHWGeometryState.fVertexOffset ||
386                              newStride != oldStride;
387 
388     // position and tex coord offsets change if above conditions are true
389     // or the type/normalization changed based on text vs nontext type coords.
390     bool posAndTexChange = allOffsetsChange ||
391                            (((TEXT_COORDS_GL_TYPE != GR_GL_FLOAT) || TEXT_COORDS_ARE_NORMALIZED) &&
392                                 (GrDrawState::kTextFormat_VertexLayoutBit &
393                                   (fHWGeometryState.fVertexLayout ^ currLayout)));
394 
395     if (posAndTexChange) {
396         int idx = GrGLProgram::PositionAttributeIdx();
397         GL_CALL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
398                                   (GrGLvoid*)vertexOffset));
399         fHWGeometryState.fVertexOffset = vertexOffset;
400     }
401 
402     for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
403         if (newTexCoordOffsets[t] > 0) {
404             GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
405             int idx = GrGLProgram::TexCoordAttributeIdx(t);
406             if (oldTexCoordOffsets[t] <= 0) {
407                 GL_CALL(EnableVertexAttribArray(idx));
408                 GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
409                                           newStride, texCoordOffset));
410             } else if (posAndTexChange ||
411                        newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
412                 GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
413                                           newStride, texCoordOffset));
414             }
415         } else if (oldTexCoordOffsets[t] > 0) {
416             GL_CALL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
417         }
418     }
419 
420     if (newColorOffset > 0) {
421         GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
422         int idx = GrGLProgram::ColorAttributeIdx();
423         if (oldColorOffset <= 0) {
424             GL_CALL(EnableVertexAttribArray(idx));
425             GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
426                                       true, newStride, colorOffset));
427         } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
428             GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
429                                       true, newStride, colorOffset));
430         }
431     } else if (oldColorOffset > 0) {
432         GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
433     }
434 
435     if (newCoverageOffset > 0) {
436         GrGLvoid* coverageOffset = (int8_t*)(vertexOffset + newCoverageOffset);
437         int idx = GrGLProgram::CoverageAttributeIdx();
438         if (oldCoverageOffset <= 0) {
439             GL_CALL(EnableVertexAttribArray(idx));
440             GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
441                                         true, newStride, coverageOffset));
442         } else if (allOffsetsChange || newCoverageOffset != oldCoverageOffset) {
443             GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
444                                         true, newStride, coverageOffset));
445         }
446     } else if (oldCoverageOffset > 0) {
447         GL_CALL(DisableVertexAttribArray(GrGLProgram::CoverageAttributeIdx()));
448     }
449 
450     if (newEdgeOffset > 0) {
451         GrGLvoid* edgeOffset = (int8_t*)(vertexOffset + newEdgeOffset);
452         int idx = GrGLProgram::EdgeAttributeIdx();
453         if (oldEdgeOffset <= 0) {
454             GL_CALL(EnableVertexAttribArray(idx));
455             GL_CALL(VertexAttribPointer(idx, 4, scalarType,
456                                         false, newStride, edgeOffset));
457         } else if (allOffsetsChange || newEdgeOffset != oldEdgeOffset) {
458             GL_CALL(VertexAttribPointer(idx, 4, scalarType,
459                                         false, newStride, edgeOffset));
460         }
461     } else if (oldEdgeOffset > 0) {
462         GL_CALL(DisableVertexAttribArray(GrGLProgram::EdgeAttributeIdx()));
463     }
464 
465     fHWGeometryState.fVertexLayout = currLayout;
466     fHWGeometryState.fArrayPtrsDirty = false;
467 }
468 
buildProgram(bool isPoints,BlendOptFlags blendOpts,GrBlendCoeff dstCoeff,ProgramDesc * desc)469 void GrGpuGL::buildProgram(bool isPoints,
470                            BlendOptFlags blendOpts,
471                            GrBlendCoeff dstCoeff,
472                            ProgramDesc* desc) {
473     const GrDrawState& drawState = this->getDrawState();
474 
475     // This should already have been caught
476     GrAssert(!(kSkipDraw_BlendOptFlag & blendOpts));
477 
478     bool skipCoverage = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
479 
480     bool skipColor = SkToBool(blendOpts & (kEmitTransBlack_BlendOptFlag |
481                                            kEmitCoverage_BlendOptFlag));
482 
483     // The descriptor is used as a cache key. Thus when a field of the
484     // descriptor will not affect program generation (because of the vertex
485     // layout in use or other descriptor field settings) it should be set
486     // to a canonical value to avoid duplicate programs with different keys.
487 
488     // Must initialize all fields or cache will have false negatives!
489     desc->fVertexLayout = this->getVertexLayout();
490 
491     desc->fEmitsPointSize = isPoints;
492 
493     bool requiresAttributeColors = !skipColor &&
494                                    SkToBool(desc->fVertexLayout & GrDrawState::kColor_VertexLayoutBit);
495     bool requiresAttributeCoverage = !skipCoverage &&
496                                      SkToBool(desc->fVertexLayout & GrDrawState::kCoverage_VertexLayoutBit);
497 
498     // fColorInput/fCoverageInput records how colors are specified for the.
499     // program. So we strip the bits from the layout to avoid false negatives
500     // when searching for an existing program in the cache.
501     desc->fVertexLayout &= ~(GrDrawState::kColor_VertexLayoutBit | GrDrawState::kCoverage_VertexLayoutBit);
502 
503     desc->fColorFilterXfermode = skipColor ?
504                                 SkXfermode::kDst_Mode :
505                                 drawState.getColorFilterMode();
506 
507     // no reason to do edge aa or look at per-vertex coverage if coverage is
508     // ignored
509     if (skipCoverage) {
510         desc->fVertexLayout &= ~(GrDrawState::kEdge_VertexLayoutBit | GrDrawState::kCoverage_VertexLayoutBit);
511     }
512 
513     bool colorIsTransBlack = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
514     bool colorIsSolidWhite = (blendOpts & kEmitCoverage_BlendOptFlag) ||
515                              (!requiresAttributeColors && 0xffffffff == drawState.getColor());
516     if (GR_AGGRESSIVE_SHADER_OPTS && colorIsTransBlack) {
517         desc->fColorInput = ProgramDesc::kTransBlack_ColorInput;
518     } else if (GR_AGGRESSIVE_SHADER_OPTS && colorIsSolidWhite) {
519         desc->fColorInput = ProgramDesc::kSolidWhite_ColorInput;
520     } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) {
521         desc->fColorInput = ProgramDesc::kUniform_ColorInput;
522     } else {
523         desc->fColorInput = ProgramDesc::kAttribute_ColorInput;
524     }
525 
526     bool covIsSolidWhite = !requiresAttributeCoverage && 0xffffffff == drawState.getCoverage();
527 
528     if (skipCoverage) {
529         desc->fCoverageInput = ProgramDesc::kTransBlack_ColorInput;
530     } else if (covIsSolidWhite) {
531         desc->fCoverageInput = ProgramDesc::kSolidWhite_ColorInput;
532     } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeCoverage) {
533         desc->fCoverageInput = ProgramDesc::kUniform_ColorInput;
534     } else {
535         desc->fCoverageInput = ProgramDesc::kAttribute_ColorInput;
536     }
537 
538     int lastEnabledStage = -1;
539 
540     if (!skipCoverage && (desc->fVertexLayout &GrDrawState::kEdge_VertexLayoutBit)) {
541         desc->fVertexEdgeType = drawState.getVertexEdgeType();
542         desc->fDiscardIfOutsideEdge = drawState.getStencil().doesWrite();
543     } else {
544         // Use canonical values when edge-aa is not enabled to avoid program cache misses.
545         desc->fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
546         desc->fDiscardIfOutsideEdge = false;
547     }
548 
549     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
550 
551         bool skip = s < drawState.getFirstCoverageStage() ? skipColor : skipCoverage;
552         if (!skip && drawState.isStageEnabled(s)) {
553             lastEnabledStage = s;
554             const GrEffectRef& effect = *drawState.getStage(s).getEffect();
555             const GrBackendEffectFactory& factory = effect->getFactory();
556             desc->fEffectKeys[s] = factory.glEffectKey(drawState.getStage(s), this->glCaps());
557         } else {
558             desc->fEffectKeys[s] = 0;
559         }
560     }
561 
562     desc->fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
563 
564     // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
565     // other than pass through values from the VS to the FS anyway).
566 #if 0 && GR_GL_EXPERIMENTAL_GS
567     desc->fExperimentalGS = this->getCaps().fGeometryShaderSupport;
568 #endif
569 
570     // We want to avoid generating programs with different "first cov stage" values when they would
571     // compute the same result. We set field in the desc to kNumStages when either there are no
572     // coverage stages or the distinction between coverage and color is immaterial.
573     int firstCoverageStage = GrDrawState::kNumStages;
574     desc->fFirstCoverageStage = GrDrawState::kNumStages;
575     bool hasCoverage = drawState.getFirstCoverageStage() <= lastEnabledStage;
576     if (hasCoverage) {
577         firstCoverageStage = drawState.getFirstCoverageStage();
578     }
579 
580     // other coverage inputs
581     if (!hasCoverage) {
582         hasCoverage = requiresAttributeCoverage ||
583                       (desc->fVertexLayout & GrDrawState::kEdge_VertexLayoutBit);
584     }
585 
586     if (hasCoverage) {
587         // color filter is applied between color/coverage computation
588         if (SkXfermode::kDst_Mode != desc->fColorFilterXfermode) {
589             desc->fFirstCoverageStage = firstCoverageStage;
590         }
591 
592         if (this->getCaps().dualSourceBlendingSupport() &&
593             !(blendOpts & (kEmitCoverage_BlendOptFlag | kCoverageAsAlpha_BlendOptFlag))) {
594             if (kZero_GrBlendCoeff == dstCoeff) {
595                 // write the coverage value to second color
596                 desc->fDualSrcOutput =  ProgramDesc::kCoverage_DualSrcOutput;
597                 desc->fFirstCoverageStage = firstCoverageStage;
598             } else if (kSA_GrBlendCoeff == dstCoeff) {
599                 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
600                 desc->fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput;
601                 desc->fFirstCoverageStage = firstCoverageStage;
602             } else if (kSC_GrBlendCoeff == dstCoeff) {
603                 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
604                 desc->fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput;
605                 desc->fFirstCoverageStage = firstCoverageStage;
606             }
607         }
608     }
609 }
610