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