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; |
} |
+ |