| Index: src/gpu/gl/GrGLProgramDesc.cpp
|
| diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
|
| index e8812fade79d743cb30146ec858ff7d1b01a18fc..276f9b5a09ea6b3e8a94078c531efebb63ec0e97 100644
|
| --- a/src/gpu/gl/GrGLProgramDesc.cpp
|
| +++ b/src/gpu/gl/GrGLProgramDesc.cpp
|
| @@ -12,6 +12,8 @@
|
| #include "GrGLShaderBuilder.h"
|
| #include "GrGpuGL.h"
|
|
|
| +#include "SkChecksum.h"
|
| +
|
| void GrGLProgramDesc::Build(const GrDrawState& drawState,
|
| bool isPoints,
|
| GrDrawState::BlendOptFlags blendOpts,
|
| @@ -19,8 +21,8 @@ void GrGLProgramDesc::Build(const GrDrawState& drawState,
|
| GrBlendCoeff dstCoeff,
|
| const GrGpuGL* gpu,
|
| const GrDeviceCoordTexture* dstCopy,
|
| + const GrEffectStage* stages[],
|
| GrGLProgramDesc* desc) {
|
| -
|
| // This should already have been caught
|
| GrAssert(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
|
|
|
| @@ -34,131 +36,169 @@ void GrGLProgramDesc::Build(const GrDrawState& drawState,
|
| // 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();
|
| + // Do an initial loop over the stages to count them. We count the color and coverage effects
|
| + // separately here. Later we may decide the distinction doesn't matter and will count all
|
| + // effects as color in desc. Two things will allow simplication of this mess: GrDrawState will
|
| + // have tight lists of color and coverage stages rather than a fixed size array with NULLS and
|
| + // the xfermode-color filter will be removed.
|
| + int colorEffectCnt = 0;
|
| + int coverageEffectCnt = 0;
|
| + if (!skipColor) {
|
| + for (int s = 0; s < drawState.getFirstCoverageStage(); ++s) {
|
| + if (drawState.isStageEnabled(s)) {
|
| + stages[colorEffectCnt] = &drawState.getStage(s);
|
| + ++colorEffectCnt;
|
| + }
|
| + }
|
| + }
|
| + if (!skipCoverage) {
|
| + for (int s = drawState.getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) {
|
| + if (drawState.isStageEnabled(s)) {
|
| + stages[colorEffectCnt + coverageEffectCnt] = &drawState.getStage(s);
|
| + ++coverageEffectCnt;
|
| + }
|
| + }
|
| + }
|
|
|
| - 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;
|
| + size_t newKeyLength = KeyLength(colorEffectCnt + coverageEffectCnt);
|
| + 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>() = newKeyLength;
|
| +
|
| + KeyHeader* header = desc->header();
|
| + EffectKey* effectKeys = desc->effectKeys();
|
|
|
| + int currEffectKey = 0;
|
| bool readsDst = false;
|
| bool readFragPosition = 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());
|
| + effectKeys[currEffectKey] = factory.glEffectKey(drawEffect, gpu->glCaps());
|
| + ++currEffectKey;
|
| if (effect->willReadDstColor()) {
|
| readsDst = true;
|
| }
|
| if (effect->willReadFragmentPosition()) {
|
| readFragPosition = true;
|
| }
|
| - } else {
|
| - desc->fEffectKeys[s] = 0;
|
| }
|
| }
|
|
|
| + header->fEmitsPointSize = isPoints;
|
| + header->fColorFilterXfermode = skipColor ? SkXfermode::kDst_Mode : drawState.getColorFilterMode();
|
| +
|
| + // 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
|
| + if (colorIsTransBlack) {
|
| + header->fColorInput = kTransBlack_ColorInput;
|
| + } else if (colorIsSolidWhite) {
|
| + header->fColorInput = kSolidWhite_ColorInput;
|
| + } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresColorAttrib) {
|
| + header->fColorInput = kUniform_ColorInput;
|
| + } else {
|
| + header->fColorInput = kAttribute_ColorInput;
|
| + }
|
| +
|
| + bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverage();
|
| +
|
| + if (skipCoverage) {
|
| + header->fCoverageInput = kTransBlack_ColorInput;
|
| + } else if (covIsSolidWhite) {
|
| + header->fCoverageInput = kSolidWhite_ColorInput;
|
| + } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresCoverageAttrib) {
|
| + header->fCoverageInput = kUniform_ColorInput;
|
| + } else {
|
| + header->fCoverageInput = kAttribute_ColorInput;
|
| + }
|
| +
|
| if (readsDst) {
|
| GrAssert(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
|
| const GrTexture* dstCopyTexture = NULL;
|
| if (NULL != dstCopy) {
|
| dstCopyTexture = dstCopy->texture();
|
| }
|
| - desc->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
|
| - GrAssert(0 != desc->fDstReadKey);
|
| + header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
|
| + GrAssert(0 != header->fDstReadKey);
|
| } else {
|
| - desc->fDstReadKey = 0;
|
| + header->fDstReadKey = 0;
|
| }
|
|
|
| if (readFragPosition) {
|
| - desc->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
|
| + header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
|
| gpu->glCaps());
|
| } else {
|
| - desc->fFragPosKey = 0;
|
| + header->fFragPosKey = 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;
|
| - }
|
| + // 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) {
|
| + GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
|
| + header->fColorAttributeIndex = availableAttributeIndex;
|
| + availableAttributeIndex++;
|
| + } else {
|
| + header->fColorAttributeIndex = -1;
|
| + }
|
| +
|
| + if (requiresCoverageAttrib) {
|
| + header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
|
| + } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
|
| + GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
|
| + header->fCoverageAttributeIndex = availableAttributeIndex;
|
| + } else {
|
| + header->fCoverageAttributeIndex = -1;
|
| }
|
|
|
| - if (hasCoverage) {
|
| + // Here we deal with whether/how we handle color and coverage separately.
|
| +
|
| + // Set these defaults and then possibly change our mind if there is coverage.
|
| + header->fDiscardIfZeroCoverage = false;
|
| + header->fCoverageOutput = kModulate_CoverageOutput;
|
| +
|
| + // If we do have coverage determine whether it matters.
|
| + bool separateCoverageFromColor = false;
|
| + if (!drawState.isCoverageDrawing() && (coverageEffectCnt > 0 || requiresCoverageAttrib)) {
|
| // color filter is applied between color/coverage computation
|
| - if (SkXfermode::kDst_Mode != desc->fColorFilterXfermode) {
|
| - desc->fFirstCoverageStage = firstCoverageStage;
|
| + if (SkXfermode::kDst_Mode != header->fColorFilterXfermode) {
|
| + separateCoverageFromColor = true;
|
| }
|
|
|
| // If we're stenciling then we want to discard samples that have zero coverage
|
| if (drawState.getStencil().doesWrite()) {
|
| - desc->fDiscardIfZeroCoverage = true;
|
| - desc->fFirstCoverageStage = firstCoverageStage;
|
| + header->fDiscardIfZeroCoverage = true;
|
| + separateCoverageFromColor = true;
|
| }
|
|
|
| if (gpu->caps()->dualSourceBlendingSupport() &&
|
| @@ -166,46 +206,45 @@ void GrGLProgramDesc::Build(const GrDrawState& drawState,
|
| GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
|
| if (kZero_GrBlendCoeff == dstCoeff) {
|
| // write the coverage value to second color
|
| - desc->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
|
| - desc->fFirstCoverageStage = firstCoverageStage;
|
| + header->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
|
| + separateCoverageFromColor = true;
|
| } 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;
|
| + header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
|
| + separateCoverageFromColor = true;
|
| } 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;
|
| + header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
|
| + separateCoverageFromColor = true;
|
| }
|
| } else if (readsDst &&
|
| kOne_GrBlendCoeff == srcCoeff &&
|
| kZero_GrBlendCoeff == dstCoeff) {
|
| - desc->fCoverageOutput = kCombineWithDst_CoverageOutput;
|
| - desc->fFirstCoverageStage = firstCoverageStage;
|
| + header->fCoverageOutput = kCombineWithDst_CoverageOutput;
|
| + separateCoverageFromColor = true;
|
| }
|
| }
|
| -
|
| - 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++;
|
| + if (separateCoverageFromColor) {
|
| + header->fColorEffectCnt = colorEffectCnt;
|
| + header->fCoverageEffectCnt = coverageEffectCnt;
|
| } else {
|
| - desc->fColorAttributeIndex = -1;
|
| + header->fColorEffectCnt = colorEffectCnt + coverageEffectCnt;
|
| + header->fCoverageEffectCnt = 0;
|
| }
|
|
|
| - if (requiresCoverageAttrib) {
|
| - desc->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
|
| - } else if (GrGLProgramDesc::kAttribute_ColorInput == desc->fCoverageInput) {
|
| - GrAssert(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
|
| - desc->fCoverageAttributeIndex = availableAttributeIndex;
|
| - } else {
|
| - desc->fCoverageAttributeIndex = -1;
|
| + *desc->checksum() = 0;
|
| + *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()),
|
| + newKeyLength);
|
| + desc->fInitialized = true;
|
| +}
|
| +
|
| +GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
|
| + fInitialized = other.fInitialized;
|
| + if (fInitialized) {
|
| + size_t keyLength = other.keyLength();
|
| + fKey.reset(keyLength);
|
| + memcpy(fKey.get(), other.fKey.get(), keyLength);
|
| }
|
| + return *this;
|
| }
|
| +
|
|
|