Chromium Code Reviews| Index: src/gpu/gl/GrGLProgramDesc.cpp |
| diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp |
| index e8812fade79d743cb30146ec858ff7d1b01a18fc..53a911073c267bfb586888d4bbf74ecbd09dc036 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,170 @@ 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); |
| + void* oldKey = desc->fKey.get(); |
| + void* newKey = desc->fKey.reset(newKeyLength); |
|
robertphillips
2013/05/21 19:22:37
Does oldKey survive reset?
bsalomon
2013/05/22 14:11:25
I just wanted to check whether reset() actually al
|
| + if (oldKey != newKey || !desc->fInitialized) { |
| + // make sure any padding in the header is zero if we malloc'ed or if we haven't used this |
| + // allocation before. |
| + memset(desc->header(), 0, kHeaderSize); |
| } |
| + // write the key length |
|
robertphillips
2013/05/21 19:22:37
reset doesn't do this?
bsalomon
2013/05/22 14:11:25
reset() was called on an SkAutoSMalloc.
|
| + *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 +207,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; |
| } |
|
robertphillips
2013/05/21 19:22:37
Do we need the first clear to 0?
bsalomon
2013/05/22 14:11:25
Yeah, the memory where the checksum will live is a
|
| - 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; |
| } |
| + |