aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/displacement.cpp137
-rw-r--r--gyp/effects.gypi2
-rw-r--r--gyp/gmslides.gypi1
-rw-r--r--include/effects/SkDisplacementMapEffect.h54
-rw-r--r--src/effects/SkDisplacementMapEffect.cpp527
-rw-r--r--src/ports/SkGlobalInitialization_default.cpp2
6 files changed, 723 insertions, 0 deletions
diff --git a/gm/displacement.cpp b/gm/displacement.cpp
new file mode 100644
index 0000000000..342806dd04
--- /dev/null
+++ b/gm/displacement.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 "SkDisplacementMapEffect.h"
+#include "SkBitmapSource.h"
+
+namespace skiagm {
+
+class DisplacementMapGM : public GM {
+public:
+ DisplacementMapGM() : fInitialized(false) {
+ this->setBGColor(0xFF000000);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("displacement");
+ }
+
+ 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(0xFF884422);
+ paint.setTextSize(SkIntToScalar(96));
+ const char* str = "g";
+ canvas.drawText(str, strlen(str), SkIntToScalar(15), SkIntToScalar(55), 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(0xFF804020);
+ SkPaint lightPaint;
+ lightPaint.setColor(0xFF244484);
+ 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(500, 200);
+ }
+
+ void drawClippedBitmap(SkCanvas* canvas, int x, int y, const SkPaint& paint) {
+ canvas->save();
+ canvas->clipRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
+ SkIntToScalar(fBitmap.width()), SkIntToScalar(fBitmap.height())));
+ canvas->drawBitmap(fBitmap, SkIntToScalar(x), SkIntToScalar(y), &paint);
+ canvas->restore();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ if (!fInitialized) {
+ make_bitmap();
+ make_checkerboard();
+ fInitialized = true;
+ }
+ canvas->clear(0x00000000);
+ SkPaint paint;
+ SkAutoTUnref<SkImageFilter> displ(SkNEW_ARGS(SkBitmapSource, (fCheckerboard)));
+ paint.setImageFilter(SkNEW_ARGS(SkDisplacementMapEffect,
+ (SkDisplacementMapEffect::kR_ChannelSelectorType,
+ SkDisplacementMapEffect::kG_ChannelSelectorType, 0.0f, displ)))->unref();
+ drawClippedBitmap(canvas, 0, 0, paint);
+ paint.setImageFilter(SkNEW_ARGS(SkDisplacementMapEffect,
+ (SkDisplacementMapEffect::kB_ChannelSelectorType,
+ SkDisplacementMapEffect::kA_ChannelSelectorType, 0.2f, displ)))->unref();
+ drawClippedBitmap(canvas, 100, 0, paint);
+ paint.setImageFilter(SkNEW_ARGS(SkDisplacementMapEffect,
+ (SkDisplacementMapEffect::kR_ChannelSelectorType,
+ SkDisplacementMapEffect::kB_ChannelSelectorType, 0.4f, displ)))->unref();
+ drawClippedBitmap(canvas, 200, 0, paint);
+ paint.setImageFilter(SkNEW_ARGS(SkDisplacementMapEffect,
+ (SkDisplacementMapEffect::kG_ChannelSelectorType,
+ SkDisplacementMapEffect::kA_ChannelSelectorType, 0.6f, displ)))->unref();
+ drawClippedBitmap(canvas, 300, 0, paint);
+ paint.setImageFilter(SkNEW_ARGS(SkDisplacementMapEffect,
+ (SkDisplacementMapEffect::kR_ChannelSelectorType,
+ SkDisplacementMapEffect::kA_ChannelSelectorType, 0.8f, displ)))->unref();
+ drawClippedBitmap(canvas, 400, 0, paint);
+
+ paint.setImageFilter(SkNEW_ARGS(SkDisplacementMapEffect,
+ (SkDisplacementMapEffect::kR_ChannelSelectorType,
+ SkDisplacementMapEffect::kG_ChannelSelectorType, 0.5f, displ)))->unref();
+ drawClippedBitmap(canvas, 0, 100, paint);
+ paint.setImageFilter(SkNEW_ARGS(SkDisplacementMapEffect,
+ (SkDisplacementMapEffect::kB_ChannelSelectorType,
+ SkDisplacementMapEffect::kA_ChannelSelectorType, 0.5f, displ)))->unref();
+ drawClippedBitmap(canvas, 100, 100, paint);
+ paint.setImageFilter(SkNEW_ARGS(SkDisplacementMapEffect,
+ (SkDisplacementMapEffect::kR_ChannelSelectorType,
+ SkDisplacementMapEffect::kB_ChannelSelectorType, 0.5f, displ)))->unref();
+ drawClippedBitmap(canvas, 200, 100, paint);
+ paint.setImageFilter(SkNEW_ARGS(SkDisplacementMapEffect,
+ (SkDisplacementMapEffect::kG_ChannelSelectorType,
+ SkDisplacementMapEffect::kA_ChannelSelectorType, 0.5f, displ)))->unref();
+ drawClippedBitmap(canvas, 300, 100, paint);
+ paint.setImageFilter(SkNEW_ARGS(SkDisplacementMapEffect,
+ (SkDisplacementMapEffect::kR_ChannelSelectorType,
+ SkDisplacementMapEffect::kA_ChannelSelectorType, 0.5f, displ)))->unref();
+ drawClippedBitmap(canvas, 400, 100, paint);
+ }
+
+private:
+ typedef GM INHERITED;
+ SkBitmap fBitmap, fCheckerboard;
+ bool fInitialized;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new DisplacementMapGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gyp/effects.gypi b/gyp/effects.gypi
index d981cd1e01..b8defb4a6a 100644
--- a/gyp/effects.gypi
+++ b/gyp/effects.gypi
@@ -25,6 +25,7 @@
'<(skia_src_path)/effects/SkCornerPathEffect.cpp',
'<(skia_src_path)/effects/SkDashPathEffect.cpp',
'<(skia_src_path)/effects/SkDiscretePathEffect.cpp',
+ '<(skia_src_path)/effects/SkDisplacementMapEffect.cpp',
'<(skia_src_path)/effects/SkEmbossMask.cpp',
'<(skia_src_path)/effects/SkEmbossMask.h',
'<(skia_src_path)/effects/SkEmbossMask_Table.h',
@@ -81,6 +82,7 @@
'<(skia_include_path)/effects/SkCornerPathEffect.h',
'<(skia_include_path)/effects/SkDashPathEffect.h',
'<(skia_include_path)/effects/SkDiscretePathEffect.h',
+ '<(skia_include_path)/effects/SkDisplacementMapEffect.h',
'<(skia_include_path)/effects/SkDrawExtraPathEffect.h',
'<(skia_include_path)/effects/SkEmbossMaskFilter.h',
'<(skia_include_path)/effects/SkGradientShader.h',
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index 1553e744fe..5aa75f6aa3 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -26,6 +26,7 @@
'../gm/dashcubics.cpp',
'../gm/dashing.cpp',
'../gm/distantclip.cpp',
+ '../gm/displacement.cpp',
'../gm/drawbitmaprect.cpp',
'../gm/drawlooper.cpp',
'../gm/extractbitmap.cpp',
diff --git a/include/effects/SkDisplacementMapEffect.h b/include/effects/SkDisplacementMapEffect.h
new file mode 100644
index 0000000000..641b4cbee4
--- /dev/null
+++ b/include/effects/SkDisplacementMapEffect.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkDisplacementMapEffect_DEFINED
+#define SkDisplacementMapEffect_DEFINED
+
+#include "SkImageFilter.h"
+#include "SkBitmap.h"
+
+class SK_API SkDisplacementMapEffect : public SkImageFilter {
+public:
+ enum ChannelSelectorType {
+ kUnknown_ChannelSelectorType,
+ kR_ChannelSelectorType,
+ kG_ChannelSelectorType,
+ kB_ChannelSelectorType,
+ kA_ChannelSelectorType,
+ kKeyBits = 3 // Max value is 4, so 3 bits are required at most
+ };
+
+ SkDisplacementMapEffect(ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, SkScalar scale, SkImageFilter* displacement, SkImageFilter* color = NULL);
+
+ ~SkDisplacementMapEffect();
+
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDisplacementMapEffect)
+
+ 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 GrTexture* filterImageGPU(Proxy* proxy, GrTexture* src, const SkRect& rect) SK_OVERRIDE;
+#endif
+
+protected:
+ explicit SkDisplacementMapEffect(SkFlattenableReadBuffer& buffer);
+ virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
+
+private:
+ ChannelSelectorType fXChannelSelector;
+ ChannelSelectorType fYChannelSelector;
+ SkScalar fScale;
+ typedef SkImageFilter INHERITED;
+ SkImageFilter* getDisplacementInput() { return getInput(0); }
+ SkImageFilter* getColorInput() { return getInput(1); }
+};
+
+#endif
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
new file mode 100644
index 0000000000..a10e623f4a
--- /dev/null
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -0,0 +1,527 @@
+/*
+ * 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 "SkDisplacementMapEffect.h"
+#include "SkFlattenableBuffers.h"
+#include "SkUnPreMultiply.h"
+#if SK_SUPPORT_GPU
+#include "SkGr.h"
+#include "SkGrPixelRef.h"
+#include "gl/GrGLEffect.h"
+#include "gl/GrGLEffectMatrix.h"
+#include "GrTBackendEffectFactory.h"
+#endif
+
+namespace {
+
+template<SkDisplacementMapEffect::ChannelSelectorType type>
+uint32_t getValue(SkColor, const SkUnPreMultiply::Scale*) {
+ SkASSERT(!"Unknown channel selector");
+ return 0;
+}
+
+template<> uint32_t getValue<SkDisplacementMapEffect::kR_ChannelSelectorType>(
+ SkColor l, const SkUnPreMultiply::Scale* table) {
+ return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedR32(l));
+}
+
+template<> uint32_t getValue<SkDisplacementMapEffect::kG_ChannelSelectorType>(
+ SkColor l, const SkUnPreMultiply::Scale* table) {
+ return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedG32(l));
+}
+
+template<> uint32_t getValue<SkDisplacementMapEffect::kB_ChannelSelectorType>(
+ SkColor l, const SkUnPreMultiply::Scale* table) {
+ return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedB32(l));
+}
+
+template<> uint32_t getValue<SkDisplacementMapEffect::kA_ChannelSelectorType>(
+ SkColor l, const SkUnPreMultiply::Scale*) {
+ return SkGetPackedA32(l);
+}
+
+template<SkDisplacementMapEffect::ChannelSelectorType typeX,
+ SkDisplacementMapEffect::ChannelSelectorType typeY>
+void computeDisplacement(SkScalar scale, SkBitmap* dst, SkBitmap* displ, SkBitmap* src)
+{
+ static const SkScalar Inv8bit = SkScalarDiv(SK_Scalar1, SkFloatToScalar(255.0f));
+ static const SkScalar Half8bit = SkFloatToScalar(255.0f * 0.5f);
+ const int dstW = displ->width();
+ const int dstH = displ->height();
+ const int srcW = src->width();
+ const int srcH = src->height();
+ const SkScalar scaleX = SkScalarMul(SkScalarMul(scale, SkIntToScalar(dstW)), Inv8bit);
+ const SkScalar scaleY = SkScalarMul(SkScalarMul(scale, SkIntToScalar(dstH)), Inv8bit);
+ const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
+ for (int y = 0; y < dstH; ++y) {
+ const SkPMColor* displPtr = displ->getAddr32(0, y);
+ SkPMColor* dstPtr = dst->getAddr32(0, y);
+ for (int x = 0; x < dstW; ++x, ++displPtr, ++dstPtr) {
+ const SkScalar displX =
+ SkScalarMul(scaleX, SkIntToScalar(getValue<typeX>(*displPtr, table))-Half8bit);
+ const SkScalar displY =
+ SkScalarMul(scaleY, SkIntToScalar(getValue<typeY>(*displPtr, table))-Half8bit);
+ const int coordX = x + SkScalarRoundToInt(displX);
+ const int coordY = y + SkScalarRoundToInt(displY);
+ *dstPtr = ((coordX < 0) || (coordX >= srcW) || (coordY < 0) || (coordY >= srcH)) ?
+ 0 : *(src->getAddr32(coordX, coordY));
+ }
+ }
+}
+
+template<SkDisplacementMapEffect::ChannelSelectorType typeX>
+void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
+ SkScalar scale, SkBitmap* dst, SkBitmap* displ, SkBitmap* src)
+{
+ switch (yChannelSelector) {
+ case SkDisplacementMapEffect::kR_ChannelSelectorType:
+ computeDisplacement<typeX, SkDisplacementMapEffect::kR_ChannelSelectorType>(
+ scale, dst, displ, src);
+ break;
+ case SkDisplacementMapEffect::kG_ChannelSelectorType:
+ computeDisplacement<typeX, SkDisplacementMapEffect::kG_ChannelSelectorType>(
+ scale, dst, displ, src);
+ break;
+ case SkDisplacementMapEffect::kB_ChannelSelectorType:
+ computeDisplacement<typeX, SkDisplacementMapEffect::kB_ChannelSelectorType>(
+ scale, dst, displ, src);
+ break;
+ case SkDisplacementMapEffect::kA_ChannelSelectorType:
+ computeDisplacement<typeX, SkDisplacementMapEffect::kA_ChannelSelectorType>(
+ scale, dst, displ, src);
+ break;
+ case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
+ default:
+ SkASSERT(!"Unknown Y channel selector");
+ }
+}
+
+void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
+ SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
+ SkScalar scale, SkBitmap* dst, SkBitmap* displ, SkBitmap* src)
+{
+ switch (xChannelSelector) {
+ case SkDisplacementMapEffect::kR_ChannelSelectorType:
+ computeDisplacement<SkDisplacementMapEffect::kR_ChannelSelectorType>(
+ yChannelSelector, scale, dst, displ, src);
+ break;
+ case SkDisplacementMapEffect::kG_ChannelSelectorType:
+ computeDisplacement<SkDisplacementMapEffect::kG_ChannelSelectorType>(
+ yChannelSelector, scale, dst, displ, src);
+ break;
+ case SkDisplacementMapEffect::kB_ChannelSelectorType:
+ computeDisplacement<SkDisplacementMapEffect::kB_ChannelSelectorType>(
+ yChannelSelector, scale, dst, displ, src);
+ break;
+ case SkDisplacementMapEffect::kA_ChannelSelectorType:
+ computeDisplacement<SkDisplacementMapEffect::kA_ChannelSelectorType>(
+ yChannelSelector, scale, dst, displ, src);
+ break;
+ case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
+ default:
+ SkASSERT(!"Unknown X channel selector");
+ }
+}
+
+} // end namespace
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkDisplacementMapEffect::SkDisplacementMapEffect(ChannelSelectorType xChannelSelector,
+ ChannelSelectorType yChannelSelector,
+ SkScalar scale,
+ SkImageFilter* displacement,
+ SkImageFilter* color)
+ : INHERITED(displacement, color)
+ , fXChannelSelector(xChannelSelector)
+ , fYChannelSelector(yChannelSelector)
+ , fScale(scale)
+{
+}
+
+SkDisplacementMapEffect::~SkDisplacementMapEffect() {
+}
+
+SkDisplacementMapEffect::SkDisplacementMapEffect(SkFlattenableReadBuffer& buffer)
+ : INHERITED(buffer)
+{
+ fXChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt();
+ fYChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt();
+ fScale = buffer.readScalar();
+}
+
+void SkDisplacementMapEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
+ this->INHERITED::flatten(buffer);
+ buffer.writeInt((int) fXChannelSelector);
+ buffer.writeInt((int) fYChannelSelector);
+ buffer.writeScalar(fScale);
+}
+
+bool SkDisplacementMapEffect::onFilterImage(Proxy* proxy,
+ const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* dst,
+ SkIPoint* offset) {
+ SkBitmap displ, color = src;
+ SkImageFilter* colorInput = getColorInput();
+ SkImageFilter* displacementInput = getDisplacementInput();
+ SkASSERT(NULL != displacementInput);
+ if ((colorInput && !colorInput->filterImage(proxy, src, ctm, &color, offset)) ||
+ !displacementInput->filterImage(proxy, src, ctm, &displ, offset)) {
+ return false;
+ }
+ if ((displ.config() != SkBitmap::kARGB_8888_Config) ||
+ (color.config() != SkBitmap::kARGB_8888_Config)) {
+ return false;
+ }
+
+ SkAutoLockPixels alp_displacement(displ), alp_color(color);
+ if (!displ.getPixels() || !color.getPixels()) {
+ return false;
+ }
+ dst->setConfig(displ.config(), displ.width(), displ.height());
+ dst->allocPixels();
+ if (!dst->getPixels()) {
+ return false;
+ }
+
+ computeDisplacement(fXChannelSelector, fYChannelSelector, fScale, dst, &displ, &color);
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#if SK_SUPPORT_GPU
+class GrGLDisplacementMapEffect : public GrGLEffect {
+public:
+ GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
+ const GrEffect& effect);
+ virtual ~GrGLDisplacementMapEffect();
+
+ virtual void emitCode(GrGLShaderBuilder*,
+ const GrEffectStage&,
+ EffectKey,
+ const char* vertexCoords,
+ const char* outputColor,
+ const char* inputColor,
+ const TextureSamplerArray&) SK_OVERRIDE;
+
+ static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
+
+ virtual void setData(const GrGLUniformManager&, const GrEffectStage&);
+
+private:
+ SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
+ SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
+ GrGLEffectMatrix fDisplacementEffectMatrix;
+ GrGLEffectMatrix fColorEffectMatrix;
+ GrGLUniformManager::UniformHandle fScaleUni;
+ GrGLUniformManager::UniformHandle fYSignColor;
+ GrGLUniformManager::UniformHandle fYSignDispl;
+
+ typedef GrGLEffect INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrDisplacementMapEffect : public GrEffect {
+public:
+ GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
+ SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
+ SkScalar scale, GrTexture* displacement, GrTexture* color);
+ virtual ~GrDisplacementMapEffect();
+
+ virtual bool isEqual(const GrEffect&) const SK_OVERRIDE;
+ const GrBackendEffectFactory& getFactory() const;
+ SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const
+ { return fXChannelSelector; }
+ SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const
+ { return fYChannelSelector; }
+ SkScalar scale() const { return fScale; }
+
+ typedef GrGLDisplacementMapEffect GLEffect;
+ static const char* Name() { return "DisplacementMap"; }
+
+ void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+
+private:
+ GR_DECLARE_EFFECT_TEST;
+
+ GrTextureAccess fDisplacementAccess;
+ GrTextureAccess fColorAccess;
+ SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
+ SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
+ SkScalar fScale;
+
+ typedef GrEffect INHERITED;
+};
+
+// FIXME: This should be refactored with SkSingleInputImageFilter's version.
+static GrTexture* getInputResultAsTexture(SkImageFilter::Proxy* proxy,
+ SkImageFilter* input,
+ GrTexture* src,
+ const SkRect& rect) {
+ GrTexture* resultTex = NULL;
+ if (!input) {
+ resultTex = src;
+ } else if (input->canFilterImageGPU()) {
+ // filterImageGPU() already refs the result, so just return it here.
+ return input->filterImageGPU(proxy, src, rect);
+ } else {
+ SkBitmap srcBitmap, result;
+ srcBitmap.setConfig(SkBitmap::kARGB_8888_Config, src->width(), src->height());
+ srcBitmap.setPixelRef(new SkGrPixelRef(src))->unref();
+ SkIPoint offset;
+ if (input->filterImage(proxy, srcBitmap, SkMatrix(), &result, &offset)) {
+ if (result.getTexture()) {
+ resultTex = (GrTexture*) result.getTexture();
+ } else {
+ resultTex = GrLockCachedBitmapTexture(src->getContext(), result, NULL);
+ SkSafeRef(resultTex);
+ GrUnlockCachedBitmapTexture(resultTex);
+ return resultTex;
+ }
+ } else {
+ resultTex = src;
+ }
+ }
+ SkSafeRef(resultTex);
+ return resultTex;
+}
+
+GrTexture* SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, GrTexture* src,
+ const SkRect& rect) {
+ SkAutoTUnref<GrTexture> color(getInputResultAsTexture(proxy, getColorInput(), src, rect));
+ SkAutoTUnref<GrTexture> displacement(getInputResultAsTexture(proxy, getDisplacementInput(),
+ src, rect));
+ GrContext* context = src->getContext();
+
+ GrTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
+ desc.fWidth = SkScalarCeilToInt(rect.width());
+ desc.fHeight = SkScalarCeilToInt(rect.height());
+ desc.fConfig = kRGBA_8888_GrPixelConfig;
+
+ GrAutoScratchTexture ast(context, desc);
+ GrTexture* dst = ast.detach();
+
+ GrContext::AutoMatrix am;
+ am.setIdentity(context);
+
+ GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
+ GrContext::AutoClip ac(context, rect);
+
+ GrPaint paint;
+ paint.colorStage(0)->setEffect(
+ SkNEW_ARGS(GrDisplacementMapEffect, (fXChannelSelector, fYChannelSelector, fScale,
+ displacement.get(), color.get())))->unref();
+ context->drawRect(paint, rect);
+ return dst;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrDisplacementMapEffect::GrDisplacementMapEffect(
+ SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
+ SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
+ SkScalar scale,
+ GrTexture* displacement,
+ GrTexture* color)
+ : fDisplacementAccess(displacement)
+ , fColorAccess(color)
+ , fXChannelSelector(xChannelSelector)
+ , fYChannelSelector(yChannelSelector)
+ , fScale(scale) {
+ this->addTextureAccess(&fDisplacementAccess);
+ this->addTextureAccess(&fColorAccess);
+}
+
+GrDisplacementMapEffect::~GrDisplacementMapEffect() {
+}
+
+bool GrDisplacementMapEffect::isEqual(const GrEffect& sBase) const {
+ const GrDisplacementMapEffect& s = static_cast<const GrDisplacementMapEffect&>(sBase);
+ return INHERITED::isEqual(sBase) && fXChannelSelector == s.fXChannelSelector &&
+ fYChannelSelector == s.fYChannelSelector && fScale == s.fScale;
+}
+
+const GrBackendEffectFactory& GrDisplacementMapEffect::getFactory() const {
+ return GrTBackendEffectFactory<GrDisplacementMapEffect>::getInstance();
+}
+
+void GrDisplacementMapEffect::getConstantColorComponents(GrColor* color,
+ uint32_t* validFlags) const {
+ // Any displacement offset bringing a pixel out of bounds will output a color of (0,0,0,0),
+ // so the only way we'd get a constant alpha is if the input color image has a constant alpha
+ // and no displacement offset push any texture coordinates out of bounds OR if the constant
+ // alpha is 0. Since this isn't trivial to compute at this point, let's assume the output is
+ // not of constant color when a displacement effect is applied.
+ *validFlags = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_EFFECT_TEST(GrDisplacementMapEffect);
+
+GrEffect* GrDisplacementMapEffect::TestCreate(SkRandom* random,
+ GrContext* context,
+ GrTexture* textures[]) {
+ int texIdxDispl = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
+ GrEffectUnitTest::kAlphaTextureIdx;
+ int texIdxColor = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
+ GrEffectUnitTest::kAlphaTextureIdx;
+ static const int kMaxComponent = 4;
+ SkDisplacementMapEffect::ChannelSelectorType xChannelSelector =
+ static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
+ random->nextRangeU(1, kMaxComponent));
+ SkDisplacementMapEffect::ChannelSelectorType yChannelSelector =
+ static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
+ random->nextRangeU(1, kMaxComponent));
+ SkScalar scale = random->nextUScalar1();
+
+ return SkNEW_ARGS(GrDisplacementMapEffect, (xChannelSelector, yChannelSelector, scale,
+ textures[texIdxDispl], textures[texIdxColor]));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrGLDisplacementMapEffect::GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory, const GrEffect& effect)
+ : INHERITED(factory)
+ , fXChannelSelector(static_cast<const GrDisplacementMapEffect&>(effect).xChannelSelector())
+ , fYChannelSelector(static_cast<const GrDisplacementMapEffect&>(effect).yChannelSelector()) {
+}
+
+GrGLDisplacementMapEffect::~GrGLDisplacementMapEffect() {
+}
+
+void GrGLDisplacementMapEffect::emitCode(GrGLShaderBuilder* builder,
+ const GrEffectStage&,
+ EffectKey key,
+ const char* vertexCoords,
+ const char* outputColor,
+ const char* inputColor,
+ const TextureSamplerArray& samplers) {
+ fScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+ kVec2f_GrSLType, "Scale");
+ const char* scaleUni = builder->getUniformCStr(fScaleUni);
+
+ const char* dCoordsIn;
+ GrSLType dCoordsType = fDisplacementEffectMatrix.emitCode(
+ builder, key, vertexCoords, &dCoordsIn, NULL, "DISPL");
+ const char* cCoordsIn;
+ GrSLType cCoordsType = fColorEffectMatrix.emitCode(
+ builder, key, vertexCoords, &cCoordsIn, NULL, "COLOR");
+
+ SkString* code = &builder->fFSCode;
+ const char* dColor = "dColor";
+ const char* dCoords = "dCoords";
+ const char* cCoords = "cCoords";
+ const char* nearZero = "1e-6"; // Since 6.10352e−5 is the smallest half float, use
+ // a number smaller than that to approximate 0, but
+ // leave room for 32-bit float GPU rounding errors.
+
+ code->appendf("\t\tvec4 %s = ", dColor);
+ builder->appendTextureLookup(code, samplers[0], dCoordsIn, dCoordsType);
+ code->append(";\n");
+
+ // Unpremultiply the displacement
+ code->appendf("\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
+ dColor, dColor, nearZero, dColor, dColor);
+
+ code->appendf("\t\tvec2 %s = %s + %s*(%s.",
+ cCoords, cCoordsIn, scaleUni, dColor);
+
+ switch (fXChannelSelector) {
+ case SkDisplacementMapEffect::kR_ChannelSelectorType:
+ code->append("r");
+ break;
+ case SkDisplacementMapEffect::kG_ChannelSelectorType:
+ code->append("g");
+ break;
+ case SkDisplacementMapEffect::kB_ChannelSelectorType:
+ code->append("b");
+ break;
+ case SkDisplacementMapEffect::kA_ChannelSelectorType:
+ code->append("a");
+ break;
+ case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
+ default:
+ SkASSERT(!"Unknown X channel selector");
+ }
+
+ switch (fYChannelSelector) {
+ case SkDisplacementMapEffect::kR_ChannelSelectorType:
+ code->append("r");
+ break;
+ case SkDisplacementMapEffect::kG_ChannelSelectorType:
+ code->append("g");
+ break;
+ case SkDisplacementMapEffect::kB_ChannelSelectorType:
+ code->append("b");
+ break;
+ case SkDisplacementMapEffect::kA_ChannelSelectorType:
+ code->append("a");
+ break;
+ case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
+ default:
+ SkASSERT(!"Unknown Y channel selector");
+ }
+ code->append("-vec2(0.5));\t\t");
+
+ // FIXME : This can be achieved with a "clamp to border" texture repeat mode and
+ // a 0 border color instead of computing if cCoords is out of bounds here.
+ code->appendf(
+ "%s = any(greaterThan(vec4(vec2(0.0), %s), vec4(%s, vec2(1.0)))) ? vec4(0.0) : ",
+ outputColor, cCoords, cCoords);
+ builder->appendTextureLookup(code, samplers[1], cCoords, cCoordsType);
+ code->append(";\n");
+}
+
+void GrGLDisplacementMapEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
+ const GrDisplacementMapEffect& displacementMap = static_cast<const GrDisplacementMapEffect&>(*stage.getEffect());
+ GrTexture* displTex = displacementMap.texture(0);
+ GrTexture* colorTex = displacementMap.texture(1);
+ fDisplacementEffectMatrix.setData(uman,
+ GrEffect::MakeDivByTextureWHMatrix(displTex),
+ stage.getCoordChangeMatrix(),
+ displTex);
+ fColorEffectMatrix.setData(uman,
+ GrEffect::MakeDivByTextureWHMatrix(colorTex),
+ stage.getCoordChangeMatrix(),
+ colorTex);
+
+ uman.set2f(fScaleUni, SkScalarToFloat(displacementMap.scale()),
+ colorTex->origin() == GrSurface::kTopLeft_Origin ?
+ SkScalarToFloat(displacementMap.scale()) :
+ SkScalarToFloat(-displacementMap.scale()));
+}
+
+GrGLEffect::EffectKey GrGLDisplacementMapEffect::GenKey(const GrEffectStage& stage,
+ const GrGLCaps&) {
+ const GrDisplacementMapEffect& displacementMap =
+ static_cast<const GrDisplacementMapEffect&>(*stage.getEffect());
+
+ GrTexture* displTex = displacementMap.texture(0);
+ GrTexture* colorTex = displacementMap.texture(1);
+
+ EffectKey displKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(displTex),
+ stage.getCoordChangeMatrix(),
+ displTex);
+
+ EffectKey colorKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(colorTex),
+ stage.getCoordChangeMatrix(),
+ colorTex);
+
+ colorKey <<= GrGLEffectMatrix::kKeyBits;
+ EffectKey xKey = displacementMap.xChannelSelector() << (2 * GrGLEffectMatrix::kKeyBits);
+ EffectKey yKey = displacementMap.yChannelSelector() << (2 * GrGLEffectMatrix::kKeyBits +
+ SkDisplacementMapEffect::kKeyBits);
+
+ return xKey | yKey | displKey | colorKey;
+}
+#endif
diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp
index 4ed7f5e16d..ae0c564828 100644
--- a/src/ports/SkGlobalInitialization_default.cpp
+++ b/src/ports/SkGlobalInitialization_default.cpp
@@ -31,6 +31,7 @@
#include "SkCornerPathEffect.h"
#include "SkDashPathEffect.h"
#include "SkDiscretePathEffect.h"
+#include "SkDisplacementMapEffect.h"
#include "SkEmptyShader.h"
#include "SkEmbossMaskFilter.h"
#include "SkFlattenable.h"
@@ -66,6 +67,7 @@ void SkFlattenable::InitializeFlattenables() {
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDashPathEffect)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDilateImageFilter)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiscretePathEffect)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDisplacementMapEffect)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmbossMaskFilter)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmptyShader)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkErodeImageFilter)