GrXferProcessor::OptFlags
PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
                                            const GrProcOptInfo& coveragePOI,
                                            bool doesStencilWrite,
                                            GrColor* overrideColor,
                                            const GrCaps& caps) {
    GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
    if (!fBlendFormula.modifiesDst()) {
        if (!doesStencilWrite) {
            optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
        }
        optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
                     GrXferProcessor::kIgnoreCoverage_OptFlag |
                     GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
    } else {
        if (!fBlendFormula.usesInputColor()) {
            optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
        }
        if (coveragePOI.isSolidWhite()) {
            optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
        }
        if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForCoverage()) {
            optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
        }
    }
    return optFlags;
}
Пример #2
0
GrXferProcessor::OptFlags CustomXP::onGetOptimizations(const GrProcOptInfo& colorPOI,
                                                       const GrProcOptInfo& coveragePOI,
                                                       bool doesStencilWrite,
                                                       GrColor* overrideColor,
                                                       const GrCaps& caps) {
  /*
    Most the optimizations we do here are based on tweaking alpha for coverage.

    The general SVG blend equation is defined in the spec as follows:

      Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa)
      Da'  = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa)

    (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha,
     and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied
     RGB colors.)

    For every blend mode supported by this class, i.e. the "advanced" blend
    modes, X=Y=Z=1 and this equation reduces to the PDF blend equation.

    It can be shown that when X=Y=Z=1, these equations can modulate alpha for
    coverage.


    == Color ==

    We substitute Y=Z=1 and define a blend() function that calculates Dca' in
    terms of premultiplied alpha only:

      blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0,
                                 Sca : if Da == 0,
                                 B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if Sa,Da != 0}

    And for coverage modulation, we use a post blend src-over model:

      Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca

    (Where f is the fractional coverage.)

    Next we show that canTweakAlphaForCoverage() is true by proving the
    following relationship:

      blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca

    General case (f,Sa,Da != 0):

      f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
        = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca  [Sa,Da != 0, definition of blend()]
        = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca
        = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca
        = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca
        = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca
        = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)
        = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)  [f!=0]
        = blend(f*Sca, Dca, f*Sa, Da)  [definition of blend()]

    Corner cases (Sa=0, Da=0, and f=0):

      Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
              = f * Dca + (1-f) * Dca  [Sa=0, definition of blend()]
              = Dca
              = blend(0, Dca, 0, Da)  [definition of blend()]
              = blend(f*Sca, Dca, f*Sa, Da)  [Sa=0]

      Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
              = f * Sca + (1-f) * Dca  [Da=0, definition of blend()]
              = f * Sca  [Da=0]
              = blend(f*Sca, 0, f*Sa, 0)  [definition of blend()]
              = blend(f*Sca, Dca, f*Sa, Da)  [Da=0]

      f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
             = Dca  [f=0]
             = blend(0, Dca, 0, Da)  [definition of blend()]
             = blend(f*Sca, Dca, f*Sa, Da)  [f=0]

    == Alpha ==

    We substitute X=Y=Z=1 and define a blend() function that calculates Da':

      blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa)
                    = Sa * Da + Sa - Sa * Da + Da - Da * Sa
                    = Sa + Da - Sa * Da

    We use the same model for coverage modulation as we did with color:

      Da'' = f * blend(Sa, Da) + (1-f) * Da

    And show that canTweakAlphaForCoverage() is true by proving the following
    relationship:

      blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da


      f * blend(Sa, Da) + (1-f) * Da
        = f * (Sa + Da - Sa * Da) + (1-f) * Da
        = f*Sa + f*Da - f*Sa * Da + Da - f*Da
        = f*Sa - f*Sa * Da + Da
        = f*Sa + Da - f*Sa * Da
        = blend(f*Sa, Da)
   */

    OptFlags flags = kNone_OptFlags;
    if (colorPOI.allStagesMultiplyInput()) {
        flags |= kCanTweakAlphaForCoverage_OptFlag;
    }
    if (this->hasHWBlendEquation() && coveragePOI.isSolidWhite()) {
        flags |= kIgnoreCoverage_OptFlag;
    }
    return flags;
}
Пример #3
0
GrXferProcessor::OptFlags
PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI,
                                                  const GrProcOptInfo& coveragePOI,
                                                  bool doesStencilWrite) {
    if (this->willReadDstColor()) {
        return GrXferProcessor::kNone_Opt;
    }

    bool srcAIsOne = colorPOI.isOpaque();
    bool hasCoverage = !coveragePOI.isSolidWhite();

    bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
                         (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
    bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
                         (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);

    // When coeffs are (0,1) there is no reason to draw at all, unless
    // stenciling is enabled. Having color writes disabled is effectively
    // (0,1).
    if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
        if (doesStencilWrite) {
            return GrXferProcessor::kIgnoreColor_OptFlag |
                   GrXferProcessor::kSetCoverageDrawing_OptFlag;
        } else {
            fDstBlend = kOne_GrBlendCoeff;
            return GrXferProcessor::kSkipDraw_OptFlag;
        }
    }

    // if we don't have coverage we can check whether the dst
    // has to read at all. If not, we'll disable blending.
    if (!hasCoverage) {
        if (dstCoeffIsZero) {
            if (kOne_GrBlendCoeff == fSrcBlend) {
                // if there is no coverage and coeffs are (1,0) then we
                // won't need to read the dst at all, it gets replaced by src
                fDstBlend = kZero_GrBlendCoeff;
                return GrXferProcessor::kNone_Opt;
            } else if (kZero_GrBlendCoeff == fSrcBlend) {
                // if the op is "clear" then we don't need to emit a color
                // or blend, just write transparent black into the dst.
                fSrcBlend = kOne_GrBlendCoeff;
                fDstBlend = kZero_GrBlendCoeff;
                return GrXferProcessor::kIgnoreColor_OptFlag |
                       GrXferProcessor::kIgnoreCoverage_OptFlag;
            }
        }
    }  else {
        // check whether coverage can be safely rolled into alpha
        // of if we can skip color computation and just emit coverage
        if (can_tweak_alpha_for_coverage(fDstBlend)) {
            if (colorPOI.allStagesMultiplyInput()) {
                return GrXferProcessor::kSetCoverageDrawing_OptFlag |
                       GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
            } else {
                return GrXferProcessor::kSetCoverageDrawing_OptFlag;

            }
        }
        if (dstCoeffIsZero) {
            if (kZero_GrBlendCoeff == fSrcBlend) {
                // the source color is not included in the blend
                // the dst coeff is effectively zero so blend works out to:
                // (c)(0)D + (1-c)D = (1-c)D.
                fDstBlend = kISA_GrBlendCoeff;
                return GrXferProcessor::kIgnoreColor_OptFlag |
                       GrXferProcessor::kSetCoverageDrawing_OptFlag;
            } else if (srcAIsOne) {
                // the dst coeff is effectively zero so blend works out to:
                // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
                // If Sa is 1 then we can replace Sa with c
                // and set dst coeff to 1-Sa.
                fDstBlend = kISA_GrBlendCoeff;
                if (colorPOI.allStagesMultiplyInput()) {
                    return GrXferProcessor::kSetCoverageDrawing_OptFlag |
                           GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
                } else {
                    return GrXferProcessor::kSetCoverageDrawing_OptFlag;

                }
            }
        } else if (dstCoeffIsOne) {
            // the dst coeff is effectively one so blend works out to:
            // cS + (c)(1)D + (1-c)D = cS + D.
            fDstBlend = kOne_GrBlendCoeff;
            if (colorPOI.allStagesMultiplyInput()) {
                return GrXferProcessor::kSetCoverageDrawing_OptFlag |
                       GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
            } else {
                return GrXferProcessor::kSetCoverageDrawing_OptFlag;

            }
            return GrXferProcessor::kSetCoverageDrawing_OptFlag;
        }
    }

    return GrXferProcessor::kNone_Opt;
}