Alter SkXfermode's asFragmentProcessor & asXPFactory contracts

TBR=bsalomon@google.com

GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1674673002

Review URL: https://codereview.chromium.org/1674673002
This commit is contained in:
robertphillips 2016-02-09 05:09:27 -08:00 committed by Commit bot
parent 81bb79b7b9
commit 4f0379444d
12 changed files with 159 additions and 176 deletions

View File

@ -52,9 +52,9 @@ public:
const SkAlpha aa[]) const override;
#if SK_SUPPORT_GPU
bool asFragmentProcessor(const GrFragmentProcessor** output,
const GrFragmentProcessor* dst) const override;
bool asXPFactory(GrXPFactory** xpf) const override;
const GrFragmentProcessor* getFragmentProcessorForImageFilter(
const GrFragmentProcessor* dst) const override;
GrXPFactory* asXPFactory() const override;
#endif
SK_TO_STRING_OVERRIDE()

View File

@ -22,10 +22,9 @@ public:
}
#if SK_SUPPORT_GPU
bool asFragmentProcessor(const GrFragmentProcessor** output,
const GrFragmentProcessor* dst) const override;
bool asXPFactory(GrXPFactory**) const override;
const GrFragmentProcessor* getFragmentProcessorForImageFilter(
const GrFragmentProcessor* dst) const override;
GrXPFactory* asXPFactory() const override;
#endif
SK_TO_STRING_OVERRIDE()

View File

