Index: src/effects/SkXfermodeImageFilter.cpp |
diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp |
index 5f88240481b316c7e0c6b7d57f0a22ed815d004a..fbceedb0dd6e0b53e605660a19384a1b48ad234d 100644 |
--- a/src/effects/SkXfermodeImageFilter.cpp |
+++ b/src/effects/SkXfermodeImageFilter.cpp |
@@ -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)); |
+ } |
+ |
+ if (foregroundTex) { |
+ SkMatrix foregroundMatrix; |
+ foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); |
+ foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), |
+ SkIntToScalar(-foregroundOffset.fY)); |
+ |
+ SkAutoTUnref<const GrFragmentProcessor> foregroundFP; |
+ |
+ foregroundFP.reset(GrTextureDomainEffect::Create( |
+ foregroundTex, foregroundMatrix, |
+ GrTextureDomain::MakeTexelDomain(foregroundTex, foreground.bounds()), |
+ GrTextureDomain::kDecal_Mode, |
+ GrTextureParams::kNone_FilterMode)); |
+ |
+ 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); |
} |
- SkMatrix foregroundMatrix; |
- foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height()); |
- foregroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), |
- SkIntToScalar(-foregroundOffset.fY)); |
- |
- |
- SkAutoTUnref<const GrFragmentProcessor> foregroundFP(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.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); |
SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(dst->asRenderTarget())); |