aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar egdaniel <egdaniel@google.com>2014-12-08 11:20:39 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2014-12-08 11:20:40 -0800
commit7c66342a399b529634bed0fabfaa562db2c0dbd4 (patch)
tree1acf634452770b9ef66d8a1422748422062ec9d6
parenta2bd24fd15378d0a25d79b4aa2d76dddc4cf564c (diff)
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: Review URL: https://codereview.chromium.org/759713002
-rw-r--r--gm/texdata.cpp6
-rw-r--r--include/core/SkXfermode.h4
-rw-r--r--include/gpu/GrPaint.h32
-rw-r--r--include/gpu/GrXferProcessor.h111
-rw-r--r--include/gpu/effects/GrPorterDuffXferProcessor.h50
-rw-r--r--src/core/SkXfermode.cpp19
-rw-r--r--src/effects/SkAlphaThresholdFilter.cpp3
-rw-r--r--src/effects/SkBlurMaskFilter.cpp7
-rwxr-xr-xsrc/gpu/GrBitmapTextContext.cpp13
-rw-r--r--src/gpu/GrClipMaskManager.cpp16
-rwxr-xr-xsrc/gpu/GrDistanceFieldTextContext.cpp14
-rw-r--r--src/gpu/GrDrawState.cpp171
-rw-r--r--src/gpu/GrDrawState.h109
-rw-r--r--src/gpu/GrOptDrawState.cpp144
-rw-r--r--src/gpu/GrOptDrawState.h18
-rw-r--r--src/gpu/GrPaint.cpp60
-rw-r--r--src/gpu/GrProcOptInfo.cpp20
-rw-r--r--src/gpu/GrProcOptInfo.h11
-rw-r--r--src/gpu/SkGpuDevice.cpp3
-rw-r--r--src/gpu/SkGr.cpp11
-rw-r--r--src/gpu/effects/GrPorterDuffXferProcessor.cpp300
-rw-r--r--tests/GLProgramsTest.cpp5
22 files changed, 629 insertions, 498 deletions
diff --git a/gm/texdata.cpp b/gm/texdata.cpp
index efe8c4d730..56dfd24ed0 100644
--- a/gm/texdata.cpp
+++ b/gm/texdata.cpp
@@ -12,8 +12,9 @@
#if SK_SUPPORT_GPU
#include "GrContext.h"
-#include "effects/GrSimpleTextureEffect.h"
#include "SkColorPriv.h"
+#include "effects/GrPorterDuffXferProcessor.h"
+#include "effects/GrSimpleTextureEffect.h"
namespace skiagm {
@@ -98,7 +99,8 @@ protected:
ctx->setRenderTarget(target);
GrPaint paint;
- paint.setBlendFunc(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
+ paint.setPorterDuffXPFactory(SkXfermode::kSrcOver_Mode);
+
SkMatrix vm;
if (i) {
vm.setRotate(90 * SK_Scalar1,
diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h
index 35e9837483..05fd81152a 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, xpf, src, and dst must all be NULL or all non-NULL.
+ fp and xpf must both be NULL or all non-NULL.
*/
static bool AsFragmentProcessorOrXPFactory(SkXfermode*, GrFragmentProcessor**,
- GrXPFactory**, Coeff* src, Coeff* dst);
+ GrXPFactory**);
SK_TO_STRING_PUREVIRT()
SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
diff --git a/include/gpu/GrPaint.h b/include/gpu/GrPaint.h
index f31830bb2b..49b95b8449 100644
--- a/include/gpu/GrPaint.h
+++ b/include/gpu/GrPaint.h
@@ -13,6 +13,7 @@
#include "GrColor.h"
#include "GrFragmentStage.h"
#include "GrXferProcessor.h"
+#include "effects/GrPorterDuffXferProcessor.h"
#include "SkXfermode.h"
@@ -51,17 +52,6 @@ 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.
*/
void setColor(GrColor color) { fColor = color; }
@@ -84,6 +74,14 @@ 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.
*/
@@ -121,8 +119,6 @@ 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;
@@ -140,7 +136,6 @@ public:
* Resets the paint to the defaults.
*/
void reset() {
- this->resetBlend();
this->resetOptions();
this->resetColor();
this->resetStages();
@@ -211,18 +206,11 @@ 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;
@@ -232,7 +220,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 10ecf54c75..b7d0bdd9fa 100644
--- a/include/gpu/GrXferProcessor.h
+++ b/include/gpu/GrXferProcessor.h
@@ -13,6 +13,8 @@
#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
@@ -27,11 +29,83 @@
* 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
@@ -45,7 +119,8 @@ private:
*/
class GrXPFactory : public SkRefCnt {
public:
- virtual const GrXferProcessor* createXferProcessor() const = 0;
+ virtual GrXferProcessor* createXferProcessor(const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI) const = 0;
/**
* This function returns true if the GrXferProcessor generated from this factory will be able to
@@ -54,6 +129,40 @@ 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 9ff3bea2ed..0ddfcdcd2a 100644
--- a/include/gpu/effects/GrPorterDuffXferProcessor.h
+++ b/include/gpu/effects/GrPorterDuffXferProcessor.h
@@ -17,8 +17,9 @@ class GrInvariantOutput;
class GrPorterDuffXferProcessor : public GrXferProcessor {
public:
- static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend) {
- return SkNEW_ARGS(GrPorterDuffXferProcessor, (srcBlend, dstBlend));
+ static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
+ GrColor constant = 0) {
+ return SkNEW_ARGS(GrPorterDuffXferProcessor, (srcBlend, dstBlend, constant));
}
virtual ~GrPorterDuffXferProcessor();
@@ -30,12 +31,28 @@ 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);
+ GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColor constant);
virtual bool onIsEqual(const GrFragmentProcessor& fpBase) const SK_OVERRIDE {
const GrPorterDuffXferProcessor& xp = fpBase.cast<GrPorterDuffXferProcessor>();
- if (fSrcBlend != xp.fSrcBlend || fDstBlend != xp.fDstBlend) {
+ if (fSrcBlend != xp.fSrcBlend ||
+ fDstBlend != xp.fDstBlend ||
+ fBlendConstant != xp.fBlendConstant) {
return false;
}
return true;
@@ -45,7 +62,8 @@ private:
GrBlendCoeff fSrcBlend;
GrBlendCoeff fDstBlend;
-
+ GrColor fBlendConstant;
+
typedef GrXferProcessor INHERITED;
};
@@ -63,20 +81,34 @@ public:
return SkNEW_ARGS(GrPorterDuffXPFactory, (src, dst));
}
- const GrXferProcessor* createXferProcessor() const SK_OVERRIDE;
+ GrXferProcessor* createXferProcessor(const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI) 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<GrPorterDuffXPFactory>();
- return (fSrc == xpf.fSrc && fDst == xpf.fDst);
+ return (fSrcCoeff == xpf.fSrcCoeff && fDstCoeff == xpf.fDstCoeff);
}
- GrBlendCoeff fSrc;
- GrBlendCoeff fDst;
+ GrBlendCoeff fSrcCoeff;
+ GrBlendCoeff fDstCoeff;
typedef GrXPFactory INHERITED;
};
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 268d41ec1b..004aa93afd 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -689,25 +689,19 @@ bool SkXfermode::asXPFactory(GrXPFactory**) const {
bool SkXfermode::AsFragmentProcessorOrXPFactory(SkXfermode* xfermode,
GrFragmentProcessor** fp,
- GrXPFactory** xpf,
- Coeff* src, Coeff* dst) {
+ GrXPFactory** xpf) {
+ Coeff src, dst;
Mode mode;
if (NULL == xfermode) {
- SkAssertResult(ModeAsCoeff(kSrcOver_Mode, src, dst));
- *xpf = GrPorterDuffXPFactory::Create(*src, *dst);
+ *xpf = GrPorterDuffXPFactory::Create(kSrcOver_Mode);
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);
@@ -716,8 +710,7 @@ bool SkXfermode::AsFragmentProcessorOrXPFactory(SkXfermode* xfermode,
#else
bool SkXfermode::AsFragmentProcessorOrXPFactory(SkXfermode* xfermode,
GrFragmentProcessor** fp,
- GrXPFactory** xpf,
- Coeff* src, Coeff* dst) {
+ GrXPFactory** xpf) {
return false;
}
#endif
diff --git a/src/effects/SkAlphaThresholdFilter.cpp b/src/effects/SkAlphaThresholdFilter.cpp
index 6f9fefce1b..13a745efe0 100644
--- a/src/effects/SkAlphaThresholdFilter.cpp
+++ b/src/effects/SkAlphaThresholdFilter.cpp
@@ -48,6 +48,7 @@ SkImageFilter* SkAlphaThresholdFilter::Create(const SkRegion& region,
#include "GrFragmentProcessor.h"
#include "GrInvariantOutput.h"
#include "GrTextureAccess.h"
+#include "effects/GrPorterDuffXferProcessor.h"
#include "SkGr.h"
@@ -281,7 +282,7 @@ bool SkAlphaThresholdFilterImpl::asFragmentProcessor(GrFragmentProcessor** fp,
{
GrContext::AutoRenderTarget art(context, maskTexture->asRenderTarget());
GrPaint grPaint;
- grPaint.setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
+ grPaint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
SkRegion::Iterator iter(fRegion);
context->clear(NULL, 0x0, true, maskTexture->asRenderTarget());
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index f7174e921f..52f99e112a 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -24,6 +24,7 @@
#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"
@@ -1218,15 +1219,15 @@ bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
paint.addColorProcessor(GrSimpleTextureEffect::Create(src, matrix))->unref();
if (kInner_SkBlurStyle == fBlurStyle) {
// inner: dst = dst * src
- paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
+ paint.setPorterDuffXPFactory(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
} else if (kSolid_SkBlurStyle == fBlurStyle) {
// solid: dst = src + dst - src * dst
// = (1 - dst) * src + 1 * dst
- paint.setBlendFunc(kIDC_GrBlendCoeff, kOne_GrBlendCoeff);
+ paint.setPorterDuffXPFactory(kIDC_GrBlendCoeff, kOne_GrBlendCoeff);
} else if (kOuter_SkBlurStyle == fBlurStyle) {
// outer: dst = dst * (1 - src)
// = 0 * src + (1 - src) * dst
- paint.setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
+ paint.setPorterDuffXPFactory(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
}
context->drawRect(paint, clipRect);
}
diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp
index 48054f4eac..e509e02437 100755
--- a/src/gpu/GrBitmapTextContext.cpp
+++ b/src/gpu/GrBitmapTextContext.cpp
@@ -561,7 +561,6 @@ 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
@@ -573,24 +572,12 @@ 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 f86aa9de29..e87c7e1bc5 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -18,9 +18,10 @@
#include "SkRasterClip.h"
#include "SkStrokeRec.h"
#include "SkTLazy.h"
-#include "effects/GrTextureDomain.h"
#include "effects/GrConvexPolyEffect.h"
+#include "effects/GrPorterDuffXferProcessor.h"
#include "effects/GrRRectEffect.h"
+#include "effects/GrTextureDomain.h"
#define GR_AA_CLIP 1
typedef SkClipStack::Element Element;
@@ -332,24 +333,25 @@ 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->setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
+ drawState->setPorterDuffXPFactory(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
break;
case SkRegion::kIntersect_Op:
- drawState->setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
+ drawState->setPorterDuffXPFactory(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
break;
case SkRegion::kUnion_Op:
- drawState->setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
+ drawState->setPorterDuffXPFactory(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
break;
case SkRegion::kXOR_Op:
- drawState->setBlendFunc(kIDC_GrBlendCoeff, kISC_GrBlendCoeff);
+ drawState->setPorterDuffXPFactory(kIDC_GrBlendCoeff, kISC_GrBlendCoeff);
break;
case SkRegion::kDifference_Op:
- drawState->setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
+ drawState->setPorterDuffXPFactory(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
break;
case SkRegion::kReverseDifference_Op:
- drawState->setBlendFunc(kIDC_GrBlendCoeff, kZero_GrBlendCoeff);
+ drawState->setPorterDuffXPFactory(kIDC_GrBlendCoeff, kZero_GrBlendCoeff);
break;
default:
SkASSERT(false);
diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp
index 5b679d1c80..1f4070f4f5 100755
--- a/src/gpu/GrDistanceFieldTextContext.cpp
+++ b/src/gpu/GrDistanceFieldTextContext.cpp
@@ -637,8 +637,6 @@ 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.
@@ -646,22 +644,10 @@ 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 8c2d75f0b5..51ef6cf5d3 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -14,8 +14,6 @@
#include "GrXferProcessor.h"
#include "effects/GrPorterDuffXferProcessor.h"
-///////////////////////////////////////////////////////////////////////////////
-
bool GrDrawState::isEqual(const GrDrawState& that) const {
bool usingVertexColors = this->hasColorVertexAttribute();
if (!usingVertexColors && this->fColor != that.fColor) {
@@ -26,9 +24,6 @@ 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) {
@@ -90,9 +85,6 @@ 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;
@@ -130,9 +122,6 @@ void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
} else {
fViewMatrix = *initialViewMatrix;
}
- fSrcBlend = kOne_GrBlendCoeff;
- fDstBlend = kZero_GrBlendCoeff;
- fBlendConstant = 0x0;
fFlagBits = 0x0;
fStencilSettings.setDisabled();
fCoverage = 0xff;
@@ -179,13 +168,11 @@ 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;
@@ -209,15 +196,11 @@ bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const {
if (caps.dualSourceBlendingSupport()) {
return true;
}
- // 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);
+
+ this->calcColorInvariantOutput();
+ this->calcCoverageInvariantOutput();
+ return fXPFactory->canApplyCoverage(fColorProcInfo, fCoverageProcInfo,
+ this->isCoverageDrawing(), this->isColorWriteDisabled());
}
bool GrDrawState::hasSolidCoverage() const {
@@ -237,13 +220,22 @@ 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<GrXferProcessor> 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();
}
@@ -288,21 +280,7 @@ 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 {
- /*
- 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();
+ return fXPFactory->canTweakAlphaForCoverage(this->isCoverageDrawing());
}
////////////////////////////////////////////////////////////////////////////////
@@ -400,97 +378,6 @@ 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()) {
@@ -501,25 +388,10 @@ bool GrDrawState::srcAlphaWillBeOne() const {
}
bool GrDrawState::willBlendWithDst() const {
- 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;
+ this->calcColorInvariantOutput();
+ this->calcCoverageInvariantOutput();
+ return fXPFactory->willBlendWithDst(fColorProcInfo, fCoverageProcInfo,
+ this->isCoverageDrawing(), this->isColorWriteDisabled());
}
void GrDrawState::calcColorInvariantOutput() const {
@@ -561,4 +433,3 @@ void GrDrawState::calcCoverageInvariantOutput() const {
fCoverageProcInfoValid = true;
}
}
-
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 39163ff5ee..68c71f020a 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -17,7 +17,9 @@
#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;
@@ -214,6 +216,22 @@ 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));
@@ -332,15 +350,6 @@ 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
@@ -348,44 +357,6 @@ 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; }
-
/// @}
///////////////////////////////////////////////////////////////////////////
@@ -637,47 +608,6 @@ 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;
@@ -716,13 +646,10 @@ private:
SkAutoTUnref<GrRenderTarget> fRenderTarget;
GrColor fColor;
SkMatrix fViewMatrix;
- GrColor fBlendConstant;
uint32_t fFlagBits;
GrStencilSettings fStencilSettings;
uint8_t fCoverage;
DrawFace fDrawFace;
- GrBlendCoeff fSrcBlend;
- GrBlendCoeff fDstBlend;
SkAutoTUnref<const GrGeometryProcessor> fGeometryProcessor;
SkAutoTUnref<const GrXPFactory> fXPFactory;
FragmentStageArray fColorStages;
diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp
index d95bd3b7c4..d3172010ed 100644
--- a/src/gpu/GrOptDrawState.cpp
+++ b/src/gpu/GrOptDrawState.cpp
@@ -11,6 +11,7 @@
#include "GrDrawTargetCaps.h"
#include "GrGpu.h"
#include "GrProcOptInfo.h"
+#include "GrXferProcessor.h"
GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
const GrDrawTargetCaps& caps,
@@ -19,14 +20,35 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
GrGpu::DrawType drawType)
: fFinalized(false) {
fDrawType = drawType;
- GrBlendCoeff optSrcCoeff;
- GrBlendCoeff optDstCoeff;
- GrDrawState::BlendOpt blendOpt = drawState.getBlendOpt(false, &optSrcCoeff, &optDstCoeff);
+
+ const GrProcOptInfo& colorPOI = drawState.colorProcInfo();
+ const GrProcOptInfo& coveragePOI = drawState.coverageProcInfo();
+
+ fColor = colorPOI.inputColorToEffectiveStage();
+ fCoverage = drawState.getCoverage();
+
+ // Create XferProcessor from DS's XPFactory
+ SkAutoTUnref<GrXferProcessor> 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);
+ }
// 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 (GrDrawState::kSkipDraw_BlendOpt == blendOpt && GrGpu::kStencilPath_DrawType != drawType) {
+ if (!xferProcessor || ((GrXferProcessor::kSkipDraw_OptFlag & optFlags) &&
+ 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;
@@ -42,12 +64,8 @@ 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;
@@ -73,10 +91,8 @@ 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;
}
@@ -85,12 +101,18 @@ 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);
- this->getStageStats(drawState, firstColorStageIdx, firstCoverageStageIdx, hasLocalCoords);
+ 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;
// Copy GeometryProcesssor from DS or ODS
SkASSERT(GrGpu::IsPathRenderingDrawType(drawType) ||
@@ -98,17 +120,13 @@ 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,
@@ -116,8 +134,6 @@ 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;
@@ -127,10 +143,12 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
init.fCoverage = this->getCoverage();
fGeometryProcessor->initBatchTracker(&fBatchTracker, init);
}
+
+ this->setOutputStateInfo(drawState, optFlags, caps);
}
void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds,
- GrDrawState::BlendOpt blendOpt,
+ GrXferProcessor::OptFlags optFlags,
const GrDrawTargetCaps& caps) {
// Set this default and then possibly change our mind if there is coverage.
fDescInfo.fPrimaryOutputType = GrProgramDesc::kModulate_PrimaryOutputType;
@@ -138,8 +156,7 @@ 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 = !(GrDrawState::kCoverageAsAlpha_BlendOpt == blendOpt ||
- GrDrawState::kEmitCoverage_BlendOpt == blendOpt);
+ bool keepCoverageSeparate = !(optFlags & GrXferProcessor::kSetCoverageDrawing_OptFlag);
if (keepCoverageSeparate && !ds.hasSolidCoverage()) {
if (caps.dualSourceBlendingSupport()) {
if (kZero_GrBlendCoeff == fDstBlend) {
@@ -163,64 +180,35 @@ void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds,
}
}
-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;
-
+void GrOptDrawState::adjustProgramFromOptimizations(const GrDrawState& ds,
+ GrXferProcessor::OptFlags flags,
+ const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI,
+ int* firstColorStageIdx,
+ int* firstCoverageStageIdx) {
fDescInfo.fReadsDst = false;
fDescInfo.fReadsFragPosition = false;
- for (int s = firstColorStageIdx; s < ds.numColorStages(); ++s) {
- const GrFragmentStage& stage = ds.getColorStage(s);
- get_stage_stats(stage, &fDescInfo.fReadsDst, &fDescInfo.fReadsFragPosition);
- }
- for (int s = firstCoverageStageIdx; s < ds.numCoverageStages(); ++s) {
- const GrFragmentStage& stage = ds.getCoverageStage(s);
- get_stage_stats(stage, &fDescInfo.fReadsDst, &fDescInfo.fReadsFragPosition);
+ if (flags & GrXferProcessor::kClearColorStages_OptFlag) {
+ fDescInfo.fInputColorIsUsed = true;
+ *firstColorStageIdx = ds.numColorStages();
+ fDescInfo.fHasVertexColor = false;
+ } else {
+ fDescInfo.fReadsDst = colorPOI.readsDst();
+ fDescInfo.fReadsFragPosition = colorPOI.readsFragPosition();
}
- if (ds.hasGeometryProcessor()) {
- const GrGeometryProcessor& gp = *ds.getGeometryProcessor();
- fDescInfo.fReadsFragPosition = fDescInfo.fReadsFragPosition || gp.willReadFragmentPosition();
+
+ 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;
+ }
}
}
diff --git a/src/gpu/GrOptDrawState.h b/src/gpu/GrOptDrawState.h
index 45501b49dd..1878d16af3 100644
--- a/src/gpu/GrOptDrawState.h
+++ b/src/gpu/GrOptDrawState.h
@@ -194,22 +194,20 @@ private:
/**
* Alter the program desc and inputs (attribs and processors) based on the blend optimization.
*/
- 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);
+ void adjustProgramFromOptimizations(const GrDrawState& ds,
+ GrXferProcessor::OptFlags,
+ const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI,
+ int* firstColorStageIdx,
+ int* firstCoverageStageIdx);
/**
* 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, GrDrawState::BlendOpt, const GrDrawTargetCaps&);
+ void setOutputStateInfo(const GrDrawState& ds, GrXferProcessor::OptFlags,
+ const GrDrawTargetCaps&);
enum Flags {
kDither_Flag = 0x1,
diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp
index 443e1c0abf..5ed573a88b 100644
--- a/src/gpu/GrPaint.cpp
+++ b/src/gpu/GrPaint.cpp
@@ -8,7 +8,6 @@
#include "GrPaint.h"
-#include "GrBlend.h"
#include "GrProcOptInfo.h"
#include "effects/GrPorterDuffXferProcessor.h"
#include "effects/GrSimpleTextureEffect.h"
@@ -52,73 +51,20 @@ bool GrPaint::isOpaqueAndConstantColor(GrColor* color) const {
void GrPaint::resetStages() {
fColorStages.reset();
fCoverageStages.reset();
- fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode));
+ fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_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);
- 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;
+ return fXPFactory->getOpaqueAndKnownColor(colorProcInfo, coverageProcInfo, solidColor,
+ solidColorKnownComponents);
}
diff --git a/src/gpu/GrProcOptInfo.cpp b/src/gpu/GrProcOptInfo.cpp
index 18a32020d4..a84ac2e17f 100644
--- a/src/gpu/GrProcOptInfo.cpp
+++ b/src/gpu/GrProcOptInfo.cpp
@@ -7,8 +7,9 @@
#include "GrProcOptInfo.h"
-#include "GrGeometryProcessor.h"
+#include "GrFragmentProcessor.h"
#include "GrFragmentStage.h"
+#include "GrGeometryProcessor.h"
void GrProcOptInfo::calcWithInitialValues(const GrFragmentStage* stages,
int stageCount,
@@ -22,6 +23,7 @@ void GrProcOptInfo::calcWithInitialValues(const GrFragmentStage* stages,
fInputColor = startColor;
fRemoveVertexAttrib = false;
fReadsDst = false;
+ fReadsFragPosition = false;
if (areCoverageStages && gp) {
gp->computeInvariantOutput(&fInOut);
@@ -31,17 +33,22 @@ 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;
- fReadsDst = false; // Reset this since we don't care if previous stages read dst
+ // Reset these since we don't care if previous stages read these values
+ fReadsDst = false;
+ fReadsFragPosition = false;
}
if (processor->willReadDstColor()) {
fReadsDst = true;
}
+ if (processor->willReadFragmentPosition()) {
+ fReadsFragPosition = true;
+ }
if (kRGBA_GrColorComponentFlags == fInOut.validFlags()) {
fFirstEffectStageIndex = i + 1;
fInputColor = fInOut.color();
@@ -50,7 +57,10 @@ 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();
- fReadsDst = false; // Reset this since we don't care if previous stages read dst
+ // Reset these since we don't care if previous stages read these values
+ fReadsDst = false;
+ fReadsFragPosition = false;
}
}
}
+
diff --git a/src/gpu/GrProcOptInfo.h b/src/gpu/GrProcOptInfo.h
index bb657d27c0..5778c4c343 100644
--- a/src/gpu/GrProcOptInfo.h
+++ b/src/gpu/GrProcOptInfo.h
@@ -12,7 +12,9 @@
#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
@@ -27,7 +29,8 @@ public:
, fInputColorIsUsed(true)
, fInputColor(0)
, fRemoveVertexAttrib(false)
- , fReadsDst(false) {}
+ , fReadsDst(false)
+ , fReadsFragPosition(false) {}
void calcWithInitialValues(const GrFragmentStage*, int stageCount, GrColor startColor,
GrColorComponentFlags flags, bool areCoverageStages,
@@ -74,6 +77,11 @@ 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;
@@ -81,6 +89,7 @@ private:
GrColor fInputColor;
bool fRemoveVertexAttrib;
bool fReadsDst;
+ bool fReadsFragPosition;
};
#endif
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index b4b24d9086..c0439f5e89 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -9,6 +9,7 @@
#include "effects/GrBicubicEffect.h"
#include "effects/GrDashingEffect.h"
+#include "effects/GrPorterDuffXferProcessor.h"
#include "effects/GrTextureDomain.h"
#include "effects/GrSimpleTextureEffect.h"
@@ -673,7 +674,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.setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
+ tempPaint.setPorterDuffXPFactory(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
}
GrContext::AutoMatrix am;
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 9059f55c7a..82b1ce4b87 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -464,30 +464,21 @@ 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,
- &sm, &dm)) {
+ if (SkXfermode::AsFragmentProcessorOrXPFactory(mode, &fragmentProcessor, &xpFactory)) {
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 55e0c93b23..52ef75572d 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -7,6 +7,7 @@
#include "effects/GrPorterDuffXferProcessor.h"
+#include "GrBlend.h"
#include "GrDrawState.h"
#include "GrInvariantOutput.h"
#include "GrProcessor.h"
@@ -16,6 +17,25 @@
#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&) {}
@@ -42,8 +62,9 @@ private:
///////////////////////////////////////////////////////////////////////////////
-GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend)
- : fSrcBlend(srcBlend), fDstBlend(dstBlend) {
+GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
+ GrColor constant)
+ : fSrcBlend(srcBlend), fDstBlend(dstBlend), fBlendConstant(constant) {
this->initClassID<GrPorterDuffXferProcessor>();
}
@@ -60,13 +81,121 @@ GrGLFragmentProcessor* GrPorterDuffXferProcessor::createGLInstance() const {
}
void GrPorterDuffXferProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const {
- inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput);
+ inout->setToUnknown(GrInvariantOutput::kWill_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)
- : fSrc(src), fDst(dst) {
+ : fSrcCoeff(src), fDstCoeff(dst) {
this->initClassID<GrPorterDuffXPFactory>();
}
@@ -152,16 +281,173 @@ GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
}
}
-const GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor() const {
- return GrPorterDuffXferProcessor::Create(fSrc, fDst);
+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;
+ }
+ }
}
bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
uint32_t knownColorFlags) const {
- if (kOne_GrBlendCoeff == fSrc && kISA_GrBlendCoeff == fDst &&
+ if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
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 18c14c45be..56707a0414 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -16,10 +16,12 @@
#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"
@@ -267,7 +269,8 @@ static void set_random_blend_func(GrDrawState* ds, SkRandom* random) {
dst = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
} while (GrBlendCoeffRefsDst(dst));
- ds->setBlendFunc(src, dst);
+ GrXPFactory* xpFactory = GrPorterDuffXPFactory::Create(src, dst);
+ ds->setXPFactory(xpFactory)->unref();
}
// right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'