@ -194,37 +194,22 @@ public:
*/
static bool IsOpaque(const SkXfermode* xfer, SrcColorOpacity opacityType);
/** Used to do in-shader blending between two colors computed in the shader via a
GrFragmentProcessor. The input to the returned FP is the src color. The dst color is
provided by the dst param which becomes a child FP of the returned FP. If the params are
null then this is just a query of whether the SkXfermode could support this functionality.
It is legal for the function to succeed but return a null output. This indicates that
#if SK_SUPPORT_GPU
/** Used by the SkXfermodeImageFilter to blend two colors via a GrFragmentProcessor.
The input to the returned FP is the src color. The dst color is
provided by the dst param which becomes a child FP of the returned FP.
It is legal for the function to return a null output. This indicates that
the output of the blend is simply the src color.
*/
virtual bool asFragmentProcessor(const GrFragmentProcessor** output,
const GrFragmentProcessor* dst) const;
virtual const GrFragmentProcessor* getFragmentProcessorForImageFilter(
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.
/** A subclass must implement this factory function to work with the GPU backend.
The xfermode will return a factory for which the caller will get a ref. It is up
to the caller to install it. 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 inline bool AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) {
if (nullptr == xfermode) {
if (xpf) {
*xpf = nullptr;
}
return true;
}
return xfermode->asXPFactory(xpf);
}
virtual GrXPFactory* asXPFactory() const;
#endif
SK_TO_STRING_PUREVIRT()
SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()

View File

@ -21,8 +21,6 @@ class SK_API SkXfermodeImageFilter : public SkImageFilter {
*/
public:
virtual ~SkXfermodeImageFilter();
static SkImageFilter* Create(SkXfermode* mode, SkImageFilter* background,
SkImageFilter* foreground = NULL,
const CropRect* cropRect = NULL) {
@ -50,7 +48,7 @@ protected:
void flatten(SkWriteBuffer&) const override;
private:
SkXfermode* fMode;
SkAutoTUnref<SkXfermode> fMode;
typedef SkImageFilter INHERITED;
};

View File

@ -737,14 +737,22 @@ bool SkXfermode::asMode(Mode* mode) const {
return false;
}
bool SkXfermode::asFragmentProcessor(const GrFragmentProcessor**,
const GrFragmentProcessor*) const {
return false;
#if SK_SUPPORT_GPU
const GrFragmentProcessor* SkXfermode::getFragmentProcessorForImageFilter(
const GrFragmentProcessor*) const {
// This should never be called.
// TODO: make pure virtual in SkXfermode once Android update lands
SkASSERT(0);
return nullptr;
}
bool SkXfermode::asXPFactory(GrXPFactory**) const {
return false;
GrXPFactory* SkXfermode::asXPFactory() const {
// This should never be called.
// TODO: make pure virtual in SkXfermode once Android update lands
SkASSERT(0);
return nullptr;
}
#endif
SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
// no-op. subclasses should override this
@ -989,33 +997,21 @@ void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
#include "effects/GrPorterDuffXferProcessor.h"
#include "effects/GrXfermodeFragmentProcessor.h"
bool SkProcCoeffXfermode::asFragmentProcessor(const GrFragmentProcessor** fp,
const GrFragmentProcessor* dst) const {
if (fp) {
SkASSERT(dst);
*fp = GrXfermodeFragmentProcessor::CreateFromDstProcessor(dst, fMode);
SkASSERT(*fp || kSrc_Mode == fMode);
}
return true;
const GrFragmentProcessor* SkProcCoeffXfermode::getFragmentProcessorForImageFilter(
const GrFragmentProcessor* dst) const {
SkASSERT(dst);
return GrXfermodeFragmentProcessor::CreateFromDstProcessor(dst, fMode);
}
bool SkProcCoeffXfermode::asXPFactory(GrXPFactory** xp) const {
GrXPFactory* SkProcCoeffXfermode::asXPFactory() const {
if (CANNOT_USE_COEFF != fSrcCoeff) {
if (xp) {
*xp = GrPorterDuffXPFactory::Create(fMode);
SkASSERT(*xp);
}
return true;
GrXPFactory* result = GrPorterDuffXPFactory::Create(fMode);
SkASSERT(result);
return result;
}
if (GrCustomXfermode::IsSupportedMode(fMode)) {
if (xp) {
*xp = GrCustomXfermode::CreateXPFactory(fMode);
SkASSERT(*xp);
}
return true;
}
return false;
SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
return GrCustomXfermode::CreateXPFactory(fMode);
}
#endif

View File

@ -45,10 +45,9 @@ public:
bool isOpaque(SkXfermode::SrcColorOpacity opacityType) const override;
#if SK_SUPPORT_GPU
bool asFragmentProcessor(const GrFragmentProcessor**,
const GrFragmentProcessor*) const override;
bool asXPFactory(GrXPFactory**) const override;
const GrFragmentProcessor* getFragmentProcessorForImageFilter(
const GrFragmentProcessor*) const override;
GrXPFactory* asXPFactory() const override;
#endif
SK_TO_STRING_OVERRIDE()

View File

@ -39,10 +39,9 @@ public:
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar)
#if SK_SUPPORT_GPU
bool asFragmentProcessor(const GrFragmentProcessor**,
const GrFragmentProcessor* dst) const override;
bool asXPFactory(GrXPFactory**) const override;
const GrFragmentProcessor* getFragmentProcessorForImageFilter(
const GrFragmentProcessor* dst) const override;
GrXPFactory* asXPFactory() const override;
#endif
private:
@ -244,28 +243,22 @@ SkXfermode* SkArithmeticMode::Create(SkScalar k1, SkScalar k2,
//////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
bool SkArithmeticMode_scalar::asFragmentProcessor(const GrFragmentProcessor** fp,
const GrFragmentProcessor* dst) const {
if (fp) {
*fp = GrArithmeticFP::Create(SkScalarToFloat(fK[0]),
SkScalarToFloat(fK[1]),
SkScalarToFloat(fK[2]),
SkScalarToFloat(fK[3]),
fEnforcePMColor,
dst);
}
return true;
const GrFragmentProcessor* SkArithmeticMode_scalar::getFragmentProcessorForImageFilter(
const GrFragmentProcessor* dst) const {
return GrArithmeticFP::Create(SkScalarToFloat(fK[0]),
SkScalarToFloat(fK[1]),
SkScalarToFloat(fK[2]),
SkScalarToFloat(fK[3]),
fEnforcePMColor,
dst);
}
bool SkArithmeticMode_scalar::asXPFactory(GrXPFactory** xpf) const {
if (xpf) {
*xpf = GrArithmeticXPFactory::Create(SkScalarToFloat(fK[0]),
SkScalarToFloat(fK[1]),
SkScalarToFloat(fK[2]),
SkScalarToFloat(fK[3]),
fEnforcePMColor);
}
return true;
GrXPFactory* SkArithmeticMode_scalar::asXPFactory() const {
return GrArithmeticXPFactory::Create(SkScalarToFloat(fK[0]),
SkScalarToFloat(fK[1]),
SkScalarToFloat(fK[2]),
SkScalarToFloat(fK[3]),
fEnforcePMColor);
}
#endif

View File

@ -521,19 +521,13 @@ const GrXPFactory* GrAvoidXPFactory::TestCreate(GrProcessorTestData* d) {
///////////////////////////////////////////////////////////////////////////////
bool SkAvoidXfermode::asFragmentProcessor(const GrFragmentProcessor** output,
const GrFragmentProcessor* dst) const {
if (output) {
*output = AvoidFP::Create(fOpColor, fTolerance, fMode, dst);
}
return true;
const GrFragmentProcessor* SkAvoidXfermode::getFragmentProcessorForImageFilter(
const GrFragmentProcessor* dst) const {
return AvoidFP::Create(fOpColor, fTolerance, fMode, dst);
}
bool SkAvoidXfermode::asXPFactory(GrXPFactory** xpf) const {
if (xpf) {
*xpf = GrAvoidXPFactory::Create(fOpColor, fTolerance, fMode);
}
return true;
GrXPFactory* SkAvoidXfermode::asXPFactory() const {
return GrAvoidXPFactory::Create(fOpColor, fTolerance, fMode);
}
#endif

View File

@ -368,19 +368,13 @@ const GrXPFactory* GrPixelXorXPFactory::TestCreate(GrProcessorTestData* d) {
///////////////////////////////////////////////////////////////////////////////
bool SkPixelXorXfermode::asFragmentProcessor(const GrFragmentProcessor** output,
const GrFragmentProcessor* dst) const {
if (output) {
*output = PixelXorFP::Create(fOpColor, dst);
}
return true;
const GrFragmentProcessor* SkPixelXorXfermode::getFragmentProcessorForImageFilter(
const GrFragmentProcessor* dst) const {
return PixelXorFP::Create(fOpColor, dst);
}
bool SkPixelXorXfermode::asXPFactory(GrXPFactory** xpf) const {
if (xpf) {
*xpf = GrPixelXorXPFactory::Create(fOpColor);
}
return true;
GrXPFactory* SkPixelXorXfermode::asXPFactory() const {
return GrPixelXorXPFactory::Create(fOpColor);
}
#endif

View File

@ -15,6 +15,7 @@
#if SK_SUPPORT_GPU
#include "GrContext.h"
#include "GrDrawContext.h"
#include "effects/GrConstColorProcessor.h"
#include "effects/GrTextureDomain.h"
#include "effects/GrSimpleTextureEffect.h"
#include "SkGr.h"
@ -25,12 +26,8 @@
SkXfermodeImageFilter::SkXfermodeImageFilter(SkXfermode* mode,
SkImageFilter* inputs[2],
const CropRect* cropRect)
: INHERITED(2, inputs, cropRect), fMode(mode) {
SkSafeRef(fMode);
}
SkXfermodeImageFilter::~SkXfermodeImageFilter() {
SkSafeUnref(fMode);
: INHERITED(2, inputs, cropRect)
, fMode(SkSafeRef(mode)) {
}
SkFlattenable* SkXfermodeImageFilter::CreateProc(SkReadBuffer& buffer) {
@ -45,10 +42,10 @@ void SkXfermodeImageFilter::flatten(SkWriteBuffer& buffer) const {
}
bool SkXfermodeImageFilter::onFilterImage(Proxy* proxy,
const SkBitmap& src,
const Context& ctx,
SkBitmap* dst,
SkIPoint* offset) const {
const SkBitmap& src,
const Context& ctx,
SkBitmap* dst,
SkIPoint* offset) const {
SkBitmap background = src, foreground = src;
SkIPoint backgroundOffset = SkIPoint::Make(0, 0);
if (!this->filterInput(0, proxy, src, ctx, &background, &backgroundOffset)) {
@ -120,41 +117,47 @@ void SkXfermodeImageFilter::toString(SkString* str) const {
#if SK_SUPPORT_GPU
bool SkXfermodeImageFilter::canFilterImageGPU() const {
return fMode && fMode->asFragmentProcessor(nullptr, nullptr) && !cropRectIsSet();
return !this->cropRectIsSet();
}
#include "SkXfermode_proccoeff.h"
bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy,
const SkBitmap& src,
const Context& ctx,
SkBitmap* result,
SkIPoint* offset) const {
GrContext* context = nullptr;
SkBitmap background = src;
SkIPoint backgroundOffset = SkIPoint::Make(0, 0);
if (!this->filterInputGPU(0, proxy, src, ctx, &background, &backgroundOffset)) {
return false;
background.reset();
}
GrTexture* backgroundTex = background.getTexture();
if (nullptr == backgroundTex) {
SkASSERT(false);
return false;
if (backgroundTex) {
context = backgroundTex->getContext();
}
SkBitmap foreground = src;
SkIPoint foregroundOffset = SkIPoint::Make(0, 0);
if (!this->filterInputGPU(1, proxy, src, ctx, &foreground, &foregroundOffset)) {
return false;
foreground.reset();
}
GrTexture* foregroundTex = foreground.getTexture();
GrContext* context = foregroundTex->getContext();
if (foregroundTex) {
context = foregroundTex->getContext();
}
if (!context) {
return false;
}
SkIRect bounds = background.bounds().makeOffset(backgroundOffset.x(), backgroundOffset.y());
bounds.join(foreground.bounds().makeOffset(foregroundOffset.x(), foregroundOffset.y()));
if (bounds.isEmpty()) {
return false;
}
const GrFragmentProcessor* xferFP = nullptr;
GrSurfaceDesc desc;
desc.fFlags = kRenderTarget_GrSurfaceFlag;
desc.fWidth = bounds.width();
@ -166,39 +169,62 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy,
}
GrPaint paint;
SkMatrix backgroundMatrix;
backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height());
backgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX),
SkIntToScalar(-backgroundOffset.fY));
SkAutoTUnref<const GrFragmentProcessor> bgFP(GrTextureDomainEffect::Create(
backgroundTex, backgroundMatrix,
GrTextureDomain::MakeTexelDomain(backgroundTex, background.bounds()),
GrTextureDomain::kDecal_Mode,
GrTextureParams::kNone_FilterMode)
);
if (!fMode || !fMode->asFragmentProcessor(&xferFP, bgFP)) {
// canFilterImageGPU() should've taken care of this
SkASSERT(false);
return false;
SkAutoTUnref<const GrFragmentProcessor> bgFP;
if (backgroundTex) {
SkMatrix backgroundMatrix;
backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height());
backgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX),
SkIntToScalar(-backgroundOffset.fY));
bgFP.reset(GrTextureDomainEffect::Create(
backgroundTex, backgroundMatrix,
GrTextureDomain::MakeTexelDomain(backgroundTex, background.bounds()),
GrTextureDomain::kDecal_Mode,
GrTextureParams::kNone_FilterMode));
} else {
bgFP.reset(GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
GrConstColorProcessor::kIgnore_InputMode));
}
SkMatrix foregroundMatrix;
foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height());
foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX),
SkIntToScalar(-foregroundOffset.fY));
if (foregroundTex) {
SkMatrix foregroundMatrix;
foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height());
foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX),
SkIntToScalar(-foregroundOffset.fY));
SkAutoTUnref<const GrFragmentProcessor> foregroundFP;
SkAutoTUnref<const GrFragmentProcessor> foregroundFP(GrTextureDomainEffect::Create(
foregroundTex, foregroundMatrix,
GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()),
GrTextureDomain::kDecal_Mode,
GrTextureParams::kNone_FilterMode)
);
foregroundFP.reset(GrTextureDomainEffect::Create(
foregroundTex, foregroundMatrix,
GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()),
GrTextureDomain::kDecal_Mode,
GrTextureParams::kNone_FilterMode));
paint.addColorFragmentProcessor(foregroundFP.get());
if (xferFP) {
paint.addColorFragmentProcessor(xferFP)->unref();
paint.addColorFragmentProcessor(foregroundFP.get());
// A null fMode is interpreted to mean kSrcOver_Mode (to match raster).
SkAutoTUnref<SkXfermode> mode(SkSafeRef(fMode.get()));
if (!mode) {
// It would be awesome to use SkXfermode::Create here but it knows better
// than us and won't return a kSrcOver_Mode SkXfermode. That means we
// have to get one the hard way.
struct ProcCoeff rec;
rec.fProc = SkXfermode::GetProc(SkXfermode::kSrcOver_Mode);
SkXfermode::ModeAsCoeff(SkXfermode::kSrcOver_Mode, &rec.fSC, &rec.fDC);
mode.reset(new SkProcCoeffXfermode(rec, SkXfermode::kSrcOver_Mode));
}
SkAutoTUnref<const GrFragmentProcessor> xferFP(mode->getFragmentProcessorForImageFilter(bgFP));
// A null 'xferFP' here means kSrc_Mode was used in which case we can just proceed
if (xferFP) {
paint.addColorFragmentProcessor(xferFP);
}
} else {
paint.addColorFragmentProcessor(bgFP);
}
paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget()));

View File

@ -489,10 +489,15 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context,
}
}
SkXfermode* mode = skPaint.getXfermode();
GrXPFactory* xpFactory = nullptr;
SkXfermode::AsXPFactory(mode, &xpFactory);
SkSafeUnref(grPaint->setXPFactory(xpFactory));
// When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field on
// the GrPaint to also be null (also kSrcOver).
SkASSERT(!grPaint->getXPFactory());
SkXfermode* xfermode = skPaint.getXfermode();
if (xfermode) {
// SafeUnref in case a new xfermode is added that returns null.
// In such cases we will fall back to kSrcOver_Mode.
SkSafeUnref(grPaint->setXPFactory(xfermode->asXPFactory()));
}
#ifndef SK_IGNORE_GPU_DITHER
if (skPaint.isDither() && grPaint->numColorFragmentProcessors() > 0) {

View File

@ -291,19 +291,13 @@ public:
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkOverdrawXfermode)
#if SK_SUPPORT_GPU
bool asFragmentProcessor(const GrFragmentProcessor** output,
const GrFragmentProcessor* dst) const override {
if (output) {
*output = GrOverdrawFP::Create(dst);
}
return true;
const GrFragmentProcessor* getFragmentProcessorForImageFilter(
const GrFragmentProcessor* dst) const override {
return GrOverdrawFP::Create(dst);
}
bool asXPFactory(GrXPFactory** xpf) const override {
if (xpf) {
*xpf = GrOverdrawXPFactory::Create();
}
return true;
GrXPFactory* asXPFactory() const override {
return GrOverdrawXPFactory::Create();
}
#endif