aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-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()'