Ejemplo n.º 1
0
void GrGLProgramDesc::Build(const GrDrawState& drawState,
                            bool isPoints,
                            GrDrawState::BlendOptFlags blendOpts,
                            GrBlendCoeff srcCoeff,
                            GrBlendCoeff dstCoeff,
                            const GrGpuGL* gpu,
                            const GrDeviceCoordTexture* dstCopy,
                            GrGLProgramDesc* desc) {

    // This should already have been caught
    GrAssert(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));

    bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);

    bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
                                           GrDrawState::kEmitCoverage_BlendOptFlag));

    // The descriptor is used as a cache key. Thus when a field of the
    // descriptor will not affect program generation (because of the attribute
    // bindings in use or other descriptor field settings) it should be set
    // to a canonical value to avoid duplicate programs with different keys.


    desc->fEmitsPointSize = isPoints;

    bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
    bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
    // we only need the local coords if we're actually going to generate effect code
    bool requiresLocalCoordAttrib = !(skipCoverage  && skipColor) &&
                                    drawState.hasLocalCoordAttribute();

    // fColorInput/fCoverageInput records how colors are specified for the program so we strip the
    // bits from the bindings to avoid false negatives when searching for an existing program in the
    // cache.

    desc->fColorFilterXfermode = skipColor ? SkXfermode::kDst_Mode : drawState.getColorFilterMode();


    bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
    bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
                             (!requiresColorAttrib && 0xffffffff == drawState.getColor());
    if (colorIsTransBlack) {
        desc->fColorInput = kTransBlack_ColorInput;
    } else if (colorIsSolidWhite) {
        desc->fColorInput = kSolidWhite_ColorInput;
    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresColorAttrib) {
        desc->fColorInput = kUniform_ColorInput;
    } else {
        desc->fColorInput = kAttribute_ColorInput;
    }

    bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverage();

    if (skipCoverage) {
        desc->fCoverageInput = kTransBlack_ColorInput;
    } else if (covIsSolidWhite) {
        desc->fCoverageInput = kSolidWhite_ColorInput;
    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresCoverageAttrib) {
        desc->fCoverageInput = kUniform_ColorInput;
    } else {
        desc->fCoverageInput = kAttribute_ColorInput;
    }

    bool readsDst = false;
    int lastEnabledStage = -1;

    for (int s = 0; s < GrDrawState::kNumStages; ++s) {

        bool skip = s < drawState.getFirstCoverageStage() ? skipColor : skipCoverage;
        if (!skip && drawState.isStageEnabled(s)) {
            lastEnabledStage = s;
            const GrEffectRef& effect = *drawState.getStage(s).getEffect();
            const GrBackendEffectFactory& factory = effect->getFactory();
            GrDrawEffect drawEffect(drawState.getStage(s), requiresLocalCoordAttrib);
            desc->fEffectKeys[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
            if (effect->willReadDst()) {
                readsDst = true;
            }
        } else {
            desc->fEffectKeys[s] = 0;
        }
    }

    if (readsDst) {
        GrAssert(NULL != dstCopy);
        desc->fDstRead = GrGLShaderBuilder::KeyForDstRead(dstCopy->texture(), gpu->glCaps());
        GrAssert(0 != desc->fDstRead);
    } else {
        desc->fDstRead = 0;
    }

    desc->fCoverageOutput = kModulate_CoverageOutput;

    // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
    // other than pass through values from the VS to the FS anyway).
#if GR_GL_EXPERIMENTAL_GS
#if 0
    desc->fExperimentalGS = gpu->caps().geometryShaderSupport();
#else
    desc->fExperimentalGS = false;
#endif
#endif

    // We leave this set to kNumStages until we discover that the coverage/color distinction is
    // material to the generated program. We do this to avoid distinct keys that generate equivalent
    // programs.
    desc->fFirstCoverageStage = GrDrawState::kNumStages;
    // This tracks the actual first coverage stage.
    int firstCoverageStage = GrDrawState::kNumStages;
    desc->fDiscardIfZeroCoverage = false; // Enabled below if stenciling and there is coverage.
    bool hasCoverage = false;
    // If we're rendering coverage-as-color then it's as though there are no coverage stages.
    if (!drawState.isCoverageDrawing()) {
        // We can have coverage either through a stage or coverage vertex attributes.
        if (drawState.getFirstCoverageStage() <= lastEnabledStage) {
            firstCoverageStage = drawState.getFirstCoverageStage();
            hasCoverage = true;
        } else {
            hasCoverage = requiresCoverageAttrib;
        }
    }

    if (hasCoverage) {
        // color filter is applied between color/coverage computation
        if (SkXfermode::kDst_Mode != desc->fColorFilterXfermode) {
            desc->fFirstCoverageStage = firstCoverageStage;
        }

        // If we're stenciling then we want to discard samples that have zero coverage
        if (drawState.getStencil().doesWrite()) {
            desc->fDiscardIfZeroCoverage = true;
            desc->fFirstCoverageStage = firstCoverageStage;
        }

        if (gpu->caps()->dualSourceBlendingSupport() &&
            !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
                           GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
            if (kZero_GrBlendCoeff == dstCoeff) {
                // write the coverage value to second color
                desc->fCoverageOutput =  kSecondaryCoverage_CoverageOutput;
                desc->fFirstCoverageStage = firstCoverageStage;
            } else if (kSA_GrBlendCoeff == dstCoeff) {
                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
                desc->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
                desc->fFirstCoverageStage = firstCoverageStage;
            } else if (kSC_GrBlendCoeff == dstCoeff) {
                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
                desc->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
                desc->fFirstCoverageStage = firstCoverageStage;
            }
        } else if (readsDst &&
                   kOne_GrBlendCoeff == drawState.getSrcBlendCoeff() &&
                   kZero_GrBlendCoeff == drawState.getDstBlendCoeff()) {
            desc->fCoverageOutput = kCombineWithDst_CoverageOutput;
            desc->fFirstCoverageStage = firstCoverageStage;
        }
    }

    desc->fPositionAttributeIndex = drawState.positionAttributeIndex();
    desc->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();

    // For constant color and coverage we need an attribute with an index beyond those already set
    int availableAttributeIndex = drawState.getVertexAttribCount();
    if (requiresColorAttrib) {
        desc->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
    } else if (GrGLProgramDesc::kAttribute_ColorInput == desc->fColorInput) {
        GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
        desc->fColorAttributeIndex = availableAttributeIndex;
        availableAttributeIndex++;
    } else {
        desc->fColorAttributeIndex = -1;
    }

    if (requiresCoverageAttrib) {
        desc->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
    } else if (GrGLProgramDesc::kAttribute_ColorInput == desc->fCoverageInput) {
        GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
        desc->fCoverageAttributeIndex = availableAttributeIndex;
    } else {
        desc->fCoverageAttributeIndex = -1;
    }
}
Ejemplo n.º 2
0
void GrGLProgramDesc::Build(const GrDrawState& drawState,
                            bool isPoints,
                            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) {
    colorStages->reset();
    coverageStages->reset();

    // This should already have been caught
    SkASSERT(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));

    bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);

    bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
                                           GrDrawState::kEmitCoverage_BlendOptFlag));
    int firstEffectiveColorStage = 0;
    bool inputColorIsUsed = true;
    if (!skipColor) {
        firstEffectiveColorStage = drawState.numColorStages();
        while (firstEffectiveColorStage > 0 && inputColorIsUsed) {
            --firstEffectiveColorStage;
            const GrEffect* effect = drawState.getColorStage(firstEffectiveColorStage).getEffect()->get();
            inputColorIsUsed = effect->willUseInputColor();
        }
    }

    int firstEffectiveCoverageStage = 0;
    bool inputCoverageIsUsed = true;
    if (!skipCoverage) {
        firstEffectiveCoverageStage = drawState.numCoverageStages();
        while (firstEffectiveCoverageStage > 0 && inputCoverageIsUsed) {
            --firstEffectiveCoverageStage;
            const GrEffect* effect = drawState.getCoverageStage(firstEffectiveCoverageStage).getEffect()->get();
            inputCoverageIsUsed = effect->willUseInputColor();
        }
    }

    // The descriptor is used as a cache key. Thus when a field of the
    // descriptor will not affect program generation (because of the attribute
    // bindings in use or other descriptor field settings) it should be set
    // to a canonical value to avoid duplicate programs with different keys.

    bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
    bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
    // we only need the local coords if we're actually going to generate effect code
    bool requiresLocalCoordAttrib = !(skipCoverage  && skipColor) &&
                                    drawState.hasLocalCoordAttribute();

    bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
    bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
                             (!requiresColorAttrib && 0xffffffff == drawState.getColor()) ||
                             (!inputColorIsUsed);

    int numEffects = (skipColor ? 0 : (drawState.numColorStages() - firstEffectiveColorStage)) +
                     (skipCoverage ? 0 : (drawState.numCoverageStages() - firstEffectiveCoverageStage));

    size_t newKeyLength = KeyLength(numEffects);
    bool allocChanged;
    desc->fKey.reset(newKeyLength, SkAutoMalloc::kAlloc_OnShrink, &allocChanged);
    if (allocChanged || !desc->fInitialized) {
        // make sure any padding in the header is zero if we we haven't used this allocation before.
        memset(desc->header(), 0, kHeaderSize);
    }
    // write the key length
    *desc->atOffset<uint32_t, kLengthOffset>() = SkToU32(newKeyLength);

    KeyHeader* header = desc->header();
    EffectKey* effectKeys = desc->effectKeys();

    int currEffectKey = 0;
    bool readsDst = false;
    bool readFragPosition = false;
    bool hasVertexCode = false;
    if (!skipColor) {
        for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
            effectKeys[currEffectKey++] =
                get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
                                         requiresLocalCoordAttrib, &readsDst, &readFragPosition,
                                         &hasVertexCode);
        }
    }
    if (!skipCoverage) {
        for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
            effectKeys[currEffectKey++] =
                get_key_and_update_stats(drawState.getCoverageStage(s), gpu->glCaps(),
                                         requiresLocalCoordAttrib, &readsDst, &readFragPosition,
                                         &hasVertexCode);
        }
    }

    header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib;
    header->fEmitsPointSize = isPoints;

    // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
    // other than pass through values from the VS to the FS anyway).
