--- /dev/null
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkArithmeticMode.h"
+#include "SkXfermodeImageFilter.h"
+#include "SkBitmapSource.h"
+
+#define WIDTH 600
+#define HEIGHT 600
+#define MARGIN 12
+
+namespace skiagm {
+
+class XfermodeImageFilterGM : public GM {
+public:
+ XfermodeImageFilterGM() : fInitialized(false) {
+ this->setBGColor(0xFF000000);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("xfermodeimagefilter");
+ }
+
+ void make_bitmap() {
+ fBitmap.setConfig(SkBitmap::kARGB_8888_Config, 80, 80);
+ fBitmap.allocPixels();
+ SkDevice device(fBitmap);
+ SkCanvas canvas(&device);
+ canvas.clear(0x00000000);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(0xD000D000);
+ paint.setTextSize(SkIntToScalar(96));
+ const char* str = "e";
+ canvas.drawText(str, strlen(str), SkIntToScalar(15), SkIntToScalar(65), paint);
+ }
+
+ void make_checkerboard() {
+ fCheckerboard.setConfig(SkBitmap::kARGB_8888_Config, 80, 80);
+ fCheckerboard.allocPixels();
+ SkDevice device(fCheckerboard);
+ SkCanvas canvas(&device);
+ canvas.clear(0x00000000);
+ SkPaint darkPaint;
+ darkPaint.setColor(0xFF404040);
+ SkPaint lightPaint;
+ lightPaint.setColor(0xFFA0A0A0);
+ for (int y = 0; y < 80; y += 16) {
+ for (int x = 0; x < 80; x += 16) {
+ canvas.save();
+ canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
+ canvas.drawRect(SkRect::MakeXYWH(0, 0, 8, 8), darkPaint);
+ canvas.drawRect(SkRect::MakeXYWH(8, 0, 8, 8), lightPaint);
+ canvas.drawRect(SkRect::MakeXYWH(0, 8, 8, 8), lightPaint);
+ canvas.drawRect(SkRect::MakeXYWH(8, 8, 8, 8), darkPaint);
+ canvas.restore();
+ }
+ }
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(WIDTH, HEIGHT);
+ }
+
+ void drawClippedBitmap(SkCanvas* canvas, const SkBitmap& bitmap, const SkPaint& paint, SkScalar x, SkScalar y) {
+ canvas->save();
+ canvas->clipRect(SkRect::MakeXYWH(x, y,
+ SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())));
+ canvas->drawBitmap(bitmap, x, y, &paint);
+ canvas->restore();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ if (!fInitialized) {
+ make_bitmap();
+ make_checkerboard();
+ fInitialized = true;
+ }
+ canvas->clear(0x00000000);
+ SkPaint paint;
+
+ const struct {
+ SkXfermode::Mode fMode;
+ const char* fLabel;
+ } gModes[] = {
+ { SkXfermode::kClear_Mode, "Clear" },
+ { SkXfermode::kSrc_Mode, "Src" },
+ { SkXfermode::kDst_Mode, "Dst" },
+ { SkXfermode::kSrcOver_Mode, "SrcOver" },
+ { SkXfermode::kDstOver_Mode, "DstOver" },
+ { SkXfermode::kSrcIn_Mode, "SrcIn" },
+ { SkXfermode::kDstIn_Mode, "DstIn" },
+ { SkXfermode::kSrcOut_Mode, "SrcOut" },
+ { SkXfermode::kDstOut_Mode, "DstOut" },
+ { SkXfermode::kSrcATop_Mode, "SrcATop" },
+ { SkXfermode::kDstATop_Mode, "DstATop" },
+ { SkXfermode::kXor_Mode, "Xor" },
+
+ { SkXfermode::kPlus_Mode, "Plus" },
+ { SkXfermode::kModulate_Mode, "Modulate" },
+ { SkXfermode::kScreen_Mode, "Screen" },
+ { SkXfermode::kOverlay_Mode, "Overlay" },
+ { SkXfermode::kDarken_Mode, "Darken" },
+ { SkXfermode::kLighten_Mode, "Lighten" },
+ { SkXfermode::kColorDodge_Mode, "ColorDodge" },
+ { SkXfermode::kColorBurn_Mode, "ColorBurn" },
+ { SkXfermode::kHardLight_Mode, "HardLight" },
+ { SkXfermode::kSoftLight_Mode, "SoftLight" },
+ { SkXfermode::kDifference_Mode, "Difference" },
+ { SkXfermode::kExclusion_Mode, "Exclusion" },
+ { SkXfermode::kMultiply_Mode, "Multiply" },
+ { SkXfermode::kHue_Mode, "Hue" },
+ { SkXfermode::kSaturation_Mode, "Saturation" },
+ { SkXfermode::kColor_Mode, "Color" },
+ { SkXfermode::kLuminosity_Mode, "Luminosity" },
+ };
+
+ int x = 0, y = 0;
+ SkAutoTUnref<SkImageFilter> background(SkNEW_ARGS(SkBitmapSource, (fCheckerboard)));
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
+ SkAutoTUnref<SkXfermode> mode(SkXfermode::Create(gModes[i].fMode));
+ SkAutoTUnref<SkImageFilter> filter(SkNEW_ARGS(SkXfermodeImageFilter, (mode, background)));
+ paint.setImageFilter(filter);
+ drawClippedBitmap(canvas, fBitmap, paint, SkIntToScalar(x), SkIntToScalar(y));
+ x += fBitmap.width() + MARGIN;
+ if (x + fBitmap.width() > WIDTH) {
+ x = 0;
+ y += fBitmap.height() + MARGIN;
+ }
+ }
+ // Test arithmetic mode as image filter
+ SkAutoTUnref<SkXfermode> mode(SkArithmeticMode::Create(0, SK_Scalar1, SK_Scalar1, 0));
+ SkAutoTUnref<SkImageFilter> filter(SkNEW_ARGS(SkXfermodeImageFilter, (mode, background)));
+ paint.setImageFilter(filter);
+ drawClippedBitmap(canvas, fBitmap, paint, SkIntToScalar(x), SkIntToScalar(y));
+ x += fBitmap.width() + MARGIN;
+ if (x + fBitmap.width() > WIDTH) {
+ x = 0;
+ y += fBitmap.height() + MARGIN;
+ }
+ // Test NULL mode
+ filter.reset(SkNEW_ARGS(SkXfermodeImageFilter, (NULL, background)));
+ paint.setImageFilter(filter);
+ drawClippedBitmap(canvas, fBitmap, paint, SkIntToScalar(x), SkIntToScalar(y));
+ }
+private:
+ typedef GM INHERITED;
+ SkBitmap fBitmap, fCheckerboard;
+ bool fInitialized;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new XfermodeImageFilterGM; }
+static GMRegistry reg(MyFactory);
+
+}
'sources': [
'<(skia_src_path)/effects/Sk1DPathEffect.cpp',
'<(skia_src_path)/effects/Sk2DPathEffect.cpp',
- '<(skia_src_path)/effects/SkAvoidXfermode.cpp',
'<(skia_src_path)/effects/SkArithmeticMode.cpp',
+ '<(skia_src_path)/effects/SkAvoidXfermode.cpp',
'<(skia_src_path)/effects/SkBicubicImageFilter.cpp',
'<(skia_src_path)/effects/SkBitmapSource.cpp',
'<(skia_src_path)/effects/SkBlendImageFilter.cpp',
'<(skia_src_path)/effects/SkLayerRasterizer.cpp',
'<(skia_src_path)/effects/SkLerpXfermode.cpp',
'<(skia_src_path)/effects/SkLightingImageFilter.cpp',
+ '<(skia_src_path)/effects/SkMagnifierImageFilter.cpp',
'<(skia_src_path)/effects/SkMatrixConvolutionImageFilter.cpp',
'<(skia_src_path)/effects/SkMergeImageFilter.cpp',
'<(skia_src_path)/effects/SkMorphologyImageFilter.cpp',
'<(skia_src_path)/effects/SkTableMaskFilter.cpp',
'<(skia_src_path)/effects/SkTestImageFilters.cpp',
'<(skia_src_path)/effects/SkTransparentShader.cpp',
- '<(skia_src_path)/effects/SkMagnifierImageFilter.cpp',
+ '<(skia_src_path)/effects/SkXfermodeImageFilter.cpp',
'<(skia_src_path)/effects/gradients/SkBitmapCache.cpp',
'<(skia_src_path)/effects/gradients/SkBitmapCache.h',
'<(skia_include_path)/effects/Sk1DPathEffect.h',
'<(skia_include_path)/effects/Sk2DPathEffect.h',
- '<(skia_include_path)/effects/SkAvoidXfermode.h',
+ '<(skia_include_path)/effects/SkXfermodeImageFilter.h',
'<(skia_include_path)/effects/SkArithmeticMode.h',
+ '<(skia_include_path)/effects/SkAvoidXfermode.h',
'<(skia_include_path)/effects/SkBitmapSource.h',
'<(skia_include_path)/effects/SkBlendImageFilter.h',
'<(skia_include_path)/effects/SkBlurDrawLooper.h',
'../gm/verttext.cpp',
'../gm/verttext2.cpp',
'../gm/verylargebitmap.cpp',
+ '../gm/xfermodeimagefilter.cpp',
'../gm/xfermodes.cpp',
'../gm/xfermodes2.cpp',
],
class GrContext;
class GrEffectRef;
+class GrTexture;
class SkString;
/** \class SkXfermode
it and own a ref to it. Since the xfermode may or may not assign *effect, the caller should
set *effect to NULL beforehand. If the function returns true and *effect is NULL then the
src and dst coeffs will be applied to the draw. When *effect is non-NULL the coeffs are
- ignored.
+ ignored. background specifies the texture to use as the background for compositing, and
+ should be accessed in the effect's fragment shader. If NULL, the effect should request
+ access to destination color (setWillReadDstColor()), and use that in the fragment shader
+ (builder->dstColor()).
*/
virtual bool asNewEffectOrCoeff(GrContext*,
GrEffectRef** effect,
Coeff* src,
- Coeff* dst) const;
+ Coeff* dst,
+ GrTexture* background = NULL) const;
/**
* The same as calling xfermode->asNewEffect(...), except that this also checks if the xfermode
GrContext*,
GrEffectRef** effect,
Coeff* src,
- Coeff* dst);
+ Coeff* dst,
+ GrTexture* background = NULL);
SkDEVCODE(virtual void toString(SkString* str) const = 0;)
SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
--- /dev/null
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkXfermodeImageFilter_DEFINED
+#define SkXfermodeImageFilter_DEFINED
+
+#include "SkImageFilter.h"
+
+class SkBitmap;
+class SkXfermode;
+
+class SK_API SkXfermodeImageFilter : public SkImageFilter {
+ /**
+ * This filter takes an xfermode, and uses it to composite the foreground
+ * over the background. If foreground or background is NULL, the input
+ * bitmap (src) is used instead.
+ */
+
+public:
+ SkXfermodeImageFilter(SkXfermode* mode, SkImageFilter* background, SkImageFilter* foreground = NULL);
+
+ virtual ~SkXfermodeImageFilter();
+
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkXfermodeImageFilter)
+
+ virtual bool onFilterImage(Proxy* proxy,
+ const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* dst,
+ SkIPoint* offset) SK_OVERRIDE;
+#if SK_SUPPORT_GPU
+ virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
+ virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
+#endif
+
+protected:
+ explicit SkXfermodeImageFilter(SkFlattenableReadBuffer& buffer);
+ virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
+
+private:
+ SkXfermode* fMode;
+ typedef SkImageFilter INHERITED;
+};
+
+#endif
return false;
}
-bool SkXfermode::asNewEffectOrCoeff(GrContext*, GrEffectRef**, Coeff* src, Coeff* dst) const {
+bool SkXfermode::asNewEffectOrCoeff(GrContext*, GrEffectRef**, Coeff* src, Coeff* dst, GrTexture*) const {
return this->asCoeff(src, dst);
}
GrContext* context,
GrEffectRef** effect,
Coeff* src,
- Coeff* dst) {
+ Coeff* dst,
+ GrTexture* background) {
if (NULL == xfermode) {
return ModeAsCoeff(kSrcOver_Mode, src, dst);
} else {
- return xfermode->asNewEffectOrCoeff(context, effect, src, dst);
+ return xfermode->asNewEffectOrCoeff(context, effect, src, dst, background);
}
}
#include "GrEffectUnitTest.h"
#include "GrTBackendEffectFactory.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLEffectMatrix.h"
/**
* GrEffect that implements the all the separable xfer modes that cannot be expressed as Coeffs.
return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode;
}
- static GrEffectRef* Create(SkXfermode::Mode mode) {
+ static GrEffectRef* Create(SkXfermode::Mode mode, GrTexture* background) {
if (!IsSupportedMode(mode)) {
return NULL;
} else {
- AutoEffectUnref effect(SkNEW_ARGS(XferEffect, (mode)));
+ AutoEffectUnref effect(SkNEW_ARGS(XferEffect, (mode, background)));
return CreateEffectRef(effect);
}
}
static const char* Name() { return "XferEffect"; }
SkXfermode::Mode mode() const { return fMode; }
+ const GrTextureAccess& backgroundAccess() const { return fBackgroundAccess; }
class GLEffect : public GrGLEffect {
public:
GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
- : GrGLEffect(factory ) {
+ : GrGLEffect(factory )
+ , fBackgroundEffectMatrix(kCoordsType) {
}
virtual void emitCode(GrGLShaderBuilder* builder,
const GrDrawEffect& drawEffect,
const char* outputColor,
const char* inputColor,
const TextureSamplerArray& samplers) SK_OVERRIDE {
- const char* dstColor = builder->dstColor();
+ SkXfermode::Mode mode = drawEffect.castEffect<XferEffect>().mode();
+ const GrTexture* backgroundTex = drawEffect.castEffect<XferEffect>().backgroundAccess().getTexture();
+ const char* dstColor;
+ if (backgroundTex) {
+ const char* bgCoords;
+ GrSLType bgCoordsType = fBackgroundEffectMatrix.emitCode(builder, key, &bgCoords, NULL, "BG");
+ dstColor = "bgColor";
+ builder->fsCodeAppendf("\t\tvec4 %s = ", dstColor);
+ builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
+ samplers[0],
+ bgCoords,
+ bgCoordsType);
+ builder->fsCodeAppendf(";\n");
+ } else {
+ dstColor = builder->dstColor();
+ }
GrAssert(NULL != dstColor);
// We don't try to optimize for this case at all
builder->fsCodeAppendf("\t\tconst vec4 ones = %s;\n", GrGLSLOnesVecf(4));
inputColor = "ones";
}
-
- SkXfermode::Mode mode = drawEffect.castEffect<XferEffect>().mode();
builder->fsCodeAppendf("\t\t// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
// These all perform src-over on the alpha channel.
}
static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
- return drawEffect.castEffect<XferEffect>().mode();
+ const XferEffect& xfer = drawEffect.castEffect<XferEffect>();
+ GrTexture* bgTex = xfer.backgroundAccess().getTexture();
+ EffectKey bgKey = 0;
+ if (bgTex) {
+ bgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(bgTex),
+ drawEffect,
+ GLEffect::kCoordsType,
+ bgTex);
+ }
+ EffectKey modeKey = xfer.mode() << GrGLEffectMatrix::kKeyBits;
+ return modeKey | bgKey;
}
- virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
+ virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) SK_OVERRIDE {
+ const XferEffect& xfer = drawEffect.castEffect<XferEffect>();
+ GrTexture* bgTex = xfer.backgroundAccess().getTexture();
+ if (bgTex) {
+ fBackgroundEffectMatrix.setData(uman,
+ GrEffect::MakeDivByTextureWHMatrix(bgTex),
+ drawEffect,
+ bgTex);
+ }
+ }
private:
static void HardLight(GrGLShaderBuilder* builder,
}
+ static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType;
+ GrGLEffectMatrix fBackgroundEffectMatrix;
typedef GrGLEffect INHERITED;
};
GR_DECLARE_EFFECT_TEST;
private:
- XferEffect(SkXfermode::Mode mode) : fMode(mode) { this->setWillReadDstColor(); }
- virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { return true; }
+ XferEffect(SkXfermode::Mode mode, GrTexture* background)
+ : fMode(mode) {
+ if (background) {
+ fBackgroundAccess.reset(background);
+ this->addTextureAccess(&fBackgroundAccess);
+ } else {
+ this->setWillReadDstColor();
+ }
+ }
+ virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
+ const XferEffect& s = CastEffect<XferEffect>(other);
+ return fMode == s.fMode &&
+ fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture();
+ }
SkXfermode::Mode fMode;
+ GrTextureAccess fBackgroundAccess;
typedef GrEffect INHERITED;
};
GrTexture*[]) {
int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
- static AutoEffectUnref gEffect(SkNEW_ARGS(XferEffect, (static_cast<SkXfermode::Mode>(mode))));
+ static AutoEffectUnref gEffect(SkNEW_ARGS(XferEffect, (static_cast<SkXfermode::Mode>(mode), NULL)));
return CreateEffectRef(gEffect);
}
virtual bool asNewEffectOrCoeff(GrContext*,
GrEffectRef** effect,
Coeff* src,
- Coeff* dst) const SK_OVERRIDE {
+ Coeff* dst,
+ GrTexture* background) const SK_OVERRIDE {
if (this->asCoeff(src, dst)) {
return true;
}
if (XferEffect::IsSupportedMode(fMode)) {
if (NULL != effect) {
- *effect = XferEffect::Create(fMode);
+ *effect = XferEffect::Create(fMode, background);
SkASSERT(NULL != *effect);
}
return true;
#if SK_SUPPORT_GPU
#include "GrContext.h"
#include "gl/GrGLEffect.h"
+#include "gl/GrGLEffectMatrix.h"
#include "GrTBackendEffectFactory.h"
#include "SkImageFilterUtils.h"
#endif
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar)
#if SK_SUPPORT_GPU
- virtual bool asNewEffectOrCoeff(GrContext*, GrEffectRef** effect, Coeff*, Coeff*) const SK_OVERRIDE;
+ virtual bool asNewEffectOrCoeff(GrContext*, GrEffectRef** effect, Coeff*, Coeff*, GrTexture* background) const SK_OVERRIDE;
#endif
private:
private:
static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType;
-
+ GrGLEffectMatrix fBackgroundEffectMatrix;
GrGLUniformManager::UniformHandle fKUni;
typedef GrGLEffect INHERITED;
class GrArithmeticEffect : public GrEffect {
public:
- static GrEffectRef* Create(float k1, float k2, float k3, float k4) {
- AutoEffectUnref effect(SkNEW_ARGS(GrArithmeticEffect, (k1, k2, k3, k4)));
+ static GrEffectRef* Create(float k1, float k2, float k3, float k4, GrTexture* background) {
+ AutoEffectUnref effect(SkNEW_ARGS(GrArithmeticEffect, (k1, k2, k3, k4, background)));
return CreateEffectRef(effect);
}
typedef GrGLArithmeticEffect GLEffect;
static const char* Name() { return "Arithmetic"; }
+ GrTexture* backgroundTexture() const { return fBackgroundAccess.getTexture(); }
virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
private:
virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
- GrArithmeticEffect(float k1, float k2, float k3, float k4);
+ GrArithmeticEffect(float k1, float k2, float k3, float k4, GrTexture* background);
float fK1, fK2, fK3, fK4;
+ GrTextureAccess fBackgroundAccess;
GR_DECLARE_EFFECT_TEST;
typedef GrEffect INHERITED;
///////////////////////////////////////////////////////////////////////////////
-GrArithmeticEffect::GrArithmeticEffect(float k1, float k2, float k3, float k4)
+GrArithmeticEffect::GrArithmeticEffect(float k1, float k2, float k3, float k4,
+ GrTexture* background)
: fK1(k1), fK2(k2), fK3(k3), fK4(k4) {
- this->setWillReadDstColor();
+ if (background) {
+ fBackgroundAccess.reset(background);
+ this->addTextureAccess(&fBackgroundAccess);
+ } else {
+ this->setWillReadDstColor();
+ }
}
GrArithmeticEffect::~GrArithmeticEffect() {
return fK1 == s.fK1 &&
fK2 == s.fK2 &&
fK3 == s.fK3 &&
- fK4 == s.fK4;
+ fK4 == s.fK4 &&
+ backgroundTexture() == s.backgroundTexture();
}
const GrBackendEffectFactory& GrArithmeticEffect::getFactory() const {
///////////////////////////////////////////////////////////////////////////////
GrGLArithmeticEffect::GrGLArithmeticEffect(const GrBackendEffectFactory& factory,
- const GrDrawEffect& drawEffect) : INHERITED(factory) {
+ const GrDrawEffect& drawEffect)
+ : INHERITED(factory)
+ , fBackgroundEffectMatrix(kCoordsType) {
}
GrGLArithmeticEffect::~GrGLArithmeticEffect() {
}
void GrGLArithmeticEffect::emitCode(GrGLShaderBuilder* builder,
- const GrDrawEffect&,
+ const GrDrawEffect& drawEffect,
EffectKey key,
const char* outputColor,
const char* inputColor,
const TextureSamplerArray& samplers) {
- const char* dstColor = builder->dstColor();
+
+ GrTexture* backgroundTex = drawEffect.castEffect<GrArithmeticEffect>().backgroundTexture();
+ const char* dstColor;
+ if (backgroundTex) {
+ const char* bgCoords;
+ GrSLType bgCoordsType = fBackgroundEffectMatrix.emitCode(builder, key, &bgCoords, NULL, "BG");
+ builder->fsCodeAppend("\t\tvec4 bgColor = ");
+ builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
+ samplers[0],
+ bgCoords,
+ bgCoordsType);
+ builder->fsCodeAppendf(";\n");
+ dstColor = "bgColor";
+ } else {
+ dstColor = builder->dstColor();
+ }
+
GrAssert(NULL != dstColor);
fKUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
kVec4f_GrSLType, "k");
void GrGLArithmeticEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) {
const GrArithmeticEffect& arith = drawEffect.castEffect<GrArithmeticEffect>();
uman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
+ GrTexture* bgTex = arith.backgroundTexture();
+ if (bgTex) {
+ fBackgroundEffectMatrix.setData(uman,
+ GrEffect::MakeDivByTextureWHMatrix(bgTex),
+ drawEffect,
+ bgTex);
+ }
}
GrGLEffect::EffectKey GrGLArithmeticEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
- return 0;
+ const GrArithmeticEffect& effect = drawEffect.castEffect<GrArithmeticEffect>();
+ GrTexture* bgTex = effect.backgroundTexture();
+ EffectKey bgKey = 0;
+ if (bgTex) {
+ bgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(bgTex),
+ drawEffect,
+ GrGLArithmeticEffect::kCoordsType,
+ bgTex);
+ }
+ return bgKey;
}
GrEffectRef* GrArithmeticEffect::TestCreate(SkMWCRandom* rand,
float k3 = rand->nextF();
float k4 = rand->nextF();
- static AutoEffectUnref gEffect(SkNEW_ARGS(GrArithmeticEffect, (k1, k2, k3, k4)));
+ static AutoEffectUnref gEffect(SkNEW_ARGS(GrArithmeticEffect, (k1, k2, k3, k4, NULL)));
return CreateEffectRef(gEffect);
}
bool SkArithmeticMode_scalar::asNewEffectOrCoeff(GrContext*,
GrEffectRef** effect,
Coeff*,
- Coeff*) const {
+ Coeff*,
+ GrTexture* background) const {
if (effect) {
*effect = GrArithmeticEffect::Create(SkScalarToFloat(fK[0]),
SkScalarToFloat(fK[1]),
SkScalarToFloat(fK[2]),
- SkScalarToFloat(fK[3]));
+ SkScalarToFloat(fK[3]),
+ background);
}
return true;
}
--- /dev/null
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkXfermodeImageFilter.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkFlattenableBuffers.h"
+#include "SkXfermode.h"
+#if SK_SUPPORT_GPU
+#include "GrContext.h"
+#include "effects/GrSimpleTextureEffect.h"
+#include "SkGr.h"
+#include "SkImageFilterUtils.h"
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkXfermodeImageFilter::SkXfermodeImageFilter(SkXfermode* mode, SkImageFilter* background, SkImageFilter* foreground)
+ : INHERITED(background, foreground), fMode(mode) {
+ SkSafeRef(fMode);
+}
+
+SkXfermodeImageFilter::~SkXfermodeImageFilter() {
+ SkSafeUnref(fMode);
+}
+
+SkXfermodeImageFilter::SkXfermodeImageFilter(SkFlattenableReadBuffer& buffer)
+ : INHERITED(buffer) {
+ fMode = buffer.readFlattenableT<SkXfermode>();
+}
+
+void SkXfermodeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
+ this->INHERITED::flatten(buffer);
+ buffer.writeFlattenable(fMode);
+}
+
+bool SkXfermodeImageFilter::onFilterImage(Proxy* proxy,
+ const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* dst,
+ SkIPoint* offset) {
+ SkBitmap background = src, foreground = src;
+ SkImageFilter* backgroundInput = getInput(0);
+ SkImageFilter* foregroundInput = getInput(1);
+ if (backgroundInput && !backgroundInput->filterImage(proxy, src, ctm, &background, offset)) {
+ return false;
+ }
+ if (foregroundInput && !foregroundInput->filterImage(proxy, src, ctm, &foreground, offset)) {
+ return false;
+ }
+ dst->setConfig(background.config(), background.width(), background.height());
+ dst->allocPixels();
+ SkCanvas canvas(*dst);
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas.drawBitmap(background, 0, 0, &paint);
+ paint.setXfermode(fMode);
+ canvas.drawBitmap(foreground, 0, 0, &paint);
+ return true;
+}
+
+#if SK_SUPPORT_GPU
+
+bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
+ SkBitmap background;
+ if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &background)) {
+ return false;
+ }
+ GrTexture* backgroundTex = (GrTexture*) background.getTexture();
+ SkBitmap foreground;
+ if (!SkImageFilterUtils::GetInputResultGPU(getInput(1), proxy, src, &foreground)) {
+ return false;
+ }
+ GrTexture* foregroundTex = (GrTexture*) foreground.getTexture();
+ GrContext* context = foregroundTex->getContext();
+
+ GrEffectRef* xferEffect = NULL;
+
+ GrTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
+ desc.fWidth = src.width();
+ desc.fHeight = src.height();
+ desc.fConfig = kSkia8888_GrPixelConfig;
+
+ GrAutoScratchTexture ast(context, desc);
+ SkAutoTUnref<GrTexture> dst(ast.detach());
+
+ GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
+
+ SkXfermode::Coeff sm, dm;
+ if (!SkXfermode::AsNewEffectOrCoeff(fMode, context, &xferEffect, &sm, &dm, backgroundTex)) {
+ return false;
+ }
+
+ GrPaint paint;
+ SkRect srcRect;
+ src.getBounds(&srcRect);
+ if (NULL != xferEffect) {
+ paint.colorStage(0)->setEffect(
+ GrSimpleTextureEffect::Create(foregroundTex, GrEffect::MakeDivByTextureWHMatrix(foregroundTex)))->unref();
+ paint.colorStage(1)->setEffect(xferEffect);
+ context->drawRect(paint, srcRect);
+ } else {
+ paint.colorStage(0)->setEffect(
+ GrSimpleTextureEffect::Create(backgroundTex, GrEffect::MakeDivByTextureWHMatrix(backgroundTex)))->unref();
+ context->drawRect(paint, srcRect);
+ paint.setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm));
+ paint.colorStage(0)->setEffect(
+ GrSimpleTextureEffect::Create(foregroundTex, GrEffect::MakeDivByTextureWHMatrix(foregroundTex)))->unref();
+ context->drawRect(paint, srcRect);
+ }
+ return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), result);
+}
+
+#endif
#include "SkStippleMaskFilter.h"
#include "SkTableColorFilter.h"
#include "SkTestImageFilters.h"
+#include "SkXfermodeImageFilter.h"
void SkFlattenable::InitializeFlattenables() {
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPixelXorXfermode)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkStippleMaskFilter)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSumPathEffect)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkXfermodeImageFilter)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMagnifierImageFilter)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMatrixConvolutionImageFilter)