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
This commit is contained in:
egdaniel 2014-12-08 11:20:39 -08:00 committed by Commit bot
parent a2bd24fd15
commit 7c66342a39
22 changed files with 629 additions and 498 deletions

View File

@ -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,

View File

@ -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()

View File

@ -13,6 +13,7 @@
#include "GrColor.h"
#include "GrFragmentStage.h"
#include "GrXferProcessor.h"
#include "effects/GrPorterDuffXferProcessor.h"
#include "SkXfermode.h"
@ -50,17 +51,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.
*/
@ -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

View File

@ -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;

View File

@ -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;
};

View File

@ -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

View File

@ -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());

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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());
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);
if (flags & GrXferProcessor::kClearColorStages_OptFlag) {
fDescInfo.fInputColorIsUsed = true;
*firstColorStageIdx = ds.numColorStages();
fDescInfo.fHasVertexColor = false;
} else {
fDescInfo.fReadsDst = colorPOI.readsDst();
fDescInfo.fReadsFragPosition = colorPOI.readsFragPosition();
}
for (int s = firstCoverageStageIdx; s < ds.numCoverageStages(); ++s) {
const GrFragmentStage& stage = ds.getCoverageStage(s);
get_stage_stats(stage, &fDescInfo.fReadsDst, &fDescInfo.fReadsFragPosition);
}
if (ds.hasGeometryProcessor()) {
const GrGeometryProcessor& gp = *ds.getGeometryProcessor();
fDescInfo.fReadsFragPosition = fDescInfo.fReadsFragPosition || gp.willReadFragmentPosition();
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;
}
}
}

View File

@ -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,

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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()'