#if GR_GL_EXPERIMENTAL_GS
#if 0
    header->fExperimentalGS = gpu->caps().geometryShaderSupport();
#else
    header->fExperimentalGS = false;
#endif
#endif
    bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport();

    if (colorIsTransBlack) {
        header->fColorInput = kTransBlack_ColorInput;
    } else if (colorIsSolidWhite) {
        header->fColorInput = kSolidWhite_ColorInput;
    } else if (defaultToUniformInputs && !requiresColorAttrib) {
        header->fColorInput = kUniform_ColorInput;
    } else {
        header->fColorInput = kAttribute_ColorInput;
        header->fHasVertexCode = true;
    }

    bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverageColor();

    if (skipCoverage) {
        header->fCoverageInput = kTransBlack_ColorInput;
    } else if (covIsSolidWhite || !inputCoverageIsUsed) {
        header->fCoverageInput = kSolidWhite_ColorInput;
    } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
        header->fCoverageInput = kUniform_ColorInput;
    } else {
        header->fCoverageInput = kAttribute_ColorInput;
        header->fHasVertexCode = true;
    }

    if (readsDst) {
        SkASSERT(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
        const GrTexture* dstCopyTexture = NULL;
        if (NULL != dstCopy) {
            dstCopyTexture = dstCopy->texture();
        }
        header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
        SkASSERT(0 != header->fDstReadKey);
    } else {
        header->fDstReadKey = 0;
    }

    if (readFragPosition) {
        header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
                                                                      gpu->glCaps());
    } else {
        header->fFragPosKey = 0;
    }

    // Record attribute indices
    header->fPositionAttributeIndex = drawState.positionAttributeIndex();
    header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();

    // For constant color and coverage we need an attribute with an index beyond those already set
    int availableAttributeIndex = drawState.getVertexAttribCount();
    if (requiresColorAttrib) {
        header->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
    } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
        SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
        header->fColorAttributeIndex = availableAttributeIndex;
        availableAttributeIndex++;
    } else {
        header->fColorAttributeIndex = -1;
    }

    if (requiresCoverageAttrib) {
        header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
    } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
        SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
        header->fCoverageAttributeIndex = availableAttributeIndex;
    } else {
        header->fCoverageAttributeIndex = -1;
    }

    // Here we deal with whether/how we handle color and coverage separately.

    // Set this default and then possibly change our mind if there is coverage.
    header->fCoverageOutput = kModulate_CoverageOutput;

    // If we do have coverage determine whether it matters.
    bool separateCoverageFromColor = false;
    if (!drawState.isCoverageDrawing() && !skipCoverage &&
        (drawState.numCoverageStages() > 0 || requiresCoverageAttrib)) {

        if (gpu->caps()->dualSourceBlendingSupport() &&
            !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
                           GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
            if (kZero_GrBlendCoeff == dstCoeff) {
                // write the coverage value to second color
                header->fCoverageOutput =  kSecondaryCoverage_CoverageOutput;
                separateCoverageFromColor = true;
            } else if (kSA_GrBlendCoeff == dstCoeff) {
                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
                header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
                separateCoverageFromColor = true;
            } else if (kSC_GrBlendCoeff == dstCoeff) {
                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
                header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
                separateCoverageFromColor = true;
            }
        } else if (readsDst &&
                   kOne_GrBlendCoeff == srcCoeff &&
                   kZero_GrBlendCoeff == dstCoeff) {
            header->fCoverageOutput = kCombineWithDst_CoverageOutput;
            separateCoverageFromColor = true;
        }
    }
    if (!skipColor) {
        for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
            colorStages->push_back(&drawState.getColorStage(s));
        }
    }
    if (!skipCoverage) {
        SkTArray<const GrEffectStage*, true>* array;
        if (separateCoverageFromColor) {
            array = coverageStages;
        } else {
            array = colorStages;
        }
        for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
            array->push_back(&drawState.getCoverageStage(s));
        }
    }
    header->fColorEffectCnt = colorStages->count();
    header->fCoverageEffectCnt = coverageStages->count();

    *desc->checksum() = 0;
    *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()),
                                            newKeyLength);
    desc->fInitialized = true;
}
Ejemplo n.º 3
0
bool GrGLProgramDesc::Build(const GrDrawState& drawState,
                            GrGpu::DrawType drawType,
                            GrDrawState::BlendOptFlags blendOpts,
                            GrBlendCoeff srcCoeff,
                            GrBlendCoeff dstCoeff,
                            const GrGpuGL* gpu,
                            const GrDeviceCoordTexture* dstCopy,
                            const GrEffectStage** geometryProcessor,
                            SkTArray<const GrEffectStage*, true>* colorStages,
                            SkTArray<const GrEffectStage*, true>* coverageStages,
                            GrGLProgramDesc* desc) {
    colorStages->reset();
    coverageStages->reset();

    // This should already have been caught
    SkASSERT(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));

    bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);

    bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
                                           GrDrawState::kEmitCoverage_BlendOptFlag));

    int firstEffectiveColorStage = 0;
    bool inputColorIsUsed = true;

    if (!skipColor) {
        firstEffectiveColorStage = drawState.numColorStages();
        while (firstEffectiveColorStage > 0 && inputColorIsUsed) {
            --firstEffectiveColorStage;
            const GrEffect* effect = drawState.getColorStage(firstEffectiveColorStage).getEffect();
            inputColorIsUsed = effect->willUseInputColor();
        }
    }

    int firstEffectiveCoverageStage = 0;
    bool inputCoverageIsUsed = true;
    if (!skipCoverage) {
        firstEffectiveCoverageStage = drawState.numCoverageStages();
        while (firstEffectiveCoverageStage > 0 && inputCoverageIsUsed) {
            --firstEffectiveCoverageStage;
            const GrEffect* effect = drawState.getCoverageStage(firstEffectiveCoverageStage).getEffect();
            inputCoverageIsUsed = effect->willUseInputColor();
        }
    }

    // The descriptor is used as a cache key. Thus when a field of the
    // descriptor will not affect program generation (because of the attribute
    // bindings in use or other descriptor field settings) it should be set
    // to a canonical value to avoid duplicate programs with different keys.

    bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
    bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
    // we only need the local coords if we're actually going to generate effect code
    bool requiresLocalCoordAttrib = !(skipCoverage  && skipColor) &&
                                    drawState.hasLocalCoordAttribute();

    bool readsDst = false;
    bool readFragPosition = false;

    // Provide option for shader programs without vertex shader only when drawing paths.
    bool requiresVertexShader = !GrGpu::IsPathRenderingDrawType(drawType);

    int numStages = 0;
    if (drawState.hasGeometryProcessor()) {
        numStages++;
    }
    if (!skipColor) {
        numStages += drawState.numColorStages() - firstEffectiveColorStage;
    }
    if (!skipCoverage) {
        numStages += drawState.numCoverageStages() - firstEffectiveCoverageStage;
    }
    GR_STATIC_ASSERT(0 == kEffectKeyOffsetsAndLengthOffset % sizeof(uint32_t));
    // Make room for everything up to and including the array of offsets to effect keys.
    desc->fKey.reset();
    desc->fKey.push_back_n(kEffectKeyOffsetsAndLengthOffset + 2 * sizeof(uint16_t) * numStages);

    int offsetAndSizeIndex = 0;
    bool effectKeySuccess = true;

    KeyHeader* header = desc->header();
    // make sure any padding in the header is zeroed.
    memset(desc->header(), 0, kHeaderSize);

    // We can only have one effect which touches the vertex shader
    if (drawState.hasGeometryProcessor()) {
        uint16_t* offsetAndSize =
                reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
                                            offsetAndSizeIndex * 2 * sizeof(uint16_t));

            GrEffectKeyBuilder b(&desc->fKey);
            uint16_t effectKeySize;
            uint32_t effectOffset = desc->fKey.count();
            effectKeySuccess |= GetEffectKeyAndUpdateStats(
                                    *drawState.getGeometryProcessor(), gpu->glCaps(),
                                    requiresLocalCoordAttrib, &b,
                                    &effectKeySize, &readsDst,
                                    &readFragPosition, &requiresVertexShader);
            effectKeySuccess |= (effectOffset <= SK_MaxU16);

            offsetAndSize[0] = SkToU16(effectOffset);
            offsetAndSize[1] = effectKeySize;
            ++offsetAndSizeIndex;
            *geometryProcessor = drawState.getGeometryProcessor();
            SkASSERT(requiresVertexShader);
            header->fHasGeometryProcessor = true;
    }

    if (!skipColor) {
        for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
            uint16_t* offsetAndSize =
                reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
                                            offsetAndSizeIndex * 2 * sizeof(uint16_t));

            bool effectRequiresVertexShader = false;
            GrEffectKeyBuilder b(&desc->fKey);
            uint16_t effectKeySize;
            uint32_t effectOffset = desc->fKey.count();
            effectKeySuccess |= GetEffectKeyAndUpdateStats(
                                    drawState.getColorStage(s), gpu->glCaps(),
                                    requiresLocalCoordAttrib, &b,
                                    &effectKeySize, &readsDst,
                                    &readFragPosition, &effectRequiresVertexShader);
            effectKeySuccess |= (effectOffset <= SK_MaxU16);

            offsetAndSize[0] = SkToU16(effectOffset);
            offsetAndSize[1] = effectKeySize;
            ++offsetAndSizeIndex;
            SkASSERT(!effectRequiresVertexShader);
        }
    }
    if (!skipCoverage) {
        for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
            uint16_t* offsetAndSize =
                reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
                                            offsetAndSizeIndex * 2 * sizeof(uint16_t));

            bool effectRequiresVertexShader = false;
            GrEffectKeyBuilder b(&desc->fKey);
            uint16_t effectKeySize;
            uint32_t effectOffset = desc->fKey.count();
            effectKeySuccess |= GetEffectKeyAndUpdateStats(
                                    drawState.getCoverageStage(s), gpu->glCaps(),
                                    requiresLocalCoordAttrib, &b,
                                    &effectKeySize, &readsDst,
                                    &readFragPosition, &effectRequiresVertexShader);
            effectKeySuccess |= (effectOffset <= SK_MaxU16);

            offsetAndSize[0] = SkToU16(effectOffset);
            offsetAndSize[1] = effectKeySize;
            ++offsetAndSizeIndex;
            SkASSERT(!effectRequiresVertexShader);
        }
    }
    if (!effectKeySuccess) {
        desc->fKey.reset();
        return false;
    }

    // Because header is a pointer into the dynamic array, we can't push any new data into the key
    // below here.

    header->fRequiresVertexShader = requiresVertexShader || requiresLocalCoordAttrib;
    header->fEmitsPointSize = GrGpu::kDrawPoints_DrawType == drawType;

    // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
    // other than pass through values from the VS to the FS anyway).
