Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Unified Diff: src/effects/SkArithmeticImageFilter.cpp

Issue 16064002: Provide a GPU implementation of SkArithmeticMode (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Fix spacing Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « include/effects/SkArithmeticImageFilter.h ('k') | src/effects/SkArithmeticMode.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/effects/SkArithmeticImageFilter.cpp
diff --git a/src/effects/SkArithmeticImageFilter.cpp b/src/effects/SkArithmeticImageFilter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d36f183b60914de016ee8962967f5bf97d82ecfb
--- /dev/null
+++ b/src/effects/SkArithmeticImageFilter.cpp
@@ -0,0 +1,312 @@
+/*
+ * 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 fK1Uni, fK2Uni, fK3Uni, fK4Uni;
+ 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");
+
+ fK1Uni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
bsalomon 2013/05/28 14:21:20 Just wondering if it'd make sense to use a vec4 fo
Stephen White 2013/05/28 15:08:34 Yeah, I thought of that. Just thought it might mak
+ kFloat_GrSLType, "k1");
+ const char* k1Uni = builder->getUniformCStr(fK1Uni);
+
+ fK2Uni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+ kFloat_GrSLType, "k2");
+ const char* k2Uni = builder->getUniformCStr(fK2Uni);
+
+ fK3Uni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+ kFloat_GrSLType, "k3");
+ const char* k3Uni = builder->getUniformCStr(fK3Uni);
+
+ fK4Uni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+ kFloat_GrSLType, "k4");
+ const char* k4Uni = builder->getUniformCStr(fK4Uni);
+
+ 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");
bsalomon 2013/05/28 14:21:20 What does clamp do if the first param is NaN?
Stephen White 2013/05/28 15:08:34 It returns zero, as far as I can tell (empirically
+ builder->fsCodeAppend("\t\tbgColor.rgb = clamp(bgColor.rgb / bgColor.a, 0.0, 1.0);\n");
+
+ builder->fsCodeAppendf("\t\t%s = %s * bgColor * fgColor + %s * bgColor + %s * fgColor + %s;\n", outputColor, k1Uni, k2Uni, k3Uni, k4Uni);
+ 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.set1f(fK1Uni, arith.k1());
+ uman.set1f(fK2Uni, arith.k2());
+ uman.set1f(fK3Uni, arith.k3());
+ uman.set1f(fK4Uni, 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
« no previous file with comments | « include/effects/SkArithmeticImageFilter.h ('k') | src/effects/SkArithmeticMode.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698