From 8d95ffa497091d0c9c7cda099684c7bca6714a17 Mon Sep 17 00:00:00 2001 From: egdaniel Date: Mon, 8 Dec 2014 13:26:43 -0800 Subject: [PATCH] Revert of Make all blending up to GrOptDrawState be handled by the xp/xp factory. (patchset #7 id:140001 of https://codereview.chromium.org/759713002/) Reason for revert: break many gm's Original issue's description: > Make all blending up to GrOptDrawState be handled by the xp/xp factory. > > In this cl the blending information is extracted for the xp and stored in the ODS > which is then used as it currently is. In the follow up cl, an XP backend will be added > and at that point all blending work will take place inside XP's. > > BUG=skia: > > Committed: https://skia.googlesource.com/skia/+/7c66342a399b529634bed0fabfaa562db2c0dbd4 TBR=bsalomon@google.com NOTREECHECKS=true NOTRY=true BUG=skia: Review URL: https://codereview.chromium.org/766653008 --- gm/texdata.cpp | 6 +- include/core/SkXfermode.h | 4 +- include/gpu/GrPaint.h | 32 +- include/gpu/GrXferProcessor.h | 111 +------ .../gpu/effects/GrPorterDuffXferProcessor.h | 50 +-- src/core/SkXfermode.cpp | 19 +- src/effects/SkAlphaThresholdFilter.cpp | 3 +- src/effects/SkBlurMaskFilter.cpp | 7 +- src/gpu/GrBitmapTextContext.cpp | 13 + src/gpu/GrClipMaskManager.cpp | 18 +- src/gpu/GrDistanceFieldTextContext.cpp | 14 + src/gpu/GrDrawState.cpp | 171 ++++++++-- src/gpu/GrDrawState.h | 109 +++++-- src/gpu/GrOptDrawState.cpp | 144 +++++---- src/gpu/GrOptDrawState.h | 18 +- src/gpu/GrPaint.cpp | 60 +++- src/gpu/GrProcOptInfo.cpp | 20 +- src/gpu/GrProcOptInfo.h | 11 +- src/gpu/SkGpuDevice.cpp | 3 +- src/gpu/SkGr.cpp | 11 +- src/gpu/effects/GrPorterDuffXferProcessor.cpp | 300 +----------------- tests/GLProgramsTest.cpp | 5 +- 22 files changed, 499 insertions(+), 630 deletions(-) diff --git a/gm/texdata.cpp b/gm/texdata.cpp index 56dfd24ed0..efe8c4d730 100644 --- a/gm/texdata.cpp +++ b/gm/texdata.cpp @@ -12,9 +12,8 @@ #if SK_SUPPORT_GPU #include "GrContext.h" -#include "SkColorPriv.h" -#include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrSimpleTextureEffect.h" +#include "SkColorPriv.h" namespace skiagm { @@ -99,8 +98,7 @@ protected: ctx->setRenderTarget(target); GrPaint paint; - paint.setPorterDuffXPFactory(SkXfermode::kSrcOver_Mode); - + paint.setBlendFunc(kOne_GrBlendCoeff, kISA_GrBlendCoeff); SkMatrix vm; if (i) { vm.setRotate(90 * SK_Scalar1, diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h index 05fd81152a..35e9837483 100644 --- a/include/core/SkXfermode.h +++ b/include/core/SkXfermode.h @@ -217,10 +217,10 @@ public: or a fragment processor. This helper calls the asCoeff(), asXPFactory(), and asFragmentProcessor() virtuals. If the xfermode is NULL, it is treated as kSrcOver_Mode. It is legal to call this with all params NULL to simply test the return value. - fp and xpf must both be NULL or all non-NULL. + fp, xpf, src, and dst must all be NULL or all non-NULL. */ static bool AsFragmentProcessorOrXPFactory(SkXfermode*, GrFragmentProcessor**, - GrXPFactory**); + GrXPFactory**, Coeff* src, Coeff* dst); SK_TO_STRING_PUREVIRT() SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() diff --git a/include/gpu/GrPaint.h b/include/gpu/GrPaint.h index 49b95b8449..f31830bb2b 100644 --- a/include/gpu/GrPaint.h +++ b/include/gpu/GrPaint.h @@ -13,7 +13,6 @@ #include "GrColor.h" #include "GrFragmentStage.h" #include "GrXferProcessor.h" -#include "effects/GrPorterDuffXferProcessor.h" #include "SkXfermode.h" @@ -51,6 +50,17 @@ public: ~GrPaint() {} + /** + * Sets the blending coefficients to use to blend the final primitive color with the + * destination color. Defaults to kOne for src and kZero for dst (i.e. src mode). + */ + void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) { + fSrcBlendCoeff = srcCoeff; + fDstBlendCoeff = dstCoeff; + } + GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlendCoeff; } + GrBlendCoeff getDstBlendCoeff() const { return fDstBlendCoeff; } + /** * The initial color of the drawn primitive. Defaults to solid white. */ @@ -74,14 +84,6 @@ public: return xpFactory; } - void setPorterDuffXPFactory(SkXfermode::Mode mode) { - fXPFactory.reset(GrPorterDuffXPFactory::Create(mode)); - } - - void setPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst) { - fXPFactory.reset(GrPorterDuffXPFactory::Create(src, dst)); - } - /** * Appends an additional color processor to the color computation. */ @@ -119,6 +121,8 @@ public: const GrFragmentStage& getCoverageStage(int s) const { return fCoverageStages[s]; } GrPaint& operator=(const GrPaint& paint) { + fSrcBlendCoeff = paint.fSrcBlendCoeff; + fDstBlendCoeff = paint.fDstBlendCoeff; fAntiAlias = paint.fAntiAlias; fDither = paint.fDither; @@ -136,6 +140,7 @@ public: * Resets the paint to the defaults. */ void reset() { + this->resetBlend(); this->resetOptions(); this->resetColor(); this->resetStages(); @@ -206,11 +211,18 @@ private: SkSTArray<4, GrFragmentStage> fColorStages; SkSTArray<2, GrFragmentStage> fCoverageStages; + GrBlendCoeff fSrcBlendCoeff; + GrBlendCoeff fDstBlendCoeff; bool fAntiAlias; bool fDither; GrColor fColor; + void resetBlend() { + fSrcBlendCoeff = kOne_GrBlendCoeff; + fDstBlendCoeff = kZero_GrBlendCoeff; + } + void resetOptions() { fAntiAlias = false; fDither = false; @@ -220,7 +232,7 @@ private: fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff); } - void resetStages(); + void resetStages(); }; #endif diff --git a/include/gpu/GrXferProcessor.h b/include/gpu/GrXferProcessor.h index b7d0bdd9fa..10ecf54c75 100644 --- a/include/gpu/GrXferProcessor.h +++ b/include/gpu/GrXferProcessor.h @@ -13,8 +13,6 @@ #include "GrTypes.h" #include "SkXfermode.h" -class GrProcOptInfo; - /** * GrXferProcessor is responsible for implementing the xfer mode that blends the src color and dst * color. It does this by emitting fragment shader code and controlling the fixed-function blend @@ -29,83 +27,11 @@ class GrProcOptInfo; * GrXPFactory once we have finalized the state of our draw. */ class GrXferProcessor : public GrFragmentProcessor { -public: - /** - * Optimizations for blending / coverage that an OptDrawState should apply to itself. - */ - enum OptFlags { - /** - * No optimizations needed - */ - kNone_Opt = 0, - /** - * The draw can be skipped completely. - */ - kSkipDraw_OptFlag = 0x1, - /** - * Clear color stages, remove color vertex attribs, and use input color - */ - kClearColorStages_OptFlag = 0x2, - /** - * Clear coverage stages, remove coverage vertex attribs, and use input coverage - */ - kClearCoverageStages_OptFlag = 0x4, - /** - * Set CoverageDrawing_StateBit - */ - kSetCoverageDrawing_OptFlag = 0x8, - }; - - GR_DECL_BITFIELD_OPS_FRIENDS(OptFlags); - - /** - * Determines which optimizations (as described by the ptFlags above) can be performed by - * the draw with this xfer processor. If this function is called, the xfer processor may change - * its state to reflected the given blend optimizations. It will also set the output parameters, - * color and coverage, to specific values if it decides to remove all color or coverage stages. - * A caller who calls this function on a XP is required to honor the returned OptFlags - * and color/coverage values for its draw. - */ - // TODO: remove need for isCoverageDrawing once coverageDrawing is its own XP. - // TODO: remove need for colorWriteDisabled once colorWriteDisabled is its own XP. - virtual OptFlags getOptimizations(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, - bool colorWriteDisabled, - bool doesStencilWrite, - GrColor* color, - uint8_t* coverage) = 0; - - struct BlendInfo { - GrBlendCoeff fSrcBlend; - GrBlendCoeff fDstBlend; - GrColor fBlendConstant; - }; - - virtual void getBlendInfo(BlendInfo* blendInfo) const = 0; - - /** Will this prceossor read the destination pixel value? */ - bool willReadDstColor() const { return fWillReadDstColor; } - -protected: - GrXferProcessor() : fWillReadDstColor(false) {} - - /** - * If the prceossor subclass will read the destination pixel value then it must call this - * function from its constructor. Otherwise, when its generated backend-specific prceossor class - * attempts to generate code that reads the destination pixel it will fail. - */ - void setWillReadDstColor() { fWillReadDstColor = true; } - private: - bool fWillReadDstColor; - typedef GrFragmentProcessor INHERITED; }; -GR_MAKE_BITFIELD_OPS(GrXferProcessor::OptFlags); - /** * We install a GrXPFactory (XPF) early on in the pipeline before all the final draw information is * known (e.g. whether there is fractional pixel coverage, will coverage be 1 or 4 channel, is the @@ -119,8 +45,7 @@ GR_MAKE_BITFIELD_OPS(GrXferProcessor::OptFlags); */ class GrXPFactory : public SkRefCnt { public: - virtual GrXferProcessor* createXferProcessor(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI) const = 0; + virtual const GrXferProcessor* createXferProcessor() const = 0; /** * This function returns true if the GrXferProcessor generated from this factory will be able to @@ -129,40 +54,6 @@ public: */ virtual bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const = 0; - /** - * Depending on color blend mode requested it may or may not be possible to correctly blend with - * fractional pixel coverage generated by the fragment shader. - * - * This function considers the known color and coverage input into the xfer processor and - * certain state information (isCoverageDrawing and colorWriteDisabled) to determine whether - * coverage can be handled correctly. - */ - // TODO: remove need for isCoverageDrawing once coverageDrawing is its own XP. - // TODO: remove need for colorWriteDisabled once colorWriteDisabled is its own XP. - virtual bool canApplyCoverage(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled) const = 0; - - /** - * This function returns true if the destination pixel values will be read for blending during - * draw. - */ - // TODO: remove need for isCoverageDrawing once coverageDrawing is its own XP. - // TODO: remove need for colorWriteDisabled once only XP can read dst. - virtual bool willBlendWithDst(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled) const = 0; - - /** - * Determines whether multiplying the computed per-pixel color by the pixel's fractional - * coverage before the blend will give the correct final destination color. In general it - * will not as coverage is applied after blending. - */ - // TODO: remove need for isCoverageDrawing once coverageDrawing is its own XP. - virtual bool canTweakAlphaForCoverage(bool isCoverageDrawing) const = 0; - - virtual bool getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, GrColor* solidColor, - uint32_t* solidColorKnownComponents) const = 0; - bool isEqual(const GrXPFactory& that) const { if (this->classID() != that.classID()) { return false; diff --git a/include/gpu/effects/GrPorterDuffXferProcessor.h b/include/gpu/effects/GrPorterDuffXferProcessor.h index 0ddfcdcd2a..9ff3bea2ed 100644 --- a/include/gpu/effects/GrPorterDuffXferProcessor.h +++ b/include/gpu/effects/GrPorterDuffXferProcessor.h @@ -17,9 +17,8 @@ class GrInvariantOutput; class GrPorterDuffXferProcessor : public GrXferProcessor { public: - static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, - GrColor constant = 0) { - return SkNEW_ARGS(GrPorterDuffXferProcessor, (srcBlend, dstBlend, constant)); + static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend) { + return SkNEW_ARGS(GrPorterDuffXferProcessor, (srcBlend, dstBlend)); } virtual ~GrPorterDuffXferProcessor(); @@ -31,28 +30,12 @@ public: virtual GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE; - virtual GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, - bool colorWriteDisabled, - bool doesStencilWrite, - GrColor* color, - uint8_t* coverage) SK_OVERRIDE; - - virtual void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const SK_OVERRIDE { - blendInfo->fSrcBlend = fSrcBlend; - blendInfo->fDstBlend = fDstBlend; - blendInfo->fBlendConstant = fBlendConstant; - } - private: - GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColor constant); + GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend); virtual bool onIsEqual(const GrFragmentProcessor& fpBase) const SK_OVERRIDE { const GrPorterDuffXferProcessor& xp = fpBase.cast(); - if (fSrcBlend != xp.fSrcBlend || - fDstBlend != xp.fDstBlend || - fBlendConstant != xp.fBlendConstant) { + if (fSrcBlend != xp.fSrcBlend || fDstBlend != xp.fDstBlend) { return false; } return true; @@ -62,8 +45,7 @@ private: GrBlendCoeff fSrcBlend; GrBlendCoeff fDstBlend; - GrColor fBlendConstant; - + typedef GrXferProcessor INHERITED; }; @@ -81,34 +63,20 @@ public: return SkNEW_ARGS(GrPorterDuffXPFactory, (src, dst)); } - GrXferProcessor* createXferProcessor(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI) const SK_OVERRIDE; + const GrXferProcessor* createXferProcessor() const SK_OVERRIDE; bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const SK_OVERRIDE; - bool canApplyCoverage(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled) const SK_OVERRIDE; - - bool willBlendWithDst(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled) const SK_OVERRIDE; - - bool canTweakAlphaForCoverage(bool isCoverageDrawing) const SK_OVERRIDE; - - bool getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - GrColor* solidColor, - uint32_t* solidColorKnownComponents) const SK_OVERRIDE; - private: GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst); bool onIsEqual(const GrXPFactory& xpfBase) const SK_OVERRIDE { const GrPorterDuffXPFactory& xpf = xpfBase.cast(); - return (fSrcCoeff == xpf.fSrcCoeff && fDstCoeff == xpf.fDstCoeff); + return (fSrc == xpf.fSrc && fDst == xpf.fDst); } - GrBlendCoeff fSrcCoeff; - GrBlendCoeff fDstCoeff; + GrBlendCoeff fSrc; + GrBlendCoeff fDst; typedef GrXPFactory INHERITED; }; diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index 004aa93afd..268d41ec1b 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -689,19 +689,25 @@ bool SkXfermode::asXPFactory(GrXPFactory**) const { bool SkXfermode::AsFragmentProcessorOrXPFactory(SkXfermode* xfermode, GrFragmentProcessor** fp, - GrXPFactory** xpf) { - Coeff src, dst; + GrXPFactory** xpf, + Coeff* src, Coeff* dst) { Mode mode; if (NULL == xfermode) { - *xpf = GrPorterDuffXPFactory::Create(kSrcOver_Mode); + SkAssertResult(ModeAsCoeff(kSrcOver_Mode, src, dst)); + *xpf = GrPorterDuffXPFactory::Create(*src, *dst); return true; } else if (xfermode->asMode(&mode) && mode <= kLastCoeffMode) { *xpf = GrPorterDuffXPFactory::Create(mode); + // TODO: This Line will be removed in follow up cl that handles blending and thus we won't + // have to set coeffs here. + SkAssertResult(ModeAsCoeff(mode, src, dst)); return true; - } else if (xfermode->asCoeff(&src, &dst)) { - *xpf = GrPorterDuffXPFactory::Create(src, dst); + } else if (xfermode->asCoeff(src, dst)) { + *xpf = GrPorterDuffXPFactory::Create(*src, *dst); return true; } else if (xfermode->asXPFactory(xpf)) { + *src = SkXfermode::kOne_Coeff; + *dst = SkXfermode::kZero_Coeff; return true; } else { return xfermode->asFragmentProcessor(fp); @@ -710,7 +716,8 @@ bool SkXfermode::AsFragmentProcessorOrXPFactory(SkXfermode* xfermode, #else bool SkXfermode::AsFragmentProcessorOrXPFactory(SkXfermode* xfermode, GrFragmentProcessor** fp, - GrXPFactory** xpf) { + GrXPFactory** xpf, + Coeff* src, Coeff* dst) { return false; } #endif diff --git a/src/effects/SkAlphaThresholdFilter.cpp b/src/effects/SkAlphaThresholdFilter.cpp index 13a745efe0..6f9fefce1b 100644 --- a/src/effects/SkAlphaThresholdFilter.cpp +++ b/src/effects/SkAlphaThresholdFilter.cpp @@ -48,7 +48,6 @@ SkImageFilter* SkAlphaThresholdFilter::Create(const SkRegion& region, #include "GrFragmentProcessor.h" #include "GrInvariantOutput.h" #include "GrTextureAccess.h" -#include "effects/GrPorterDuffXferProcessor.h" #include "SkGr.h" @@ -282,7 +281,7 @@ bool SkAlphaThresholdFilterImpl::asFragmentProcessor(GrFragmentProcessor** fp, { GrContext::AutoRenderTarget art(context, maskTexture->asRenderTarget()); GrPaint grPaint; - grPaint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); + grPaint.setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff); SkRegion::Iterator iter(fRegion); context->clear(NULL, 0x0, true, maskTexture->asRenderTarget()); diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index 52f99e112a..f7174e921f 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -24,7 +24,6 @@ #include "GrInvariantOutput.h" #include "SkGrPixelRef.h" #include "SkDraw.h" -#include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrSimpleTextureEffect.h" #include "gl/GrGLProcessor.h" #include "gl/builders/GrGLProgramBuilder.h" @@ -1219,15 +1218,15 @@ bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src, paint.addColorProcessor(GrSimpleTextureEffect::Create(src, matrix))->unref(); if (kInner_SkBlurStyle == fBlurStyle) { // inner: dst = dst * src - paint.setPorterDuffXPFactory(kDC_GrBlendCoeff, kZero_GrBlendCoeff); + paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff); } else if (kSolid_SkBlurStyle == fBlurStyle) { // solid: dst = src + dst - src * dst // = (1 - dst) * src + 1 * dst - paint.setPorterDuffXPFactory(kIDC_GrBlendCoeff, kOne_GrBlendCoeff); + paint.setBlendFunc(kIDC_GrBlendCoeff, kOne_GrBlendCoeff); } else if (kOuter_SkBlurStyle == fBlurStyle) { // outer: dst = dst * (1 - src) // = 0 * src + (1 - src) * dst - paint.setPorterDuffXPFactory(kZero_GrBlendCoeff, kISC_GrBlendCoeff); + paint.setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff); } context->drawRect(paint, clipRect); } diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp index e509e02437..48054f4eac 100755 --- a/src/gpu/GrBitmapTextContext.cpp +++ b/src/gpu/GrBitmapTextContext.cpp @@ -561,6 +561,7 @@ void GrBitmapTextContext::flush() { // Color bitmap text case kARGB_GrMaskFormat: SkASSERT(!drawState.hasColorVertexAttribute()); + drawState.setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff()); drawState.setAlpha(fSkPaint.getAlpha()); break; // LCD text @@ -572,12 +573,24 @@ void GrBitmapTextContext::flush() { 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(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor())); + drawState.setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff); break; } // Grayscale/BW text case kA8_GrMaskFormat: drawState.setHint(GrDrawState::kVertexColorsAreOpaque_Hint, 0xFF == GrColorUnpackA(fPaint.getColor())); + // 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; diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index e87c7e1bc5..f86aa9de29 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -18,10 +18,9 @@ #include "SkRasterClip.h" #include "SkStrokeRec.h" #include "SkTLazy.h" -#include "effects/GrConvexPolyEffect.h" -#include "effects/GrPorterDuffXferProcessor.h" -#include "effects/GrRRectEffect.h" #include "effects/GrTextureDomain.h" +#include "effects/GrConvexPolyEffect.h" +#include "effects/GrRRectEffect.h" #define GR_AA_CLIP 1 typedef SkClipStack::Element Element; @@ -333,25 +332,24 @@ namespace { // set up the OpenGL blend function to perform the specified // boolean operation for alpha clip mask creation void setup_boolean_blendcoeffs(SkRegion::Op op, GrDrawState* drawState) { - // TODO: once we have a coverageDrawing XP this will all use that instead of PD switch (op) { case SkRegion::kReplace_Op: - drawState->setPorterDuffXPFactory(kOne_GrBlendCoeff, kZero_GrBlendCoeff); + drawState->setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff); break; case SkRegion::kIntersect_Op: - drawState->setPorterDuffXPFactory(kDC_GrBlendCoeff, kZero_GrBlendCoeff); + drawState->setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff); break; case SkRegion::kUnion_Op: - drawState->setPorterDuffXPFactory(kOne_GrBlendCoeff, kISC_GrBlendCoeff); + drawState->setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff); break; case SkRegion::kXOR_Op: - drawState->setPorterDuffXPFactory(kIDC_GrBlendCoeff, kISC_GrBlendCoeff); + drawState->setBlendFunc(kIDC_GrBlendCoeff, kISC_GrBlendCoeff); break; case SkRegion::kDifference_Op: - drawState->setPorterDuffXPFactory(kZero_GrBlendCoeff, kISC_GrBlendCoeff); + drawState->setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff); break; case SkRegion::kReverseDifference_Op: - drawState->setPorterDuffXPFactory(kIDC_GrBlendCoeff, kZero_GrBlendCoeff); + drawState->setBlendFunc(kIDC_GrBlendCoeff, kZero_GrBlendCoeff); break; default: SkASSERT(false); diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp index 1f4070f4f5..5b679d1c80 100755 --- a/src/gpu/GrDistanceFieldTextContext.cpp +++ b/src/gpu/GrDistanceFieldTextContext.cpp @@ -637,6 +637,8 @@ void GrDistanceFieldTextContext::flush() { // Set draw state if (fUseLCDText) { + GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor); + // TODO: move supportsRGBCoverage check to setupCoverageEffect and only add LCD // processor if the xp can support it. For now we will simply assume that if // fUseLCDText is true, then we have a known color output. @@ -644,10 +646,22 @@ void GrDistanceFieldTextContext::flush() { 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()); } diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp index 51ef6cf5d3..8c2d75f0b5 100644 --- a/src/gpu/GrDrawState.cpp +++ b/src/gpu/GrDrawState.cpp @@ -14,6 +14,8 @@ #include "GrXferProcessor.h" #include "effects/GrPorterDuffXferProcessor.h" +/////////////////////////////////////////////////////////////////////////////// + bool GrDrawState::isEqual(const GrDrawState& that) const { bool usingVertexColors = this->hasColorVertexAttribute(); if (!usingVertexColors && this->fColor != that.fColor) { @@ -24,6 +26,9 @@ bool GrDrawState::isEqual(const GrDrawState& that) const { this->fColorStages.count() != that.fColorStages.count() || this->fCoverageStages.count() != that.fCoverageStages.count() || !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) || + this->fSrcBlend != that.fSrcBlend || + this->fDstBlend != that.fDstBlend || + this->fBlendConstant != that.fBlendConstant || this->fFlagBits != that.fFlagBits || this->fStencilSettings != that.fStencilSettings || this->fDrawFace != that.fDrawFace) { @@ -85,6 +90,9 @@ GrDrawState& GrDrawState::operator=(const GrDrawState& that) { fRenderTarget.reset(SkSafeRef(that.fRenderTarget.get())); fColor = that.fColor; fViewMatrix = that.fViewMatrix; + fSrcBlend = that.fSrcBlend; + fDstBlend = that.fDstBlend; + fBlendConstant = that.fBlendConstant; fFlagBits = that.fFlagBits; fStencilSettings = that.fStencilSettings; fCoverage = that.fCoverage; @@ -122,6 +130,9 @@ void GrDrawState::onReset(const SkMatrix* initialViewMatrix) { } else { fViewMatrix = *initialViewMatrix; } + fSrcBlend = kOne_GrBlendCoeff; + fDstBlend = kZero_GrBlendCoeff; + fBlendConstant = 0x0; fFlagBits = 0x0; fStencilSettings.setDisabled(); fCoverage = 0xff; @@ -168,11 +179,13 @@ void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRende fXPFactory.reset(SkRef(paint.getXPFactory())); + this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff()); this->setRenderTarget(rt); fViewMatrix = vm; // These have no equivalent in GrPaint, set them to defaults + fBlendConstant = 0x0; fDrawFace = kBoth_DrawFace; fStencilSettings.setDisabled(); fFlagBits = 0; @@ -196,11 +209,15 @@ bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const { if (caps.dualSourceBlendingSupport()) { return true; } - - this->calcColorInvariantOutput(); - this->calcCoverageInvariantOutput(); - return fXPFactory->canApplyCoverage(fColorProcInfo, fCoverageProcInfo, - this->isCoverageDrawing(), this->isColorWriteDisabled()); + // we can correctly apply coverage if a) we have dual source blending + // or b) one of our blend optimizations applies + // or c) the src, dst blend coeffs are 1,0 and we will read Dst Color + GrBlendCoeff srcCoeff; + GrBlendCoeff dstCoeff; + BlendOpt opt = this->getBlendOpt(true, &srcCoeff, &dstCoeff); + return GrDrawState::kNone_BlendOpt != opt || + (this->willEffectReadDstColor() && + kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff); } bool GrDrawState::hasSolidCoverage() const { @@ -220,22 +237,13 @@ bool GrDrawState::hasSolidCoverage() const { //////////////////////////////////////////////////////////////////////////////s bool GrDrawState::willEffectReadDstColor() const { - this->calcColorInvariantOutput(); - this->calcCoverageInvariantOutput(); - // TODO: Remove need to create the XP here. - // Also once all custom blends are turned into XPs we can remove the need - // to check other stages since only xp's will be able to read dst - SkAutoTUnref xferProcessor(fXPFactory->createXferProcessor(fColorProcInfo, - fCoverageProcInfo)); - if (xferProcessor && xferProcessor->willReadDstColor()) { - return true; - } - if (!this->isColorWriteDisabled()) { + this->calcColorInvariantOutput(); if (fColorProcInfo.readsDst()) { return true; } } + this->calcCoverageInvariantOutput(); return fCoverageProcInfo.readsDst(); } @@ -280,7 +288,21 @@ void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) { // Some blend modes allow folding a fractional coverage value into the color's alpha channel, while // others will blend incorrectly. bool GrDrawState::canTweakAlphaForCoverage() const { - return fXPFactory->canTweakAlphaForCoverage(this->isCoverageDrawing()); + /* + The fractional coverage is f. + The src and dst coeffs are Cs and Cd. + The dst and src colors are S and D. + We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha + we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second + term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we + find that only 1, ISA, and ISC produce the correct destination when applied to S' and D. + Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as + color by definition. + */ + return kOne_GrBlendCoeff == fDstBlend || + kISA_GrBlendCoeff == fDstBlend || + kISC_GrBlendCoeff == fDstBlend || + this->isCoverageDrawing(); } //////////////////////////////////////////////////////////////////////////////// @@ -378,6 +400,97 @@ GrDrawState::~GrDrawState() { //////////////////////////////////////////////////////////////////////////////// +GrDrawState::BlendOpt GrDrawState::getBlendOpt(bool forceCoverage, + GrBlendCoeff* srcCoeff, + GrBlendCoeff* dstCoeff) const { + GrBlendCoeff bogusSrcCoeff, bogusDstCoeff; + if (NULL == srcCoeff) { + srcCoeff = &bogusSrcCoeff; + } + if (NULL == dstCoeff) { + dstCoeff = &bogusDstCoeff; + } + + *srcCoeff = this->getSrcBlendCoeff(); + *dstCoeff = this->getDstBlendCoeff(); + + if (this->isColorWriteDisabled()) { + *srcCoeff = kZero_GrBlendCoeff; + *dstCoeff = kOne_GrBlendCoeff; + } + + bool srcAIsOne = this->srcAlphaWillBeOne(); + bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff || + (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne); + bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff || + (kISA_GrBlendCoeff == *dstCoeff && 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 == *srcCoeff && dstCoeffIsOne)) { + if (this->getStencil().doesWrite()) { + return kEmitCoverage_BlendOpt; + } else { + *dstCoeff = kOne_GrBlendCoeff; + return kSkipDraw_BlendOpt; + } + } + + bool hasCoverage = forceCoverage || !this->hasSolidCoverage(); + + // 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 == *srcCoeff) { + // 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 + *dstCoeff = kZero_GrBlendCoeff; + return kNone_BlendOpt; + } else if (kZero_GrBlendCoeff == *srcCoeff) { + // if the op is "clear" then we don't need to emit a color + // or blend, just write transparent black into the dst. + *srcCoeff = kOne_GrBlendCoeff; + *dstCoeff = kZero_GrBlendCoeff; + return kEmitTransBlack_BlendOpt; + } + } + } else if (this->isCoverageDrawing()) { + // we have coverage but we aren't distinguishing it from alpha by request. + return kCoverageAsAlpha_BlendOpt; + } else { + // check whether coverage can be safely rolled into alpha + // of if we can skip color computation and just emit coverage + if (this->canTweakAlphaForCoverage()) { + return kCoverageAsAlpha_BlendOpt; + } + if (dstCoeffIsZero) { + if (kZero_GrBlendCoeff == *srcCoeff) { + // 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. + *dstCoeff = kISA_GrBlendCoeff; + return kEmitCoverage_BlendOpt; + } 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. + *dstCoeff = kISA_GrBlendCoeff; + return kCoverageAsAlpha_BlendOpt; + } + } else if (dstCoeffIsOne) { + // the dst coeff is effectively one so blend works out to: + // cS + (c)(1)D + (1-c)D = cS + D. + *dstCoeff = kOne_GrBlendCoeff; + return kCoverageAsAlpha_BlendOpt; + } + } + + return kNone_BlendOpt; +} + bool GrDrawState::srcAlphaWillBeOne() const { this->calcColorInvariantOutput(); if (this->isCoverageDrawing()) { @@ -388,10 +501,25 @@ bool GrDrawState::srcAlphaWillBeOne() const { } bool GrDrawState::willBlendWithDst() const { - this->calcColorInvariantOutput(); - this->calcCoverageInvariantOutput(); - return fXPFactory->willBlendWithDst(fColorProcInfo, fCoverageProcInfo, - this->isCoverageDrawing(), this->isColorWriteDisabled()); + if (!this->hasSolidCoverage()) { + return true; + } + + if (this->willEffectReadDstColor()) { + return true; + } + + if (GrBlendCoeffRefsDst(this->getSrcBlendCoeff())) { + return true; + } + + GrBlendCoeff dstCoeff = this->getDstBlendCoeff(); + if (!(kZero_GrBlendCoeff == dstCoeff || + (kISA_GrBlendCoeff == dstCoeff && this->srcAlphaWillBeOne()))) { + return true; + } + + return false; } void GrDrawState::calcColorInvariantOutput() const { @@ -433,3 +561,4 @@ void GrDrawState::calcCoverageInvariantOutput() const { fCoverageProcInfoValid = true; } } + diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h index 68c71f020a..39163ff5ee 100644 --- a/src/gpu/GrDrawState.h +++ b/src/gpu/GrDrawState.h @@ -17,9 +17,7 @@ #include "GrProcOptInfo.h" #include "GrRenderTarget.h" #include "GrStencil.h" -#include "GrXferProcessor.h" #include "SkMatrix.h" -#include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrSimpleTextureEffect.h" class GrDrawTargetCaps; @@ -216,22 +214,6 @@ public: */ bool willEffectReadDstColor() const; - /** - * The xfer processor factory. - */ - const GrXPFactory* setXPFactory(const GrXPFactory* xpFactory) { - fXPFactory.reset(SkRef(xpFactory)); - return xpFactory; - } - - void setPorterDuffXPFactory(SkXfermode::Mode mode) { - fXPFactory.reset(GrPorterDuffXPFactory::Create(mode)); - } - - void setPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst) { - fXPFactory.reset(GrPorterDuffXPFactory::Create(src, dst)); - } - const GrFragmentProcessor* addColorProcessor(const GrFragmentProcessor* effect) { SkASSERT(effect); SkNEW_APPEND_TO_TARRAY(&fColorStages, GrFragmentStage, (effect)); @@ -350,6 +332,15 @@ public: /// @name Blending //// + GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlend; } + GrBlendCoeff getDstBlendCoeff() const { return fDstBlend; } + + /** + * Retrieves the last value set by setBlendConstant() + * @return the blending constant value + */ + GrColor getBlendConstant() const { return fBlendConstant; } + /** * Determines whether multiplying the computed per-pixel color by the pixel's fractional * coverage before the blend will give the correct final destination color. In general it @@ -357,6 +348,44 @@ public: */ bool canTweakAlphaForCoverage() const; + /** + * Sets the blending function coefficients. + * + * The blend function will be: + * D' = sat(S*srcCoef + D*dstCoef) + * + * where D is the existing destination color, S is the incoming source + * color, and D' is the new destination color that will be written. sat() + * is the saturation function. + * + * @param srcCoef coefficient applied to the src color. + * @param dstCoef coefficient applied to the dst color. + */ + void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) { + fSrcBlend = srcCoeff; + fDstBlend = dstCoeff; + #ifdef SK_DEBUG + if (GrBlendCoeffRefsDst(dstCoeff)) { + SkDebugf("Unexpected dst blend coeff. Won't work correctly with coverage stages.\n"); + } + if (GrBlendCoeffRefsSrc(srcCoeff)) { + SkDebugf("Unexpected src blend coeff. Won't work correctly with coverage stages.\n"); + } + #endif + } + + /** + * Sets the blending function constant referenced by the following blending + * coefficients: + * kConstC_GrBlendCoeff + * kIConstC_GrBlendCoeff + * kConstA_GrBlendCoeff + * kIConstA_GrBlendCoeff + * + * @param constant the constant to set + */ + void setBlendConstant(GrColor constant) { fBlendConstant = constant; } + /// @} /////////////////////////////////////////////////////////////////////////// @@ -608,6 +637,47 @@ public: private: bool isEqual(const GrDrawState& that) const; + /** + * Optimizations for blending / coverage to that can be applied based on the current state. + */ + enum BlendOpt { + /** + * No optimization + */ + kNone_BlendOpt, + /** + * Don't draw at all + */ + kSkipDraw_BlendOpt, + /** + * The coverage value does not have to be computed separately from alpha, the the output + * color can be the modulation of the two. + */ + kCoverageAsAlpha_BlendOpt, + /** + * Instead of emitting a src color, emit coverage in the alpha channel and r,g,b are + * "don't cares". + */ + kEmitCoverage_BlendOpt, + /** + * Emit transparent black instead of the src color, no need to compute coverage. + */ + kEmitTransBlack_BlendOpt + }; + + /** + * Determines what optimizations can be applied based on the blend. The coefficients may have + * to be tweaked in order for the optimization to work. srcCoeff and dstCoeff are optional + * params that receive the tweaked coefficients. Normally the function looks at the current + * state to see if coverage is enabled. By setting forceCoverage the caller can speculatively + * determine the blend optimizations that would be used if there was partial pixel coverage. + * + * This is used internally and when constructing a GrOptDrawState. + */ + BlendOpt getBlendOpt(bool forceCoverage = false, + GrBlendCoeff* srcCoeff = NULL, + GrBlendCoeff* dstCoeff = NULL) const; + const GrProcOptInfo& colorProcInfo() const { this->calcColorInvariantOutput(); return fColorProcInfo; @@ -646,10 +716,13 @@ private: SkAutoTUnref fRenderTarget; GrColor fColor; SkMatrix fViewMatrix; + GrColor fBlendConstant; uint32_t fFlagBits; GrStencilSettings fStencilSettings; uint8_t fCoverage; DrawFace fDrawFace; + GrBlendCoeff fSrcBlend; + GrBlendCoeff fDstBlend; SkAutoTUnref fGeometryProcessor; SkAutoTUnref fXPFactory; FragmentStageArray fColorStages; diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp index d3172010ed..d95bd3b7c4 100644 --- a/src/gpu/GrOptDrawState.cpp +++ b/src/gpu/GrOptDrawState.cpp @@ -11,7 +11,6 @@ #include "GrDrawTargetCaps.h" #include "GrGpu.h" #include "GrProcOptInfo.h" -#include "GrXferProcessor.h" GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, const GrDrawTargetCaps& caps, @@ -20,35 +19,14 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, GrGpu::DrawType drawType) : fFinalized(false) { fDrawType = drawType; - - const GrProcOptInfo& colorPOI = drawState.colorProcInfo(); - const GrProcOptInfo& coveragePOI = drawState.coverageProcInfo(); - - fColor = colorPOI.inputColorToEffectiveStage(); - fCoverage = drawState.getCoverage(); - - // Create XferProcessor from DS's XPFactory - SkAutoTUnref xferProcessor( - drawState.getXPFactory()->createXferProcessor(colorPOI, coveragePOI)); - - GrXferProcessor::OptFlags optFlags; - if (xferProcessor) { - fXferProcessor.reset(xferProcessor.get()); - - optFlags = xferProcessor->getOptimizations(colorPOI, - coveragePOI, - drawState.isCoverageDrawing(), - drawState.isColorWriteDisabled(), - drawState.getStencil().doesWrite(), - &fColor, - &fCoverage); - } + GrBlendCoeff optSrcCoeff; + GrBlendCoeff optDstCoeff; + GrDrawState::BlendOpt blendOpt = drawState.getBlendOpt(false, &optSrcCoeff, &optDstCoeff); // When path rendering the stencil settings are not always set on the draw state // so we must check the draw type. In cases where we will skip drawing we simply return a // null GrOptDrawState. - if (!xferProcessor || ((GrXferProcessor::kSkipDraw_OptFlag & optFlags) && - GrGpu::kStencilPath_DrawType != drawType)) { + if (GrDrawState::kSkipDraw_BlendOpt == blendOpt && GrGpu::kStencilPath_DrawType != drawType) { // Set the fields that don't default init and return. The lack of a render target will // indicate that this can be skipped. fFlags = 0; @@ -64,8 +42,12 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, SkASSERT(fRenderTarget); fScissorState = scissorState; fViewMatrix = drawState.getViewMatrix(); + fBlendConstant = drawState.getBlendConstant(); fStencilSettings = drawState.getStencil(); fDrawFace = drawState.getDrawFace(); + fSrcBlend = optSrcCoeff; + fDstBlend = optDstCoeff; + // TODO move this out of optDrawState if (dstCopy) { fDstCopy = *dstCopy; @@ -91,8 +73,10 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, bool hasLocalCoords = drawState.hasGeometryProcessor() && drawState.getGeometryProcessor()->hasLocalCoords(); + const GrProcOptInfo& colorPOI = drawState.colorProcInfo(); int firstColorStageIdx = colorPOI.firstEffectiveStageIndex(); fDescInfo.fInputColorIsUsed = colorPOI.inputColorIsUsed(); + fColor = colorPOI.inputColorToEffectiveStage(); if (colorPOI.removeVertexAttrib()) { fDescInfo.fHasVertexColor = false; } @@ -101,18 +85,12 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, // drawState's coverageProcInfo (like color above) to set this initial information. int firstCoverageStageIdx = 0; fDescInfo.fInputCoverageIsUsed = true; + fCoverage = drawState.getCoverage(); + this->adjustProgramForBlendOpt(drawState, blendOpt, &firstColorStageIdx, + &firstCoverageStageIdx); - GrXferProcessor::BlendInfo blendInfo; - fXferProcessor->getBlendInfo(&blendInfo); - fSrcBlend = blendInfo.fSrcBlend; - fDstBlend = blendInfo.fDstBlend; - fBlendConstant = blendInfo.fBlendConstant; - - this->adjustProgramFromOptimizations(drawState, optFlags, colorPOI, coveragePOI, - &firstColorStageIdx, &firstCoverageStageIdx); - - fDescInfo.fRequiresLocalCoordAttrib = hasLocalCoords; + this->getStageStats(drawState, firstColorStageIdx, firstCoverageStageIdx, hasLocalCoords); // Copy GeometryProcesssor from DS or ODS SkASSERT(GrGpu::IsPathRenderingDrawType(drawType) || @@ -120,13 +98,17 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, drawState.hasGeometryProcessor()); fGeometryProcessor.reset(drawState.getGeometryProcessor()); + // Create XferProcessor from DS's XPFactory + const GrXferProcessor* xpProcessor = drawState.getXPFactory()->createXferProcessor(); + fXferProcessor.reset(xpProcessor); + xpProcessor->unref(); + // Copy Stages from DS to ODS for (int i = firstColorStageIdx; i < drawState.numColorStages(); ++i) { SkNEW_APPEND_TO_TARRAY(&fFragmentStages, GrPendingFragmentStage, (drawState.fColorStages[i], hasLocalCoords)); } - fNumColorStages = fFragmentStages.count(); for (int i = firstCoverageStageIdx; i < drawState.numCoverageStages(); ++i) { SkNEW_APPEND_TO_TARRAY(&fFragmentStages, @@ -134,6 +116,8 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, (drawState.fCoverageStages[i], hasLocalCoords)); } + this->setOutputStateInfo(drawState, blendOpt, caps); + // let the GP init the batch tracker if (drawState.hasGeometryProcessor()) { GrGeometryProcessor::InitBT init; @@ -143,12 +127,10 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, init.fCoverage = this->getCoverage(); fGeometryProcessor->initBatchTracker(&fBatchTracker, init); } - - this->setOutputStateInfo(drawState, optFlags, caps); } void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds, - GrXferProcessor::OptFlags optFlags, + GrDrawState::BlendOpt blendOpt, const GrDrawTargetCaps& caps) { // Set this default and then possibly change our mind if there is coverage. fDescInfo.fPrimaryOutputType = GrProgramDesc::kModulate_PrimaryOutputType; @@ -156,7 +138,8 @@ void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds, // Determine whether we should use dual source blending or shader code to keep coverage // separate from color. - bool keepCoverageSeparate = !(optFlags & GrXferProcessor::kSetCoverageDrawing_OptFlag); + bool keepCoverageSeparate = !(GrDrawState::kCoverageAsAlpha_BlendOpt == blendOpt || + GrDrawState::kEmitCoverage_BlendOpt == blendOpt); if (keepCoverageSeparate && !ds.hasSolidCoverage()) { if (caps.dualSourceBlendingSupport()) { if (kZero_GrBlendCoeff == fDstBlend) { @@ -180,35 +163,64 @@ void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds, } } -void GrOptDrawState::adjustProgramFromOptimizations(const GrDrawState& ds, - GrXferProcessor::OptFlags flags, - const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - int* firstColorStageIdx, - int* firstCoverageStageIdx) { +void GrOptDrawState::adjustProgramForBlendOpt(const GrDrawState& ds, + GrDrawState::BlendOpt blendOpt, + int* firstColorStageIdx, + int* firstCoverageStageIdx) { + switch (blendOpt) { + case GrDrawState::kNone_BlendOpt: + case GrDrawState::kSkipDraw_BlendOpt: + case GrDrawState::kCoverageAsAlpha_BlendOpt: + break; + case GrDrawState::kEmitCoverage_BlendOpt: + fColor = 0xffffffff; + fDescInfo.fInputColorIsUsed = true; + *firstColorStageIdx = ds.numColorStages(); + fDescInfo.fHasVertexColor = false; + break; + case GrDrawState::kEmitTransBlack_BlendOpt: + fColor = 0; + fCoverage = 0xff; + fDescInfo.fInputColorIsUsed = true; + fDescInfo.fInputCoverageIsUsed = true; + *firstColorStageIdx = ds.numColorStages(); + *firstCoverageStageIdx = ds.numCoverageStages(); + fDescInfo.fHasVertexColor = false; + fDescInfo.fHasVertexCoverage = false; + break; + } +} + +static void get_stage_stats(const GrFragmentStage& stage, bool* readsDst, bool* readsFragPosition) { + if (stage.getProcessor()->willReadDstColor()) { + *readsDst = true; + } + if (stage.getProcessor()->willReadFragmentPosition()) { + *readsFragPosition = true; + } +} + +void GrOptDrawState::getStageStats(const GrDrawState& ds, int firstColorStageIdx, + int firstCoverageStageIdx, bool hasLocalCoords) { + // We will need a local coord attrib if there is one currently set on the optState and we are + // actually generating some effect code + fDescInfo.fRequiresLocalCoordAttrib = hasLocalCoords && + ds.numTotalStages() - firstColorStageIdx - firstCoverageStageIdx > 0; + fDescInfo.fReadsDst = false; fDescInfo.fReadsFragPosition = false; - if (flags & GrXferProcessor::kClearColorStages_OptFlag) { - fDescInfo.fInputColorIsUsed = true; - *firstColorStageIdx = ds.numColorStages(); - fDescInfo.fHasVertexColor = false; - } else { - fDescInfo.fReadsDst = colorPOI.readsDst(); - fDescInfo.fReadsFragPosition = colorPOI.readsFragPosition(); + for (int s = firstColorStageIdx; s < ds.numColorStages(); ++s) { + const GrFragmentStage& stage = ds.getColorStage(s); + get_stage_stats(stage, &fDescInfo.fReadsDst, &fDescInfo.fReadsFragPosition); } - - if (flags & GrXferProcessor::kClearCoverageStages_OptFlag) { - fDescInfo.fInputCoverageIsUsed = true; - *firstCoverageStageIdx = ds.numCoverageStages(); - fDescInfo.fHasVertexCoverage = false; - } else { - if (coveragePOI.readsDst()) { - fDescInfo.fReadsDst = true; - } - if (coveragePOI.readsFragPosition()) { - fDescInfo.fReadsFragPosition = true; - } + for (int s = firstCoverageStageIdx; s < ds.numCoverageStages(); ++s) { + const GrFragmentStage& stage = ds.getCoverageStage(s); + get_stage_stats(stage, &fDescInfo.fReadsDst, &fDescInfo.fReadsFragPosition); + } + if (ds.hasGeometryProcessor()) { + const GrGeometryProcessor& gp = *ds.getGeometryProcessor(); + fDescInfo.fReadsFragPosition = fDescInfo.fReadsFragPosition || gp.willReadFragmentPosition(); } } diff --git a/src/gpu/GrOptDrawState.h b/src/gpu/GrOptDrawState.h index 1878d16af3..45501b49dd 100644 --- a/src/gpu/GrOptDrawState.h +++ b/src/gpu/GrOptDrawState.h @@ -194,20 +194,22 @@ private: /** * Alter the program desc and inputs (attribs and processors) based on the blend optimization. */ - void adjustProgramFromOptimizations(const GrDrawState& ds, - GrXferProcessor::OptFlags, - const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - int* firstColorStageIdx, - int* firstCoverageStageIdx); + void adjustProgramForBlendOpt(const GrDrawState& ds, GrDrawState::BlendOpt, + int* firstColorStageIdx, int* firstCoverageStageIdx); + + /** + * Loop over the effect stages to determine various info like what data they will read and what + * shaders they require. + */ + void getStageStats(const GrDrawState& ds, int firstColorStageIdx, int firstCoverageStageIdx, + bool hasLocalCoords); /** * Calculates the primary and secondary output types of the shader. For certain output types * the function may adjust the blend coefficients. After this function is called the src and dst * blend coeffs will represent those used by backend API. */ - void setOutputStateInfo(const GrDrawState& ds, GrXferProcessor::OptFlags, - const GrDrawTargetCaps&); + void setOutputStateInfo(const GrDrawState& ds, GrDrawState::BlendOpt, const GrDrawTargetCaps&); enum Flags { kDither_Flag = 0x1, diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp index 5ed573a88b..443e1c0abf 100644 --- a/src/gpu/GrPaint.cpp +++ b/src/gpu/GrPaint.cpp @@ -8,6 +8,7 @@ #include "GrPaint.h" +#include "GrBlend.h" #include "GrProcOptInfo.h" #include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrSimpleTextureEffect.h" @@ -51,20 +52,73 @@ bool GrPaint::isOpaqueAndConstantColor(GrColor* color) const { void GrPaint::resetStages() { fColorStages.reset(); fCoverageStages.reset(); - fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode)); + fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode)); } bool GrPaint::getOpaqueAndKnownColor(GrColor* solidColor, uint32_t* solidColorKnownComponents) const { + // TODO: Share this implementation with GrDrawState + GrProcOptInfo coverageProcInfo; coverageProcInfo.calcWithInitialValues(fCoverageStages.begin(), this->numCoverageStages(), 0xFFFFFFFF, kRGBA_GrColorComponentFlags, true); + + if (!coverageProcInfo.isSolidWhite()) { + return false; + } + GrProcOptInfo colorProcInfo; colorProcInfo.calcWithInitialValues(fColorStages.begin(), this->numColorStages(), fColor, kRGBA_GrColorComponentFlags, false); - return fXPFactory->getOpaqueAndKnownColor(colorProcInfo, coverageProcInfo, solidColor, - solidColorKnownComponents); + SkASSERT((NULL == solidColor) == (NULL == solidColorKnownComponents)); + + GrBlendCoeff srcCoeff = fSrcBlendCoeff; + GrBlendCoeff dstCoeff = fDstBlendCoeff; + GrSimplifyBlend(&srcCoeff, &dstCoeff, colorProcInfo.color(), colorProcInfo.validFlags(), + 0, 0, 0); + + bool opaque = kZero_GrBlendCoeff == dstCoeff && !GrBlendCoeffRefsDst(srcCoeff); + if (solidColor) { + if (opaque) { + switch (srcCoeff) { + case kZero_GrBlendCoeff: + *solidColor = 0; + *solidColorKnownComponents = kRGBA_GrColorComponentFlags; + break; + + case kOne_GrBlendCoeff: + *solidColor = colorProcInfo.color(); + *solidColorKnownComponents = colorProcInfo.validFlags(); + break; + + // The src coeff should never refer to the src and if it refers to dst then opaque + // should have been false. + case kSC_GrBlendCoeff: + case kISC_GrBlendCoeff: + case kDC_GrBlendCoeff: + case kIDC_GrBlendCoeff: + case kSA_GrBlendCoeff: + case kISA_GrBlendCoeff: + case kDA_GrBlendCoeff: + case kIDA_GrBlendCoeff: + default: + SkFAIL("srcCoeff should not refer to src or dst."); + break; + + // TODO: update this once GrPaint actually has a const color. + case kConstC_GrBlendCoeff: + case kIConstC_GrBlendCoeff: + case kConstA_GrBlendCoeff: + case kIConstA_GrBlendCoeff: + *solidColorKnownComponents = 0; + break; + } + } else { + solidColorKnownComponents = 0; + } + } + return opaque; } diff --git a/src/gpu/GrProcOptInfo.cpp b/src/gpu/GrProcOptInfo.cpp index a84ac2e17f..18a32020d4 100644 --- a/src/gpu/GrProcOptInfo.cpp +++ b/src/gpu/GrProcOptInfo.cpp @@ -7,9 +7,8 @@ #include "GrProcOptInfo.h" -#include "GrFragmentProcessor.h" -#include "GrFragmentStage.h" #include "GrGeometryProcessor.h" +#include "GrFragmentStage.h" void GrProcOptInfo::calcWithInitialValues(const GrFragmentStage* stages, int stageCount, @@ -23,7 +22,6 @@ void GrProcOptInfo::calcWithInitialValues(const GrFragmentStage* stages, fInputColor = startColor; fRemoveVertexAttrib = false; fReadsDst = false; - fReadsFragPosition = false; if (areCoverageStages && gp) { gp->computeInvariantOutput(&fInOut); @@ -33,22 +31,17 @@ void GrProcOptInfo::calcWithInitialValues(const GrFragmentStage* stages, const GrFragmentProcessor* processor = stages[i].getProcessor(); fInOut.resetWillUseInputColor(); processor->computeInvariantOutput(&fInOut); -#ifdef SK_DEBUG + #ifdef SK_DEBUG fInOut.validate(); -#endif + #endif if (!fInOut.willUseInputColor()) { fFirstEffectStageIndex = i; fInputColorIsUsed = false; - // Reset these since we don't care if previous stages read these values - fReadsDst = false; - fReadsFragPosition = false; + fReadsDst = false; // Reset this since we don't care if previous stages read dst } if (processor->willReadDstColor()) { fReadsDst = true; } - if (processor->willReadFragmentPosition()) { - fReadsFragPosition = true; - } if (kRGBA_GrColorComponentFlags == fInOut.validFlags()) { fFirstEffectStageIndex = i + 1; fInputColor = fInOut.color(); @@ -57,10 +50,7 @@ void GrProcOptInfo::calcWithInitialValues(const GrFragmentStage* stages, // Since we are clearing all previous color stages we are in a state where we have found // zero stages that don't multiply the inputColor. fInOut.resetNonMulStageFound(); - // Reset these since we don't care if previous stages read these values - fReadsDst = false; - fReadsFragPosition = false; + fReadsDst = false; // Reset this since we don't care if previous stages read dst } } } - diff --git a/src/gpu/GrProcOptInfo.h b/src/gpu/GrProcOptInfo.h index 5778c4c343..bb657d27c0 100644 --- a/src/gpu/GrProcOptInfo.h +++ b/src/gpu/GrProcOptInfo.h @@ -12,9 +12,7 @@ #include "GrInvariantOutput.h" class GrFragmentStage; -class GrFragmentProcessor; class GrGeometryProcessor; -class GrProcessor; /** * GrProcOptInfo gathers invariant data from a set of processor stages.It is used to recognize @@ -29,8 +27,7 @@ public: , fInputColorIsUsed(true) , fInputColor(0) , fRemoveVertexAttrib(false) - , fReadsDst(false) - , fReadsFragPosition(false) {} + , fReadsDst(false) {} void calcWithInitialValues(const GrFragmentStage*, int stageCount, GrColor startColor, GrColorComponentFlags flags, bool areCoverageStages, @@ -77,11 +74,6 @@ public: */ bool readsDst() const { return fReadsDst; } - /** - * Returns true if any of the stages preserved by GrProcOptInfo read the frag position. - */ - bool readsFragPosition() const { return fReadsFragPosition; } - private: GrInvariantOutput fInOut; int fFirstEffectStageIndex; @@ -89,7 +81,6 @@ private: GrColor fInputColor; bool fRemoveVertexAttrib; bool fReadsDst; - bool fReadsFragPosition; }; #endif diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index c0439f5e89..b4b24d9086 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -9,7 +9,6 @@ #include "effects/GrBicubicEffect.h" #include "effects/GrDashingEffect.h" -#include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrTextureDomain.h" #include "effects/GrSimpleTextureEffect.h" @@ -674,7 +673,7 @@ GrTexture* create_mask_GPU(GrContext* context, // code path may not be taken. So we use a dst blend coeff of ISA. We // could special case AA draws to a dst surface with known alpha=0 to // use a zero dst coeff when dual source blending isn't available. - tempPaint.setPorterDuffXPFactory(kOne_GrBlendCoeff, kISC_GrBlendCoeff); + tempPaint.setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff); } GrContext::AutoMatrix am; diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index 82b1ce4b87..9059f55c7a 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -464,21 +464,30 @@ void SkPaint2GrPaintNoShader(GrContext* context, const SkPaint& skPaint, GrColor grPaint->setDither(skPaint.isDither()); grPaint->setAntiAlias(skPaint.isAntiAlias()); + SkXfermode::Coeff sm; + SkXfermode::Coeff dm; + SkXfermode* mode = skPaint.getXfermode(); GrFragmentProcessor* fragmentProcessor = NULL; GrXPFactory* xpFactory = NULL; - if (SkXfermode::AsFragmentProcessorOrXPFactory(mode, &fragmentProcessor, &xpFactory)) { + if (SkXfermode::AsFragmentProcessorOrXPFactory(mode, &fragmentProcessor, &xpFactory, + &sm, &dm)) { if (fragmentProcessor) { SkASSERT(NULL == xpFactory); grPaint->addColorProcessor(fragmentProcessor)->unref(); xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode); + sm = SkXfermode::kOne_Coeff; + dm = SkXfermode::kZero_Coeff; } } else { // Fall back to src-over xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode); + sm = SkXfermode::kOne_Coeff; + dm = SkXfermode::kISA_Coeff; } SkASSERT(xpFactory); grPaint->setXPFactory(xpFactory)->unref(); + grPaint->setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm)); //set the color of the paint to the one of the parameter grPaint->setColor(paintColor); diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp index 52ef75572d..55e0c93b23 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -7,7 +7,6 @@ #include "effects/GrPorterDuffXferProcessor.h" -#include "GrBlend.h" #include "GrDrawState.h" #include "GrInvariantOutput.h" #include "GrProcessor.h" @@ -17,25 +16,6 @@ #include "gl/builders/GrGLFragmentShaderBuilder.h" #include "gl/builders/GrGLProgramBuilder.h" -static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff, bool isCoverageDrawing) { - /* - The fractional coverage is f. - The src and dst coeffs are Cs and Cd. - The dst and src colors are S and D. - We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha - we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second - term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we - find that only 1, ISA, and ISC produce the correct destination when applied to S' and D. - Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as - color by definition. - */ - // TODO: Once we have a CoverageDrawing XP, we don't need to check is CoverageDrawing here - return kOne_GrBlendCoeff == dstCoeff || - kISA_GrBlendCoeff == dstCoeff || - kISC_GrBlendCoeff == dstCoeff || - isCoverageDrawing; -} - class GrGLPorterDuffXferProcessor : public GrGLXferProcessor { public: GrGLPorterDuffXferProcessor(const GrProcessor&) {} @@ -62,9 +42,8 @@ private: /////////////////////////////////////////////////////////////////////////////// -GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, - GrColor constant) - : fSrcBlend(srcBlend), fDstBlend(dstBlend), fBlendConstant(constant) { +GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend) + : fSrcBlend(srcBlend), fDstBlend(dstBlend) { this->initClassID(); } @@ -81,121 +60,13 @@ GrGLFragmentProcessor* GrPorterDuffXferProcessor::createGLInstance() const { } void GrPorterDuffXferProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); + inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput); } -GrXferProcessor::OptFlags -GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, - bool colorWriteDisabled, - bool doesStencilWrite, - GrColor* color, uint8_t* coverage) { - if (colorWriteDisabled) { - fSrcBlend = kZero_GrBlendCoeff; - fDstBlend = kOne_GrBlendCoeff; - } - - bool srcAIsOne; - bool hasCoverage; - if (isCoverageDrawing) { - srcAIsOne = colorPOI.isOpaque() && coveragePOI.isOpaque(); - hasCoverage = false; - } else { - srcAIsOne = colorPOI.isOpaque(); - hasCoverage = !coveragePOI.isSolidWhite(); - } - - bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend || - (kSA_GrBlendCoeff == fDstBlend && srcAIsOne); - bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend || - (kISA_GrBlendCoeff == fDstBlend && srcAIsOne); - - // Optimizations when doing RGB Coverage - if (!coveragePOI.isSingleComponent()) { - // We want to force our primary output to be alpha * Coverage, where alpha is the alpha - // value of the blend the constant. We should already have valid blend coeff's if we are at - // a point where we have RGB coverage. We don't need any color stages since the known color - // output is already baked into the blendConstant. - uint8_t alpha = GrColorUnpackA(fBlendConstant); - *color = GrColorPackRGBA(alpha, alpha, alpha, alpha); - return GrXferProcessor::kClearColorStages_OptFlag; - } - - // 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) { - *color = 0xffffffff; - return GrXferProcessor::kClearColorStages_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; - *color = 0; - *coverage = 0xff; - return GrXferProcessor::kClearColorStages_OptFlag | - GrXferProcessor::kClearCoverageStages_OptFlag; - } - } - } else if (isCoverageDrawing) { - // we have coverage but we aren't distinguishing it from alpha by request. - return GrXferProcessor::kSetCoverageDrawing_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, isCoverageDrawing)) { - 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; - *color = 0xffffffff; - return GrXferProcessor::kClearColorStages_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; - 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; - return GrXferProcessor::kSetCoverageDrawing_OptFlag; - } - } - - return GrXferProcessor::kNone_Opt; -} /////////////////////////////////////////////////////////////////////////////// GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst) - : fSrcCoeff(src), fDstCoeff(dst) { + : fSrc(src), fDst(dst) { this->initClassID(); } @@ -281,173 +152,16 @@ GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) { } } -GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& covPOI) const { - if (covPOI.isSingleComponent()) { - return GrPorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff); - } else { - if (this->supportsRGBCoverage(colorPOI.color(), colorPOI.validFlags())) { - SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags()); - GrColor blendConstant = GrUnPreMulColor(colorPOI.color()); - return GrPorterDuffXferProcessor::Create(kConstC_GrBlendCoeff, kISC_GrBlendCoeff, - blendConstant); - } else { - return NULL; - } - } +const GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor() const { + return GrPorterDuffXferProcessor::Create(fSrc, fDst); } bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, uint32_t knownColorFlags) const { - if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff && + if (kOne_GrBlendCoeff == fSrc && kISA_GrBlendCoeff == fDst && kRGBA_GrColorComponentFlags == knownColorFlags) { return true; } return false; } -bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, - bool colorWriteDisabled) const { - bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.isOpaque()); - - if (colorWriteDisabled) { - return true; - } - - bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstCoeff || - (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne); - bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstCoeff || - (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne); - - if ((kZero_GrBlendCoeff == fSrcCoeff && dstCoeffIsOne)) { - return true; - } - - // if we don't have coverage we can check whether the dst - // has to read at all. - if (isCoverageDrawing) { - // we have coverage but we aren't distinguishing it from alpha by request. - return true; - } else { - // check whether coverage can be safely rolled into alpha - // of if we can skip color computation and just emit coverage - if (this->canTweakAlphaForCoverage(isCoverageDrawing)) { - return true; - } - if (dstCoeffIsZero) { - if (kZero_GrBlendCoeff == fSrcCoeff) { - return true; - } else if (srcAIsOne) { - return true; - } - } else if (dstCoeffIsOne) { - return true; - } - } - - // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's - // will readDst and PD XP's don't read dst. - if ((colorPOI.readsDst() || coveragePOI.readsDst()) && - kOne_GrBlendCoeff == fSrcCoeff && kZero_GrBlendCoeff == fDstCoeff) { - return true; - } - - return false; -} - -bool GrPorterDuffXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, - bool colorWriteDisabled) const { - if (!(isCoverageDrawing || coveragePOI.isSolidWhite())) { - return true; - } - - // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's - // will readDst and PD XP's don't read dst. - if ((!colorWriteDisabled && colorPOI.readsDst()) || coveragePOI.readsDst()) { - return true; - } - - if (GrBlendCoeffRefsDst(fSrcCoeff)) { - return true; - } - - bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.isOpaque()); - - if (!(kZero_GrBlendCoeff == fDstCoeff || - (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne))) { - return true; - } - - return false; -} - -bool GrPorterDuffXPFactory::canTweakAlphaForCoverage(bool isCoverageDrawing) const { - return can_tweak_alpha_for_coverage(fDstCoeff, isCoverageDrawing); -} - -bool GrPorterDuffXPFactory::getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI, - const GrProcOptInfo& coveragePOI, - GrColor* solidColor, - uint32_t* solidColorKnownComponents) const { - if (!coveragePOI.isSolidWhite()) { - return false; - } - - SkASSERT((NULL == solidColor) == (NULL == solidColorKnownComponents)); - - GrBlendCoeff srcCoeff = fSrcCoeff; - GrBlendCoeff dstCoeff = fDstCoeff; - - // TODO: figure out to merge this simplify with other current optimization code paths and - // eventually remove from GrBlend - GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(), - 0, 0, 0); - - bool opaque = kZero_GrBlendCoeff == dstCoeff && !GrBlendCoeffRefsDst(srcCoeff); - if (solidColor) { - if (opaque) { - switch (srcCoeff) { - case kZero_GrBlendCoeff: - *solidColor = 0; - *solidColorKnownComponents = kRGBA_GrColorComponentFlags; - break; - - case kOne_GrBlendCoeff: - *solidColor = colorPOI.color(); - *solidColorKnownComponents = colorPOI.validFlags(); - break; - - // The src coeff should never refer to the src and if it refers to dst then opaque - // should have been false. - case kSC_GrBlendCoeff: - case kISC_GrBlendCoeff: - case kDC_GrBlendCoeff: - case kIDC_GrBlendCoeff: - case kSA_GrBlendCoeff: - case kISA_GrBlendCoeff: - case kDA_GrBlendCoeff: - case kIDA_GrBlendCoeff: - default: - SkFAIL("srcCoeff should not refer to src or dst."); - break; - - // TODO: update this once GrPaint actually has a const color. - case kConstC_GrBlendCoeff: - case kIConstC_GrBlendCoeff: - case kConstA_GrBlendCoeff: - case kIConstA_GrBlendCoeff: - *solidColorKnownComponents = 0; - break; - } - } else { - solidColorKnownComponents = 0; - } - } - return opaque; -} - - diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp index 56707a0414..18c14c45be 100644 --- a/tests/GLProgramsTest.cpp +++ b/tests/GLProgramsTest.cpp @@ -16,12 +16,10 @@ #include "GrInvariantOutput.h" #include "GrOptDrawState.h" #include "GrTest.h" -#include "GrXferProcessor.h" #include "SkChecksum.h" #include "SkRandom.h" #include "Test.h" #include "effects/GrConfigConversionEffect.h" -#include "effects/GrPorterDuffXferProcessor.h" #include "gl/GrGLPathRendering.h" #include "gl/GrGpuGL.h" #include "gl/builders/GrGLProgramBuilder.h" @@ -269,8 +267,7 @@ static void set_random_blend_func(GrDrawState* ds, SkRandom* random) { dst = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff)); } while (GrBlendCoeffRefsDst(dst)); - GrXPFactory* xpFactory = GrPorterDuffXPFactory::Create(src, dst); - ds->setXPFactory(xpFactory)->unref(); + ds->setBlendFunc(src, dst); } // right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'