#if GR_GL_EXPERIMENTAL_GS
#if 0
    header->fExperimentalGS = gpu->caps().geometryShaderSupport();
#else
    header->fExperimentalGS = false;
#endif
#endif
    bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport();

    if (!inputColorIsUsed && !skipColor) {
        header->fColorInput = kAllOnes_ColorInput;
    } else if (defaultToUniformInputs && !requiresColorAttrib && inputColorIsUsed) {
        header->fColorInput = kUniform_ColorInput;
    } else {
        header->fColorInput = kAttribute_ColorInput;
        header->fRequiresVertexShader = true;
    }

    bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverageColor();

    if ((covIsSolidWhite || !inputCoverageIsUsed) && !skipCoverage) {
        header->fCoverageInput = kAllOnes_ColorInput;
    } else if (defaultToUniformInputs && !requiresCoverageAttrib && inputCoverageIsUsed) {
        header->fCoverageInput = kUniform_ColorInput;
    } else {
        header->fCoverageInput = kAttribute_ColorInput;
        header->fRequiresVertexShader = true;
    }

    if (readsDst) {
        SkASSERT(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
        const GrTexture* dstCopyTexture = NULL;
        if (NULL != dstCopy) {
            dstCopyTexture = dstCopy->texture();
        }
        header->fDstReadKey = GrGLFragmentShaderBuilder::KeyForDstRead(dstCopyTexture,
                gpu->glCaps());
        SkASSERT(0 != header->fDstReadKey);
    } else {
        header->fDstReadKey = 0;
    }

    if (readFragPosition) {
        header->fFragPosKey = GrGLFragmentShaderBuilder::KeyForFragmentPosition(
                drawState.getRenderTarget(), gpu->glCaps());
    } else {
        header->fFragPosKey = 0;
    }

    // Record attribute indices
    header->fPositionAttributeIndex = drawState.positionAttributeIndex();
    header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();

    // For constant color and coverage we need an attribute with an index beyond those already set
    int availableAttributeIndex = drawState.getVertexAttribCount();
    if (requiresColorAttrib) {
        header->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
    } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
        SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
        header->fColorAttributeIndex = availableAttributeIndex;
        availableAttributeIndex++;
    } else {
        header->fColorAttributeIndex = -1;
    }

    if (requiresCoverageAttrib) {
        header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
    } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
        SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
        header->fCoverageAttributeIndex = availableAttributeIndex;
    } else {
        header->fCoverageAttributeIndex = -1;
    }

    // Here we deal with whether/how we handle color and coverage separately.

    // Set this default and then possibly change our mind if there is coverage.
    header->fCoverageOutput = kModulate_CoverageOutput;

    // If we do have coverage determine whether it matters.
    bool separateCoverageFromColor = drawState.hasGeometryProcessor();
    if (!drawState.isCoverageDrawing() && !skipCoverage &&
        (drawState.numCoverageStages() > 0 ||
         drawState.hasGeometryProcessor() ||
         requiresCoverageAttrib)) {

        if (gpu->caps()->dualSourceBlendingSupport() &&
            !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
                           GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
            if (kZero_GrBlendCoeff == dstCoeff) {
                // write the coverage value to second color
                header->fCoverageOutput =  kSecondaryCoverage_CoverageOutput;
                separateCoverageFromColor = true;
            } else if (kSA_GrBlendCoeff == dstCoeff) {
                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
                header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
                separateCoverageFromColor = true;
            } else if (kSC_GrBlendCoeff == dstCoeff) {
                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
                header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
                separateCoverageFromColor = true;
            }
        } else if (readsDst &&
                   kOne_GrBlendCoeff == srcCoeff &&
                   kZero_GrBlendCoeff == dstCoeff) {
            header->fCoverageOutput = kCombineWithDst_CoverageOutput;
            separateCoverageFromColor = true;
        }
    }

    if (!skipColor) {
        for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
            colorStages->push_back(&drawState.getColorStage(s));
        }
    }
    if (!skipCoverage) {
        SkTArray<const GrEffectStage*, true>* array;
        if (separateCoverageFromColor) {
            array = coverageStages;
        } else {
            array = colorStages;
        }
        for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
            array->push_back(&drawState.getCoverageStage(s));
        }
    }
    header->fColorEffectCnt = colorStages->count();
    header->fCoverageEffectCnt = coverageStages->count();

    desc->finalize();
    return true;
}