SkASSERT(tt.target());
GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setXPFactory(
+ GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
pipelineBuilder.setRenderTarget(rt);
BezierCubicOrConicTestBatch::Geometry geometry;
SkASSERT(tt.target());
GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setXPFactory(
+ GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
pipelineBuilder.setRenderTarget(rt);
BezierCubicOrConicTestBatch::Geometry geometry;
SkASSERT(tt.target());
GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setXPFactory(
+ GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
pipelineBuilder.setRenderTarget(rt);
GrPathUtils::QuadUVMatrix DevToUV(pts);
return;
}
GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setXPFactory(
+ GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
SkRRect rrect = fRRects[curRRect];
rrect.offset(SkIntToScalar(x), SkIntToScalar(y));
}
GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setXPFactory(
+ GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
pipelineBuilder.addCoverageFragmentProcessor(fp);
pipelineBuilder.setRenderTarget(rt);
}
GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setXPFactory(
+ GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
pipelineBuilder.addCoverageFragmentProcessor(fp);
pipelineBuilder.setRenderTarget(rt);
return;
}
GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setXPFactory(
+ GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
SkRRect rrect = fRRects[curRRect];
rrect.offset(SkIntToScalar(x), SkIntToScalar(y));
for (int m = 0; m < GrTextureDomain::kModeCount; ++m) {
GrTextureDomain::Mode mode = (GrTextureDomain::Mode) m;
GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setXPFactory(
+ GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
SkAutoTUnref<const GrFragmentProcessor> fp(
GrTextureDomainEffect::Create(texture, textureMatrices[tm],
GrTextureDomain::MakeTexelDomain(texture,
for (int i = 0; i < 6; ++i) {
GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setXPFactory(
+ GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
SkAutoTUnref<GrFragmentProcessor> fp(
GrYUVtoRGBEffect::Create(texture[indices[i][0]],
texture[indices[i][1]],
const GrFragmentProcessor* dst) const;
/** A subclass may implement this factory function to work with the GPU backend. It is legal
- to call this with xpf NULL to simply test the return value. If xpf is non-NULL then the
- xfermode may optionally allocate a factory to return to the caller as *xpf. The caller
- will install it and own a ref to it. Since the xfermode may or may not assign *xpf, the
- caller should set *xpf to NULL beforehand. XferProcessors cannot use a background texture.
- */
+ to call this with xpf NULL to simply test the return value. If xpf is non-NULL then the
+ xfermode may optionally allocate a factory to return to the caller as *xpf. The caller
+ will install it and own a ref to it. Since the xfermode may or may not assign *xpf, the
+ caller should set *xpf to NULL beforehand. XferProcessors cannot use a background texture.
+ */
virtual bool asXPFactory(GrXPFactory** xpf) const;
/** Returns true if the xfermode can be expressed as an xfer processor factory (xpFactory).
- This helper calls the asXPFactory() virtual. If the xfermode is NULL, it is treated as
- kSrcOver_Mode. It is legal to call this with xpf param NULL to simply test the return value.
- */
- static bool AsXPFactory(SkXfermode*, GrXPFactory**);
+ This helper calls the asXPFactory() virtual. If the xfermode is NULL, it is treated as
+ kSrcOver_Mode. It is legal to call this with xpf param NULL to simply test the return value.
+ */
+ static inline bool AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) {
+ if (nullptr == xfermode) {
+ if (xpf) {
+ *xpf = nullptr;
+ }
+ return true;
+ }
+ return xfermode->asXPFactory(xpf);
+ }
SK_TO_STRING_PUREVIRT()
SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
bool isAntiAlias() const { return fAntiAlias; }
const GrXPFactory* setXPFactory(const GrXPFactory* xpFactory) {
- fXPFactory.reset(SkRef(xpFactory));
+ fXPFactory.reset(SkSafeRef(xpFactory));
return xpFactory;
}
this->numCoverageFragmentProcessors(); }
const GrXPFactory* getXPFactory() const {
- if (!fXPFactory) {
- fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode));
- }
- return fXPFactory.get();
+ return fXPFactory;
}
const GrFragmentProcessor* getColorFragmentProcessor(int i) const {
fCoverageFragmentProcessors[i]->ref();
}
- fXPFactory.reset(SkRef(paint.getXPFactory()));
+ fXPFactory.reset(SkSafeRef(paint.getXPFactory()));
return *this;
}
bool hasMixedSamples,
const DstTexture*,
const GrCaps& caps) const;
-
- /**
- * This function returns true if the GrXferProcessor generated from this factory will be able to
- * correctly blend when using RGB coverage. The knownColor and knownColorFlags represent the
- * final computed color from the color stages.
- */
- virtual bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const = 0;
-
/**
* Known color information after blending, but before accounting for any coverage.
*/
public:
static GrXPFactory* Create(SkRegion::Op regionOp, bool invertCoverage = false);
- bool supportsRGBCoverage(GrColor /*knownColor*/,
- uint32_t /*knownColorFlags*/) const override {
- return true;
- }
-
void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
GrXPFactory::InvariantBlendedColor*) const override;
public:
static GrXPFactory* Create(SkXfermode::Mode mode);
- bool supportsRGBCoverage(GrColor /*knownColor*/, uint32_t /*knownColorFlags*/) const override {
- return true;
- }
-
void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
GrXPFactory::InvariantBlendedColor*) const override;
+ static GrXferProcessor* CreateSrcOverXferProcessor(const GrCaps& caps,
+ const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI,
+ bool hasMixedSamples,
+ const GrXferProcessor::DstTexture*);
+
+ static inline void SrcOverInvariantBlendedColor(
+ GrColor inputColor,
+ GrColorComponentFlags validColorFlags,
+ bool isOpaque,
+ GrXPFactory::InvariantBlendedColor* blendedColor) {
+ if (!isOpaque) {
+ blendedColor->fWillBlendWithDst = true;
+ blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
+ return;
+ }
+ blendedColor->fWillBlendWithDst = false;
+
+ blendedColor->fKnownColor = inputColor;
+ blendedColor->fKnownColorFlags = validColorFlags;
+ }
+
+ static bool SrcOverWillNeedDstTexture(const GrCaps& caps,
+ const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI,
+ bool hasMixedSamples);
+
private:
GrPorterDuffXPFactory(SkXfermode::Mode);
if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) {
SkASSERT(fp);
paint.addColorFragmentProcessor(fp)->unref();
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
if (drawContext) {
return false;
}
-
-#if SK_SUPPORT_GPU
-#include "effects/GrPorterDuffXferProcessor.h"
-
-bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) {
- if (nullptr == xfermode) {
- if (xpf) {
- *xpf = GrPorterDuffXPFactory::Create(kSrcOver_Mode);
- }
- return true;
- } else {
- return xfermode->asXPFactory(xpf);
- }
-}
-#else
-bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) {
- return false;
-}
-#endif
-
SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
// no-op. subclasses should override this
return dst;
#if SK_SUPPORT_GPU
#include "effects/GrCustomXfermode.h"
+#include "effects/GrPorterDuffXferProcessor.h"
#include "effects/GrXfermodeFragmentProcessor.h"
bool SkProcCoeffXfermode::asFragmentProcessor(const GrFragmentProcessor** fp,
return new GrArithmeticXPFactory(k1, k2, k3, k4, enforcePMColor);
}
- bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override {
- return true;
- }
-
void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
GrXPFactory::InvariantBlendedColor*) const override;
// outer: dst = dst * (1 - src)
// = 0 * src + (1 - src) * dst
paint.setCoverageSetOpXPFactory(SkRegion::kDifference_Op);
+ } else {
+ paint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
}
SkAutoTUnref<GrDrawContext> drawContext(context->drawContext((*result)->asRenderTarget()));
offsetMatrix,
color,
colorBM.dimensions()))->unref();
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
SkIRect colorBounds = bounds;
colorBounds.offset(-colorOffset);
SkMatrix matrix;
SkAutoTUnref<GrFragmentProcessor> conv(GrConvolutionEffect::CreateGaussian(
texture, direction, radius, sigma, useBounds, bounds));
paint.addColorFragmentProcessor(conv);
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
SkMatrix localMatrix = SkMatrix::MakeTrans(srcOffset.x(), srcOffset.y());
drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, localMatrix);
}
srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_Mode,
true, sigmaX, sigmaY));
paint.addColorFragmentProcessor(conv);
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, localMatrix);
}
GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode);
paint.addColorTextureProcessor(srcTexture, matrix, params);
}
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
i < scaleFactorY ? 0.5f : 1.0f);
// FIXME: this should be mitchell, not bilinear.
GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode);
paint.addColorTextureProcessor(srcTexture, matrix, params);
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
SkRect dstRect(srcRect);
scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
GrPaint paint;
GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, bounds, boundaryMode);
paint.addColorFragmentProcessor(fp)->unref();
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
}
radius,
morphType,
bounds))->unref();
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
drawContext->fillRectToRect(clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
SkRect::Make(srcRect));
}
direction,
radius,
morphType))->unref();
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
drawContext->fillRectToRect(clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
SkRect::Make(srcRect));
}
SkPerlinNoiseShader::CreateTurbulence(baseFrequencyX, baseFrequencyY, numOctaves, seed,
stitchTiles ? &tileSize : nullptr));
- GrPaint grPaint;
return shader->asFragmentProcessor(d->fContext,
GrTest::TestMatrix(d->fRandom), nullptr,
kNone_SkFilterQuality);
if (xferFP) {
paint.addColorFragmentProcessor(xferFP)->unref();
}
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));
if (!drawContext) {
SkAutoTUnref<const GrFragmentProcessor> fp;
SkMatrix textureMatrix;
textureMatrix.setIDiv(tempTexture->width(), tempTexture->height());
- GrPaint paint;
if (applyPremulToSrc) {
fp.reset(this->createUPMToPMEffect(tempTexture, tempDrawInfo.fSwapRAndB,
textureMatrix));
if (!drawContext) {
return false;
}
+ GrPaint paint;
paint.addColorFragmentProcessor(fp);
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
drawContext->drawRect(GrClip::WideOpen(), paint, matrix, rect, nullptr);
SkMatrix textureMatrix;
textureMatrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
textureMatrix.postIDiv(src->width(), src->height());
- GrPaint paint;
SkAutoTUnref<const GrFragmentProcessor> fp;
if (unpremul) {
fp.reset(this->createPMToUPMEffect(src->asTexture(), tempDrawInfo.fSwapRAndB,
GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
}
if (fp) {
+ GrPaint paint;
paint.addColorFragmentProcessor(fp);
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(temp->asRenderTarget()));
drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, nullptr);
}
GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setXPFactory(
+ GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
pipelineBuilder.setRenderTarget(renderTarget);
this->drawNonAARect(pipelineBuilder, color, SkMatrix::I(), *rect);
kRGBA_GrColorComponentFlags, false);
GrXPFactory::InvariantBlendedColor blendedColor;
- fXPFactory->getInvariantBlendedColor(colorProcInfo, &blendedColor);
+ if (fXPFactory) {
+ fXPFactory->getInvariantBlendedColor(colorProcInfo, &blendedColor);
+ } else {
+ GrPorterDuffXPFactory::SrcOverInvariantBlendedColor(colorProcInfo.color(),
+ colorProcInfo.validFlags(),
+ colorProcInfo.isOpaque(),
+ &blendedColor);
+ }
if (kRGBA_GrColorComponentFlags == blendedColor.fKnownColorFlags) {
*color = blendedColor.fKnownColor;
const GrPipelineBuilder& builder = *args.fPipelineBuilder;
// Create XferProcessor from DS's XPFactory
- SkAutoTUnref<GrXferProcessor> xferProcessor(
- builder.getXPFactory()->createXferProcessor(args.fColorPOI, args.fCoveragePOI,
- builder.hasMixedSamples(), &args.fDstTexture,
- *args.fCaps));
+ const GrXPFactory* xpFactory = builder.getXPFactory();
+ SkAutoTUnref<GrXferProcessor> xferProcessor;
+ if (xpFactory) {
+ xferProcessor.reset(xpFactory->createXferProcessor(args.fColorPOI,
+ args.fCoveragePOI,
+ builder.hasMixedSamples(),
+ &args.fDstTexture,
+ *args.fCaps));
+ } else {
+ xferProcessor.reset(GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
+ *args.fCaps,
+ args.fColorPOI,
+ args.fCoveragePOI,
+ builder.hasMixedSamples(),
+ &args.fDstTexture));
+ }
+
if (!xferProcessor) {
return nullptr;
}
}
GrPipeline* pipeline = new (memory) GrPipeline;
- pipeline->fXferProcessor.reset(xferProcessor.get());
+ pipeline->fXferProcessor.reset(xferProcessor);
pipeline->fRenderTarget.reset(builder.fRenderTarget.get());
SkASSERT(pipeline->fRenderTarget);
}
GrXPFactory::InvariantBlendedColor blendedColor;
- builder.fXPFactory->getInvariantBlendedColor(args.fColorPOI, &blendedColor);
+ if (xpFactory) {
+ xpFactory->getInvariantBlendedColor(args.fColorPOI, &blendedColor);
+ } else {
+ GrPorterDuffXPFactory::SrcOverInvariantBlendedColor(args.fColorPOI.color(),
+ args.fColorPOI.validFlags(),
+ args.fColorPOI.isOpaque(),
+ &blendedColor);
+ }
if (blendedColor.fWillBlendWithDst) {
opts->fFlags |= GrPipelineOptimizations::kWillColorBlendWithDst_Flag;
}
fCoverageFragmentProcessors.push_back(SkRef(paint.getCoverageFragmentProcessor(i)));
}
- fXPFactory.reset(SkRef(paint.getXPFactory()));
+ fXPFactory.reset(SkSafeRef(paint.getXPFactory()));
this->setRenderTarget(rt);
bool GrPipelineBuilder::willXPNeedDstTexture(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI) const {
- return this->getXPFactory()->willNeedDstTexture(caps, colorPOI, coveragePOI,
- this->hasMixedSamples());
+ if (this->getXPFactory()) {
+ return this->getXPFactory()->willNeedDstTexture(caps, colorPOI, coveragePOI,
+ this->hasMixedSamples());
+ }
+ return GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(caps, colorPOI, coveragePOI,
+ this->hasMixedSamples());
}
void GrPipelineBuilder::AutoRestoreFragmentProcessorState::set(
* and the dst color are blended.
*/
const GrXPFactory* setXPFactory(const GrXPFactory* xpFactory) {
- fXPFactory.reset(SkRef(xpFactory));
+ fXPFactory.reset(SkSafeRef(xpFactory));
return xpFactory;
}
}
const GrXPFactory* getXPFactory() const {
- if (!fXPFactory) {
- fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode));
- }
- return fXPFactory.get();
+ return fXPFactory;
}
/**
yuvInfo.fSize,
yuvInfo.fColorSpace));
paint.addColorFragmentProcessor(yuvToRgbProcessor);
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
const SkRect r = SkRect::MakeIWH(yuvInfo.fSize[0].fWidth, yuvInfo.fSize[0].fHeight);
SkAutoTUnref<GrDrawContext> drawContext(ctx->drawContext(renderTarget));
SkXfermode* mode = skPaint.getXfermode();
GrXPFactory* xpFactory = nullptr;
- if (!SkXfermode::AsXPFactory(mode, &xpFactory)) {
- // Fall back to src-over
- // return false here?
- xpFactory = GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode);
- }
- SkASSERT(xpFactory);
- grPaint->setXPFactory(xpFactory)->unref();
+ SkXfermode::AsXPFactory(mode, &xpFactory);
+ SkSafeUnref(grPaint->setXPFactory(xpFactory));
#ifndef SK_IGNORE_GPU_DITHER
if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0) {
const bool isHairline = stroke->isHairlineStyle();
// Save the current xp on the draw state so we can reset it if needed
- SkAutoTUnref<const GrXPFactory> backupXPFactory(SkRef(pipelineBuilder->getXPFactory()));
+ const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
+ SkAutoTUnref<const GrXPFactory> backupXPFactory(SkSafeRef(xpFactory));
// face culling doesn't make sense here
SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace());
tempTex, false, *pmToUPMRule, SkMatrix::I()));
paint1.addColorFragmentProcessor(pmToUPM1);
+ paint1.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
SkAutoTUnref<GrDrawContext> readDrawContext(
readTex->readPixels(0, 0, 256, 256, kRGBA_8888_GrPixelConfig, firstRead);
paint2.addColorFragmentProcessor(upmToPM);
+ paint2.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
SkAutoTUnref<GrDrawContext> tempDrawContext(
context->drawContext(tempTex->asRenderTarget()));
kSrcRect);
paint3.addColorFragmentProcessor(pmToUPM2);
+ paint3.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
readDrawContext.reset(context->drawContext(readTex->asRenderTarget()));
if (!readDrawContext) {
public:
CustomXPFactory(SkXfermode::Mode mode);
- bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override {
- return true;
- }
-
void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
GrXPFactory::InvariantBlendedColor*) const override;
public:
static GrXPFactory* Create() { return new GrDisableColorXPFactory; }
- bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override {
- return true;
- }
-
void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
GrXPFactory::InvariantBlendedColor* blendedColor) const override {
blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
*outPrimary = blendFormula.fPrimaryOutputType;
*outSecondary = blendFormula.fSecondaryOutputType;
}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+// SrcOver Global functions
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
+ const GrCaps& caps,
+ const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& covPOI,
+ bool hasMixedSamples,
+ const GrXferProcessor::DstTexture* dstTexture) {
+ BlendFormula blendFormula;
+ if (covPOI.isFourChannelOutput()) {
+ if (kRGBA_GrColorComponentFlags == colorPOI.validFlags() &&
+ !caps.shaderCaps()->dualSourceBlendingSupport() &&
+ !caps.shaderCaps()->dstReadInShaderSupport()) {
+ // If we don't have dual source blending or in shader dst reads, we fall
+ // back to this trick for rendering SrcOver LCD text instead of doing a
+ // dst copy.
+ SkASSERT(!dstTexture || !dstTexture->texture());
+ return PDLCDXferProcessor::Create(SkXfermode::kSrcOver_Mode, colorPOI);
+ }
+ blendFormula = get_lcd_blend_formula(covPOI, SkXfermode::kSrcOver_Mode);
+ } else {
+ blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples,
+ SkXfermode::kSrcOver_Mode);
+ }
+
+ if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
+ return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkXfermode::kSrcOver_Mode);
+ }
+
+ SkASSERT(!dstTexture || !dstTexture->texture());
+ return new PorterDuffXferProcessor(blendFormula);
+}
+
+bool GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(const GrCaps& caps,
+ const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& covPOI,
+ bool hasMixedSamples) {
+ if (caps.shaderCaps()->dstReadInShaderSupport() ||
+ caps.shaderCaps()->dualSourceBlendingSupport()) {
+ return false;
+ }
+
+ // When we have four channel coverage we always need to read the dst in order to correctly
+ // blend. The one exception is when we are using srcover mode and we know the input color
+ // into the XP.
+ if (covPOI.isFourChannelOutput()) {
+ if (kRGBA_GrColorComponentFlags == colorPOI.validFlags() &&
+ !caps.shaderCaps()->dstReadInShaderSupport()) {
+ return false;
+ }
+ return get_lcd_blend_formula(covPOI, SkXfermode::kSrcOver_Mode).hasSecondaryOutput();
+ }
+ // We fallback on the shader XP when the blend formula would use dual source blending but we
+ // don't have support for it.
+ return get_blend_formula(colorPOI, covPOI,
+ hasMixedSamples, SkXfermode::kSrcOver_Mode).hasSecondaryOutput();
+}
+
const SkPath& path) {
GrTessellatingPathRenderer tess;
GrPipelineBuilder pipelineBuilder;
+ pipelineBuilder.setXPFactory(
+ GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
pipelineBuilder.setRenderTarget(rt);
GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
GrPathRenderer::DrawPathArgs args;