void GrGLProgram::setColor(const GrDrawState& drawState, GrColor color, SharedGLState* sharedState) { const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); if (!drawState.hasColorVertexAttribute() || drawState.canIgnoreColorAttribute()) { switch (header.fColorInput) { case GrGLProgramDesc::kAttribute_ColorInput: SkASSERT(-1 != header.fColorAttributeIndex); if (sharedState->fConstAttribColor != color || sharedState->fConstAttribColorIndex != header.fColorAttributeIndex) { // OpenGL ES only supports the float varieties of glVertexAttrib GrGLfloat c[4]; GrColorToRGBAFloat(color, c); GL_CALL(VertexAttrib4fv(header.fColorAttributeIndex, c)); sharedState->fConstAttribColor = color; sharedState->fConstAttribColorIndex = header.fColorAttributeIndex; } break; case GrGLProgramDesc::kUniform_ColorInput: if (fColor != color && fBuilderOutput.fUniformHandles.fColorUni.isValid()) { // OpenGL ES doesn't support unsigned byte varieties of glUniform GrGLfloat c[4]; GrColorToRGBAFloat(color, c); fUniformManager->set4fv(fBuilderOutput.fUniformHandles.fColorUni, 1, c); fColor = color; } sharedState->fConstAttribColorIndex = -1; break; default: SkFAIL("Unexpected color type."); } } else { sharedState->fConstAttribColorIndex = -1; } }
GrDrawState::CombinedState GrDrawState::CombineIfPossible( const GrDrawState& a, const GrDrawState& b, const GrDrawTargetCaps& caps) { if (!a.isEqual(b)) { return kIncompatible_CombinedState; } // If the general draw states are equal (from check above) we know hasColorVertexAttribute() // is equivalent for both a and b if (a.hasColorVertexAttribute()) { // If one is opaque and the other is not then the combined state is not opaque. Moreover, // if the opaqueness affects the ability to get color/coverage blending correct then we // don't combine the draw states. bool aIsOpaque = (kVertexColorsAreOpaque_Hint & a.fHints); bool bIsOpaque = (kVertexColorsAreOpaque_Hint & b.fHints); if (aIsOpaque != bIsOpaque) { const GrDrawState* opaque; const GrDrawState* nonOpaque; if (aIsOpaque) { opaque = &a; nonOpaque = &b; } else { opaque = &b; nonOpaque = &a; } if (!opaque->hasSolidCoverage() && opaque->couldApplyCoverage(caps)) { SkASSERT(!nonOpaque->hasSolidCoverage()); if (!nonOpaque->couldApplyCoverage(caps)) { return kIncompatible_CombinedState; } } return aIsOpaque ? kB_CombinedState : kA_CombinedState; } } return kAOrB_CombinedState; }
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; }
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; } }
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; }
void GrDistanceFieldTextContext::flush() { if (NULL == fDrawTarget) { return; } if (fCurrVertex > 0) { GrDrawState drawState; drawState.setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget()); bool useColorVerts = !fUseLCDText; set_vertex_attributes(&drawState, useColorVerts); // setup our sampler state for our text texture/atlas SkASSERT(SkIsAlign4(fCurrVertex)); // get our current color SkColor filteredColor; SkColorFilter* colorFilter = fSkPaint.getColorFilter(); if (colorFilter) { filteredColor = colorFilter->filterColor(fSkPaint.getColor()); } else { filteredColor = fSkPaint.getColor(); } this->setupCoverageEffect(filteredColor); // Effects could be stored with one of the cache objects (atlas?) drawState.setGeometryProcessor(fCachedGeometryProcessor.get()); // Set draw state if (fUseLCDText) { GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor); if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() || kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() || fPaint.numColorStages()) { SkDebugf("LCD Text will not draw correctly.\n"); } SkASSERT(!drawState.hasColorVertexAttribute()); // We don't use the GrPaint's color in this case because it's been premultiplied by // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by // the mask texture color. The end result is that we get // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor int a = SkColorGetA(fSkPaint.getColor()); // paintAlpha drawState.setColor(SkColorSetARGB(a, a, a, a)); // paintColor drawState.setBlendConstant(colorNoPreMul); drawState.setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff); } else { if (0xFF == GrColorUnpackA(fPaint.getColor())) { drawState.setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true); } // set back to normal in case we took LCD path previously. drawState.setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff()); // We're using per-vertex color. SkASSERT(drawState.hasColorVertexAttribute()); } int nGlyphs = fCurrVertex / kVerticesPerGlyph; fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); fDrawTarget->drawIndexedInstances(&drawState, kTriangles_GrPrimitiveType, nGlyphs, kVerticesPerGlyph, kIndicesPerGlyph, &fVertexBounds); fDrawTarget->resetVertexSource(); fVertices = NULL; fTotalVertexCount -= fCurrVertex; fCurrVertex = 0; SkSafeSetNull(fCurrTexture); fVertexBounds.setLargestInverted(); } }
void GrBitmapTextContext::flushGlyphs() { if (NULL == fDrawTarget) { return; } GrDrawState* drawState = fDrawTarget->drawState(); GrDrawState::AutoRestoreEffects are(drawState); drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget()); if (fCurrVertex > 0) { // setup our sampler state for our text texture/atlas SkASSERT(SkIsAlign4(fCurrVertex)); SkASSERT(fCurrTexture); GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode); uint32_t textureUniqueID = fCurrTexture->getUniqueID(); if (textureUniqueID != fEffectTextureUniqueID) { fCachedEffect.reset(GrCustomCoordsTextureEffect::Create(fCurrTexture, params)); fEffectTextureUniqueID = textureUniqueID; } // This effect could be stored with one of the cache objects (atlas?) int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex : kGlyphCoordsNoColorAttributeIndex; drawState->addCoverageEffect(fCachedEffect.get(), coordsIdx); SkASSERT(NULL != fStrike); switch (fStrike->getMaskFormat()) { // Color bitmap text case kARGB_GrMaskFormat: SkASSERT(!drawState->hasColorVertexAttribute()); drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff()); drawState->setColor(0xffffffff); break; // LCD text case kA888_GrMaskFormat: case kA565_GrMaskFormat: { if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() || kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() || fPaint.numColorStages()) { GrPrintf("LCD Text will not draw correctly.\n"); } SkASSERT(!drawState->hasColorVertexAttribute()); // We don't use the GrPaint's color in this case because it's been premultiplied by // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by // the mask texture color. The end result is that we get // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor int a = SkColorGetA(fSkPaint.getColor()); // paintAlpha drawState->setColor(SkColorSetARGB(a, a, a, a)); // paintColor drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor())); drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff); break; } // Grayscale/BW text case kA8_GrMaskFormat: // set back to normal in case we took LCD path previously. drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff()); // We're using per-vertex color. SkASSERT(drawState->hasColorVertexAttribute()); break; default: SkFAIL("Unexepected mask format."); } int nGlyphs = fCurrVertex / 4; fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType, nGlyphs, 4, 6, &fVertexBounds); fDrawTarget->resetVertexSource(); fVertices = NULL; fMaxVertices = 0; fCurrVertex = 0; fVertexBounds.setLargestInverted(); SkSafeSetNull(fCurrTexture); } }