| Index: src/effects/SkArithmeticImageFilter.cpp
|
| diff --git a/src/effects/SkArithmeticImageFilter.cpp b/src/effects/SkArithmeticImageFilter.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6eccb17f026b46411b10070de7c2ffab1867d04f
|
| --- /dev/null
|
| +++ b/src/effects/SkArithmeticImageFilter.cpp
|
| @@ -0,0 +1,297 @@
|
| +/*
|
| + * 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 "SkArithmeticImageFilter.h"
|
| +#include "SkArithmeticMode.h"
|
| +#include "SkCanvas.h"
|
| +#include "SkColorPriv.h"
|
| +#include "SkFlattenableBuffers.h"
|
| +#if SK_SUPPORT_GPU
|
| +#include "GrContext.h"
|
| +#include "gl/GrGLEffect.h"
|
| +#include "gl/GrGLEffectMatrix.h"
|
| +#include "GrTBackendEffectFactory.h"
|
| +#include "SkImageFilterUtils.h"
|
| +#endif
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +SkArithmeticImageFilter::SkArithmeticImageFilter(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4, SkImageFilter* background, SkImageFilter* foreground)
|
| + : INHERITED(background, foreground), fK1(k1), fK2(k2), fK3(k3), fK4(k4)
|
| +{
|
| +}
|
| +
|
| +SkArithmeticImageFilter::~SkArithmeticImageFilter() {
|
| +}
|
| +
|
| +SkArithmeticImageFilter::SkArithmeticImageFilter(SkFlattenableReadBuffer& buffer)
|
| + : INHERITED(buffer)
|
| +{
|
| + fK1 = buffer.readScalar();
|
| + fK2 = buffer.readScalar();
|
| + fK3 = buffer.readScalar();
|
| + fK4 = buffer.readScalar();
|
| +}
|
| +
|
| +void SkArithmeticImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
|
| + this->INHERITED::flatten(buffer);
|
| + buffer.writeScalar(fK1);
|
| + buffer.writeScalar(fK2);
|
| + buffer.writeScalar(fK3);
|
| + buffer.writeScalar(fK4);
|
| +}
|
| +
|
| +bool SkArithmeticImageFilter::onFilterImage(Proxy* proxy,
|
| + const SkBitmap& src,
|
| + const SkMatrix& ctm,
|
| + SkBitmap* dst,
|
| + SkIPoint* offset) {
|
| + SkBitmap background = src, foreground = src;
|
| + SkImageFilter* foregroundInput = getInput(0);
|
| + SkImageFilter* backgroundInput = 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;
|
| + SkAutoTUnref<SkXfermode> mode(SkArithmeticMode::Create(fK1, fK2, fK3, fK4));
|
| + paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
| + canvas.drawBitmap(background, 0, 0, &paint);
|
| + paint.setXfermode(mode);
|
| + canvas.drawBitmap(foreground, 0, 0, &paint);
|
| + return true;
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +#if SK_SUPPORT_GPU
|
| +class GrGLArithmeticEffect : public GrGLEffect {
|
| +public:
|
| + GrGLArithmeticEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
|
| + virtual ~GrGLArithmeticEffect();
|
| +
|
| + virtual void emitCode(GrGLShaderBuilder*,
|
| + const GrDrawEffect&,
|
| + EffectKey,
|
| + const char* outputColor,
|
| + const char* inputColor,
|
| + const TextureSamplerArray&) SK_OVERRIDE;
|
| +
|
| + static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
|
| +
|
| + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
|
| +
|
| +private:
|
| + static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType;
|
| +
|
| + GrGLUniformManager::UniformHandle fKUni;
|
| + GrGLEffectMatrix fForegroundEffectMatrix;
|
| + GrGLEffectMatrix fBackgroundEffectMatrix;
|
| +
|
| + typedef GrGLEffect INHERITED;
|
| +};
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +class GrArithmeticEffect : public GrEffect {
|
| +public:
|
| + static GrEffectRef* Create(float k1, float k2, float k3, float k4,
|
| + GrTexture* foreground,
|
| + GrTexture* background) {
|
| + AutoEffectUnref effect(SkNEW_ARGS(GrArithmeticEffect, (k1, k2, k3, k4, foreground, background)));
|
| + return CreateEffectRef(effect);
|
| + }
|
| +
|
| + virtual ~GrArithmeticEffect();
|
| +
|
| + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
|
| +
|
| + typedef GrGLArithmeticEffect GLEffect;
|
| + static const char* Name() { return "Arithmetic"; }
|
| +
|
| + virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
|
| +
|
| + float k1() const { return fK1; }
|
| + float k2() const { return fK2; }
|
| + float k3() const { return fK3; }
|
| + float k4() const { return fK4; }
|
| +
|
| +private:
|
| + virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
|
| +
|
| + GrArithmeticEffect(float k1, float k2, float k3, float k4, GrTexture* foreground, GrTexture* background);
|
| + float fK1, fK2, fK3, fK4;
|
| + GrTextureAccess fForegroundAccess;
|
| + GrTextureAccess fBackgroundAccess;
|
| +
|
| + typedef GrEffect INHERITED;
|
| +
|
| +};
|
| +
|
| +bool SkArithmeticImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
| + SkBitmap backgroundBM;
|
| + if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &backgroundBM)) {
|
| + return false;
|
| + }
|
| + GrTexture* background = (GrTexture*) backgroundBM.getTexture();
|
| + SkBitmap foregroundBM;
|
| + if (!SkImageFilterUtils::GetInputResultGPU(getInput(1), proxy, src, &foregroundBM)) {
|
| + return false;
|
| + }
|
| + GrTexture* foreground = (GrTexture*) foregroundBM.getTexture();
|
| + GrContext* context = foreground->getContext();
|
| +
|
| + 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());
|
| +
|
| + GrPaint paint;
|
| + paint.colorStage(0)->setEffect(
|
| + GrArithmeticEffect::Create(SkScalarToFloat(fK1),
|
| + SkScalarToFloat(fK2),
|
| + SkScalarToFloat(fK3),
|
| + SkScalarToFloat(fK4),
|
| + foreground,
|
| + background))->unref();
|
| + SkRect srcRect;
|
| + src.getBounds(&srcRect);
|
| + context->drawRect(paint, srcRect);
|
| + return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), result);
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +GrArithmeticEffect::GrArithmeticEffect(float k1,
|
| + float k2,
|
| + float k3,
|
| + float k4,
|
| + GrTexture* foreground,
|
| + GrTexture* background)
|
| + : fK1(k1), fK2(k2), fK3(k3), fK4(k4)
|
| + , fForegroundAccess(foreground)
|
| + , fBackgroundAccess(background) {
|
| + this->addTextureAccess(&fForegroundAccess);
|
| + this->addTextureAccess(&fBackgroundAccess);
|
| +}
|
| +
|
| +GrArithmeticEffect::~GrArithmeticEffect() {
|
| +}
|
| +
|
| +bool GrArithmeticEffect::onIsEqual(const GrEffect& sBase) const {
|
| + const GrArithmeticEffect& s = CastEffect<GrArithmeticEffect>(sBase);
|
| + return fForegroundAccess.getTexture() == s.fForegroundAccess.getTexture() &&
|
| + fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture() &&
|
| + fK1 == s.fK1 &&
|
| + fK2 == s.fK2 &&
|
| + fK3 == s.fK3 &&
|
| + fK4 == s.fK4;
|
| +}
|
| +
|
| +const GrBackendEffectFactory& GrArithmeticEffect::getFactory() const {
|
| + return GrTBackendEffectFactory<GrArithmeticEffect>::getInstance();
|
| +}
|
| +
|
| +void GrArithmeticEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
|
| + // TODO: optimize this
|
| + *validFlags = 0;
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +GrGLArithmeticEffect::GrGLArithmeticEffect(const GrBackendEffectFactory& factory,
|
| + const GrDrawEffect& drawEffect)
|
| + : INHERITED(factory)
|
| + , fForegroundEffectMatrix(kCoordsType)
|
| + , fBackgroundEffectMatrix(kCoordsType) {
|
| +}
|
| +
|
| +GrGLArithmeticEffect::~GrGLArithmeticEffect() {
|
| +}
|
| +
|
| +void GrGLArithmeticEffect::emitCode(GrGLShaderBuilder* builder,
|
| + const GrDrawEffect&,
|
| + EffectKey key,
|
| + const char* outputColor,
|
| + const char* inputColor,
|
| + const TextureSamplerArray& samplers) {
|
| + const char* fgCoords;
|
| + const char* bgCoords;
|
| + GrSLType fgCoordsType = fForegroundEffectMatrix.emitCode(builder, key, &fgCoords, NULL, "FG");
|
| + GrSLType bgCoordsType = fBackgroundEffectMatrix.emitCode(builder, key, &bgCoords, NULL, "BG");
|
| +
|
| + fKUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
|
| + kVec4f_GrSLType, "k");
|
| + const char* kUni = builder->getUniformCStr(fKUni);
|
| +
|
| + builder->fsCodeAppend("\t\tvec4 fgColor = ");
|
| + builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
|
| + samplers[0],
|
| + fgCoords,
|
| + fgCoordsType);
|
| + builder->fsCodeAppend(";\n");
|
| +
|
| + builder->fsCodeAppend("\t\tvec4 bgColor = ");
|
| + builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
|
| + samplers[1],
|
| + bgCoords,
|
| + bgCoordsType);
|
| + builder->fsCodeAppend(";\n");
|
| + builder->fsCodeAppend("\t\tfgColor.rgb = clamp(fgColor.rgb / fgColor.a, 0.0, 1.0);\n");
|
| + builder->fsCodeAppend("\t\tbgColor.rgb = clamp(bgColor.rgb / bgColor.a, 0.0, 1.0);\n");
|
| +
|
| + builder->fsCodeAppendf("\t\t%s = %s.x * bgColor * fgColor + %s.y * bgColor + %s.z * fgColor + %s.w;\n", outputColor, kUni, kUni, kUni, kUni);
|
| + builder->fsCodeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
|
| + builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
|
| +}
|
| +
|
| +void GrGLArithmeticEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) {
|
| + const GrArithmeticEffect& arith = drawEffect.castEffect<GrArithmeticEffect>();
|
| + GrTexture* fgTex = arith.texture(0);
|
| + GrTexture* bgTex = arith.texture(1);
|
| + fForegroundEffectMatrix.setData(uman,
|
| + GrEffect::MakeDivByTextureWHMatrix(fgTex),
|
| + drawEffect,
|
| + fgTex);
|
| + fBackgroundEffectMatrix.setData(uman,
|
| + GrEffect::MakeDivByTextureWHMatrix(bgTex),
|
| + drawEffect,
|
| + bgTex);
|
| +
|
| + uman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
|
| +}
|
| +
|
| +GrGLEffect::EffectKey GrGLArithmeticEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
|
| + const GrArithmeticEffect& arith = drawEffect.castEffect<GrArithmeticEffect>();
|
| +
|
| + GrTexture* fgTex = arith.texture(0);
|
| + GrTexture* bgTex = arith.texture(1);
|
| +
|
| + EffectKey fgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(fgTex),
|
| + drawEffect,
|
| + kCoordsType,
|
| + fgTex);
|
| +
|
| + EffectKey bgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(bgTex),
|
| + drawEffect,
|
| + kCoordsType,
|
| + bgTex);
|
| + bgKey <<= GrGLEffectMatrix::kKeyBits;
|
| + return bgKey | fgKey;
|
| +}
|
| +#endif
|
|
|