Move the code for the GPU implementation of morphology effects from GrContext
and GrMorphologyEffect.* into SkMorphologyImageFilter.cpp.

Review URL:  https://codereview.appspot.com/6458065/



git-svn-id: http://skia.googlecode.com/svn/trunk@5241 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/gpu.gyp b/gyp/gpu.gyp
index 4021f4f..11e1b69 100644
--- a/gyp/gpu.gyp
+++ b/gyp/gpu.gyp
@@ -317,8 +317,6 @@
         '../src/gpu/effects/GrColorTableEffect.h',
         '../src/gpu/effects/GrConvolutionEffect.cpp',
         '../src/gpu/effects/GrConvolutionEffect.h',
-        '../src/gpu/effects/GrMorphologyEffect.cpp',
-        '../src/gpu/effects/GrMorphologyEffect.h',
         '../src/gpu/effects/GrSingleTextureEffect.cpp',
         '../src/gpu/effects/GrSingleTextureEffect.h',
         '../src/gpu/effects/GrTextureDomainEffect.cpp',
diff --git a/include/effects/SkMorphologyImageFilter.h b/include/effects/SkMorphologyImageFilter.h
index f4f96e1..d1d43ba 100644
--- a/include/effects/SkMorphologyImageFilter.h
+++ b/include/effects/SkMorphologyImageFilter.h
@@ -19,7 +19,9 @@
 protected:
     SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer);
     virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
+#if SK_SUPPORT_GPU
     virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
+#endif
 
     SkISize    radius() const { return fRadius; }
 
@@ -35,7 +37,9 @@
 
     virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
                                SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
+#if SK_SUPPORT_GPU
     virtual GrTexture* onFilterImageGPU(GrTexture* src, const SkRect& rect) SK_OVERRIDE;
+#endif
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDilateImageFilter)
 
@@ -53,7 +57,9 @@
 
     virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
                                SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
+#if SK_SUPPORT_GPU
     virtual GrTexture* onFilterImageGPU(GrTexture* src, const SkRect& rect) SK_OVERRIDE;
+#endif
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkErodeImageFilter)
 
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 9fb47e5..8dd81d9 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -603,32 +603,6 @@
      GrTexture* zoom(GrTexture* srcTexture,
                      const SkRect& dstRect, const SkRect& srcRect, float inset);
 
-
-    /**
-     * This enum is used with the function below, applyMorphology.
-     */
-    enum MorphologyType {
-        kErode_MorphologyType,
-        kDilate_MorphologyType,
-    };
-
-    /**
-     * Applies a 2D morphology to a given texture.
-     * @param srcTexture      The source texture to be blurred.
-     * @param rect            The destination rectangle.
-     * @param filter          The morphology filter.  Must be kDilate_Filter or
-     *                        kErode_Filter.
-     * @param radius          The morphology radius in X and Y.  The filter is
-     *                        applied to a fWidth by fHeight rectangle of
-     *                        pixels.
-     * @return the morphed texture, which may be srcTexture ref'ed, or a
-     * new texture.  It is the caller's responsibility to unref this texture.
-     */
-    GrTexture* applyMorphology(GrTexture* srcTexture,
-                               const GrRect& rect,
-                               MorphologyType type,
-                               SkISize radius);
-    
     ///////////////////////////////////////////////////////////////////////////
     // Helpers
 
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index 34b3c09..cbfa5cf 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -13,6 +13,9 @@
 #if SK_SUPPORT_GPU
 #include "GrContext.h"
 #include "GrTexture.h"
+#include "GrGpu.h"
+#include "gl/GrGLProgramStage.h"
+#include "effects/Gr1DKernelEffect.h"
 #endif
 
 SkMorphologyImageFilter::SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer)
@@ -218,29 +221,274 @@
     return true;
 }
 
-GrTexture* SkDilateImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
 #if SK_SUPPORT_GPU
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrGLMorphologyEffect;
+
+/**
+ * Morphology effects. Depending upon the type of morphology, either the
+ * component-wise min (Erode_Type) or max (Dilate_Type) of all pixels in the
+ * kernel is selected as the new color. The new color is modulated by the input
+ * color.
+ */
+class GrMorphologyEffect : public Gr1DKernelEffect {
+
+public:
+
+    enum MorphologyType {
+        kErode_MorphologyType,
+        kDilate_MorphologyType,
+    };
+
+    GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType);
+    virtual ~GrMorphologyEffect();
+
+    MorphologyType type() const { return fType; }
+
+    static const char* Name() { return "Morphology"; }
+
+    typedef GrGLMorphologyEffect GLProgramStage;
+
+    virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
+    virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
+
+protected:
+
+    MorphologyType fType;
+
+private:
+    GR_DECLARE_CUSTOM_STAGE_TEST;
+
+    typedef Gr1DKernelEffect INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrGLMorphologyEffect  : public GrGLProgramStage {
+public:
+    GrGLMorphologyEffect (const GrProgramStageFactory& factory,
+                          const GrCustomStage& stage);
+
+    virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
+    virtual void emitVS(GrGLShaderBuilder* state,
+                        const char* vertexCoords) SK_OVERRIDE {};
+    virtual void emitFS(GrGLShaderBuilder* state,
+                        const char* outputColor,
+                        const char* inputColor,
+                        const char* samplerName) SK_OVERRIDE;
+
+    static inline StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps);
+
+    virtual void setData(const GrGLUniformManager&,
+                         const GrCustomStage&,
+                         const GrRenderTarget*,
+                         int stageNum) SK_OVERRIDE;
+
+private:
+    int width() const { return GrMorphologyEffect::WidthFromRadius(fRadius); }
+
+    int                                 fRadius;
+    GrMorphologyEffect::MorphologyType  fType;
+    GrGLUniformManager::UniformHandle   fImageIncrementUni;
+
+    typedef GrGLProgramStage INHERITED;
+};
+
+GrGLMorphologyEffect::GrGLMorphologyEffect(const GrProgramStageFactory& factory,
+                                           const GrCustomStage& stage)
+    : GrGLProgramStage(factory)
+    , fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle) {
+    const GrMorphologyEffect& m = static_cast<const GrMorphologyEffect&>(stage);
+    fRadius = m.radius();
+    fType = m.type();
+}
+
+void GrGLMorphologyEffect::setupVariables(GrGLShaderBuilder* builder) {
+    fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+                                             kVec2f_GrSLType, "ImageIncrement");
+}
+
+void GrGLMorphologyEffect::emitFS(GrGLShaderBuilder* builder,
+                                  const char* outputColor,
+                                  const char* inputColor,
+                                  const char* samplerName) {
+    SkString* code = &builder->fFSCode;
+
+    const char* func;
+    switch (fType) {
+        case GrMorphologyEffect::kErode_MorphologyType:
+            code->appendf("\t\tvec4 value = vec4(1, 1, 1, 1);\n");
+            func = "min";
+            break;
+        case GrMorphologyEffect::kDilate_MorphologyType:
+            code->appendf("\t\tvec4 value = vec4(0, 0, 0, 0);\n");
+            func = "max";
+            break;
+        default:
+            GrCrash("Unexpected type");
+            func = ""; // suppress warning
+            break;
+    }
+    const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
+
+    code->appendf("\t\tvec2 coord = %s - %d.0 * %s;\n",
+                   builder->fSampleCoords.c_str(), fRadius, imgInc);
+    code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
+    code->appendf("\t\t\tvalue = %s(value, ", func);
+    builder->emitTextureLookup(samplerName, "coord");
+    code->appendf(");\n");
+    code->appendf("\t\t\tcoord += %s;\n", imgInc);
+    code->appendf("\t\t}\n");
+    code->appendf("\t\t%s = value%s;\n", outputColor, builder->fModulate.c_str());
+}
+
+GrGLProgramStage::StageKey GrGLMorphologyEffect::GenKey(const GrCustomStage& s,
+                                                        const GrGLCaps& caps) {
+    const GrMorphologyEffect& m = static_cast<const GrMorphologyEffect&>(s);
+    StageKey key = static_cast<StageKey>(m.radius());
+    key |= (m.type() << 8);
+    return key;
+}
+
+void GrGLMorphologyEffect::setData(const GrGLUniformManager& uman,
+                                   const GrCustomStage& data,
+                                   const GrRenderTarget*,
+                                   int stageNum) {
+    const Gr1DKernelEffect& kern =
+        static_cast<const Gr1DKernelEffect&>(data);
+    GrGLTexture& texture =
+        *static_cast<GrGLTexture*>(data.texture(0));
+    // the code we generated was for a specific kernel radius
+    GrAssert(kern.radius() == fRadius);
+    float imageIncrement[2] = { 0 };
+    switch (kern.direction()) {
+        case Gr1DKernelEffect::kX_Direction:
+            imageIncrement[0] = 1.0f / texture.width();
+            break;
+        case Gr1DKernelEffect::kY_Direction:
+            imageIncrement[1] = 1.0f / texture.height();
+            break;
+        default:
+            GrCrash("Unknown filter direction.");
+    }
+    uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture,
+                                       Direction direction,
+                                       int radius,
+                                       MorphologyType type)
+    : Gr1DKernelEffect(texture, direction, radius)
+    , fType(type) {
+}
+
+GrMorphologyEffect::~GrMorphologyEffect() {
+}
+
+const GrProgramStageFactory& GrMorphologyEffect::getFactory() const {
+    return GrTProgramStageFactory<GrMorphologyEffect>::getInstance();
+}
+
+bool GrMorphologyEffect::isEqual(const GrCustomStage& sBase) const {
+    const GrMorphologyEffect& s =
+        static_cast<const GrMorphologyEffect&>(sBase);
+    return (INHERITED::isEqual(sBase) &&
+            this->radius() == s.radius() &&
+            this->direction() == s.direction() &&
+            this->type() == s.type());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_CUSTOM_STAGE_TEST(GrMorphologyEffect);
+
+GrCustomStage* GrMorphologyEffect::TestCreate(SkRandom* random,
+                                              GrContext* context,
+                                              GrTexture* textures[]) {
+    int texIdx = random->nextBool() ? GrCustomStageUnitTest::kSkiaPMTextureIdx :
+                                      GrCustomStageUnitTest::kAlphaTextureIdx;
+    Direction dir = random->nextBool() ? kX_Direction : kY_Direction;
+    static const int kMaxRadius = 10;
+    int radius = random->nextRangeU(1, kMaxRadius);
+    MorphologyType type = random->nextBool() ? GrMorphologyEffect::kErode_MorphologyType :
+                                               GrMorphologyEffect::kDilate_MorphologyType;
+
+    return SkNEW_ARGS(GrMorphologyEffect, (textures[texIdx], dir, radius, type));
+}
+
+namespace {
+
+void apply_morphology_pass(GrContext* context,
+                           GrTexture* texture,
+                           const SkRect& rect,
+                           int radius,
+                           GrMorphologyEffect::MorphologyType morphType,
+                           Gr1DKernelEffect::Direction direction) {
+    GrMatrix sampleM;
+    sampleM.setIDiv(texture->width(), texture->height());
+    GrPaint paint;
+    paint.reset();
+    paint.textureSampler(0)->reset(sampleM);
+    paint.textureSampler(0)->setCustomStage(SkNEW_ARGS(GrMorphologyEffect, (texture, direction, radius, morphType)))->unref();
+    context->drawRect(paint, rect);
+}
+
+GrTexture* apply_morphology(GrTexture* srcTexture,
+                            const GrRect& rect,
+                            GrMorphologyEffect::MorphologyType morphType,
+                            SkISize radius) {
+    GrContext* context = srcTexture->getContext();
+    srcTexture->ref();
+    GrContext::AutoMatrix avm(context, GrMatrix::I());
+    GrContext::AutoClip acs(context, GrRect::MakeWH(SkIntToScalar(srcTexture->width()), 
+                                                    SkIntToScalar(srcTexture->height())));
+    GrTextureDesc desc;
+    desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
+    desc.fWidth = SkScalarCeilToInt(rect.width());
+    desc.fHeight = SkScalarCeilToInt(rect.height());
+    desc.fConfig = kRGBA_8888_GrPixelConfig;
+    if (radius.fWidth > 0) {
+        GrAutoScratchTexture ast(context, desc);
+        GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget());
+        apply_morphology_pass(context, srcTexture, rect, radius.fWidth,
+                              morphType, Gr1DKernelEffect::kX_Direction);
+        SkIRect clearRect = SkIRect::MakeXYWH(
+                    SkScalarFloorToInt(rect.fLeft), 
+                    SkScalarFloorToInt(rect.fBottom),
+                    SkScalarFloorToInt(rect.width()), 
+                    radius.fHeight);
+        context->clear(&clearRect, 0x0);
+        srcTexture->unref();
+        srcTexture = ast.detach();
+    }
+    if (radius.fHeight > 0) {
+        GrAutoScratchTexture ast(context, desc);
+        GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget());
+        apply_morphology_pass(context, srcTexture, rect, radius.fHeight,
+                              morphType, Gr1DKernelEffect::kY_Direction);
+        srcTexture->unref();
+        srcTexture = ast.detach();
+    }
+    return srcTexture;
+}
+
+};
+
+GrTexture* SkDilateImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
     SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(src, rect));
-    return src->getContext()->applyMorphology(input.get(), rect,
-                                              GrContext::kDilate_MorphologyType,
-                                              radius());
-#else
-    SkDEBUGFAIL("Should not call in GPU-less build");
-    return NULL;
-#endif
+    return apply_morphology(src, rect, GrMorphologyEffect::kDilate_MorphologyType, radius());
 }
 
 GrTexture* SkErodeImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
-#if SK_SUPPORT_GPU
     SkAutoTUnref<GrTexture> input(this->getInputResultAsTexture(src, rect));
-    return src->getContext()->applyMorphology(input.get(), rect,
-                                              GrContext::kErode_MorphologyType,
-                                              radius());
-#else
-    SkDEBUGFAIL("Should not call in GPU-less build");
-    return NULL;
-#endif
+    return apply_morphology(src, rect, GrMorphologyEffect::kErode_MorphologyType, radius());
 }
 
+#endif
+
 SK_DEFINE_FLATTENABLE_REGISTRAR(SkDilateImageFilter)
 SK_DEFINE_FLATTENABLE_REGISTRAR(SkErodeImageFilter)
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 66da559..f2419ae 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -9,7 +9,6 @@
 
 #include "GrContext.h"
 
-#include "effects/GrMorphologyEffect.h"
 #include "effects/GrConvolutionEffect.h"
 #include "effects/GrSingleTextureEffect.h"
 
@@ -185,26 +184,6 @@
     return sigma;
 }
 
-void apply_morphology(GrDrawTarget* target,
-                      GrTexture* texture,
-                      const SkRect& rect,
-                      int radius,
-                      GrContext::MorphologyType morphType,
-                      Gr1DKernelEffect::Direction direction) {
-
-    GrRenderTarget* rt = target->drawState()->getRenderTarget();
-    GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kReset_ASRInit);
-    GrDrawState* drawState = target->drawState();
-    drawState->setRenderTarget(rt);
-    GrMatrix sampleM;
-    sampleM.setIDiv(texture->width(), texture->height());
-    drawState->sampler(0)->reset(sampleM);
-    SkAutoTUnref<GrCustomStage> morph(
-        SkNEW_ARGS(GrMorphologyEffect, (texture, direction, radius, morphType)));
-    drawState->sampler(0)->setCustomStage(morph);
-    target->drawSimpleRect(rect, NULL);
-}
-
 void convolve_gaussian(GrDrawTarget* target,
                        GrTexture* texture,
                        const SkRect& rect,
@@ -1852,51 +1831,6 @@
     }
 }
 
-GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
-                                      const GrRect& rect,
-                                      MorphologyType morphType,
-                                      SkISize radius) {
-    ASSERT_OWNED_RESOURCE(srcTexture);
-    srcTexture->ref();
-    GrRenderTarget* oldRenderTarget = this->getRenderTarget();
-
-    AutoMatrix avm(this, GrMatrix::I());
-
-    AutoClip acs(this, GrRect::MakeWH(SkIntToScalar(srcTexture->width()), 
-                                      SkIntToScalar(srcTexture->height())));
-    GrTextureDesc desc;
-    desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
-    desc.fWidth = SkScalarCeilToInt(rect.width());
-    desc.fHeight = SkScalarCeilToInt(rect.height());
-    desc.fConfig = kRGBA_8888_GrPixelConfig;
-    if (radius.fWidth > 0) {
-        GrAutoScratchTexture ast(this, desc);
-        this->setRenderTarget(ast.texture()->asRenderTarget());
-        GrDrawTarget* target = this->prepareToDraw(NULL, DEFAULT_BUFFERING);
-        apply_morphology(target, srcTexture, rect, radius.fWidth, morphType,
-                         Gr1DKernelEffect::kX_Direction);
-        SkIRect clearRect = SkIRect::MakeXYWH(
-                    SkScalarFloorToInt(rect.fLeft), 
-                    SkScalarFloorToInt(rect.fBottom),
-                    SkScalarFloorToInt(rect.width()), 
-                    radius.fHeight);
-        this->clear(&clearRect, 0x0);
-        srcTexture->unref();
-        srcTexture = ast.detach();
-    }
-    if (radius.fHeight > 0) {
-        GrAutoScratchTexture ast(this, desc);
-        this->setRenderTarget(ast.texture()->asRenderTarget());
-        GrDrawTarget* target = this->prepareToDraw(NULL, DEFAULT_BUFFERING);
-        apply_morphology(target, srcTexture, rect, radius.fHeight, morphType,
-                         Gr1DKernelEffect::kY_Direction);
-        srcTexture->unref();
-        srcTexture = ast.detach();
-    }
-    this->setRenderTarget(oldRenderTarget);
-    return srcTexture;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 #if GR_DEBUG
 void GrContext::printCacheStats() const {
diff --git a/src/gpu/effects/GrMorphologyEffect.cpp b/src/gpu/effects/GrMorphologyEffect.cpp
index 14b3aef..e69de29 100644
--- a/src/gpu/effects/GrMorphologyEffect.cpp
+++ b/src/gpu/effects/GrMorphologyEffect.cpp
@@ -1,168 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrMorphologyEffect.h"
-#include "gl/GrGLProgramStage.h"
-#include "gl/GrGLSL.h"
-#include "gl/GrGLTexture.h"
-#include "GrProgramStageFactory.h"
-
-///////////////////////////////////////////////////////////////////////////////
-
-class GrGLMorphologyEffect  : public GrGLProgramStage {
-public:
-    GrGLMorphologyEffect (const GrProgramStageFactory& factory,
-                          const GrCustomStage& stage);
-
-    virtual void setupVariables(GrGLShaderBuilder* builder) SK_OVERRIDE;
-    virtual void emitVS(GrGLShaderBuilder* state,
-                        const char* vertexCoords) SK_OVERRIDE {};
-    virtual void emitFS(GrGLShaderBuilder* state,
-                        const char* outputColor,
-                        const char* inputColor,
-                        const char* samplerName) SK_OVERRIDE;
-
-    static inline StageKey GenKey(const GrCustomStage& s, const GrGLCaps& caps);
-
-    virtual void setData(const GrGLUniformManager&,
-                         const GrCustomStage&,
-                         const GrRenderTarget*,
-                         int stageNum) SK_OVERRIDE;
-
-private:
-    int width() const { return GrMorphologyEffect::WidthFromRadius(fRadius); }
-
-    int                                 fRadius;
-    GrMorphologyEffect::MorphologyType  fType;
-    GrGLUniformManager::UniformHandle   fImageIncrementUni;
-
-    typedef GrGLProgramStage INHERITED;
-};
-
-GrGLMorphologyEffect ::GrGLMorphologyEffect(const GrProgramStageFactory& factory,
-                                            const GrCustomStage& stage)
-    : GrGLProgramStage(factory)
-    , fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle) {
-    const GrMorphologyEffect& m = static_cast<const GrMorphologyEffect&>(stage);
-    fRadius = m.radius();
-    fType = m.type();
-}
-
-void GrGLMorphologyEffect::setupVariables(GrGLShaderBuilder* builder) {
-    fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
-                                             kVec2f_GrSLType, "ImageIncrement");
-}
-
-void GrGLMorphologyEffect ::emitFS(GrGLShaderBuilder* builder,
-                                   const char* outputColor,
-                                   const char* inputColor,
-                                   const char* samplerName) {
-    SkString* code = &builder->fFSCode;
-
-    const char* func;
-    switch (fType) {
-        case GrContext::kErode_MorphologyType:
-            code->appendf("\t\tvec4 value = vec4(1, 1, 1, 1);\n");
-            func = "min";
-            break;
-        case GrContext::kDilate_MorphologyType:
-            code->appendf("\t\tvec4 value = vec4(0, 0, 0, 0);\n");
-            func = "max";
-            break;
-        default:
-            GrCrash("Unexpected type");
-            func = ""; // suppress warning
-            break;
-    }
-    const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
-
-    code->appendf("\t\tvec2 coord = %s - %d.0 * %s;\n",
-                   builder->fSampleCoords.c_str(), fRadius, imgInc);
-    code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
-    code->appendf("\t\t\tvalue = %s(value, ", func);
-    builder->emitTextureLookup(samplerName, "coord");
-    code->appendf(");\n");
-    code->appendf("\t\t\tcoord += %s;\n", imgInc);
-    code->appendf("\t\t}\n");
-    code->appendf("\t\t%s = value%s;\n", outputColor, builder->fModulate.c_str());
-}
-
-GrGLProgramStage::StageKey GrGLMorphologyEffect::GenKey(const GrCustomStage& s,
-                                                        const GrGLCaps& caps) {
-    const GrMorphologyEffect& m = static_cast<const GrMorphologyEffect&>(s);
-    StageKey key = static_cast<StageKey>(m.radius());
-    key |= (m.type() << 8);
-    return key;
-}
-
-void GrGLMorphologyEffect ::setData(const GrGLUniformManager& uman,
-                                    const GrCustomStage& data,
-                                    const GrRenderTarget*,
-                                    int stageNum) {
-    const Gr1DKernelEffect& kern =
-        static_cast<const Gr1DKernelEffect&>(data);
-    GrGLTexture& texture =
-        *static_cast<GrGLTexture*>(data.texture(0));
-    // the code we generated was for a specific kernel radius
-    GrAssert(kern.radius() == fRadius);
-    float imageIncrement[2] = { 0 };
-    switch (kern.direction()) {
-        case Gr1DKernelEffect::kX_Direction:
-            imageIncrement[0] = 1.0f / texture.width();
-            break;
-        case Gr1DKernelEffect::kY_Direction:
-            imageIncrement[1] = 1.0f / texture.height();
-            break;
-        default:
-            GrCrash("Unknown filter direction.");
-    }
-    uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture,
-                                       Direction direction,
-                                       int radius,
-                                       MorphologyType type)
-    : Gr1DKernelEffect(texture, direction, radius)
-    , fType(type) {
-}
-
-GrMorphologyEffect::~GrMorphologyEffect() {
-}
-
-const GrProgramStageFactory& GrMorphologyEffect::getFactory() const {
-    return GrTProgramStageFactory<GrMorphologyEffect>::getInstance();
-}
-
-bool GrMorphologyEffect::isEqual(const GrCustomStage& sBase) const {
-    const GrMorphologyEffect& s =
-        static_cast<const GrMorphologyEffect&>(sBase);
-    return (INHERITED::isEqual(sBase) &&
-            this->radius() == s.radius() &&
-            this->direction() == s.direction() &&
-            this->type() == s.type());
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-GR_DEFINE_CUSTOM_STAGE_TEST(GrMorphologyEffect);
-
-GrCustomStage* GrMorphologyEffect::TestCreate(SkRandom* random,
-                                              GrContext* context,
-                                              GrTexture* textures[]) {
-    int texIdx = random->nextBool() ? GrCustomStageUnitTest::kSkiaPMTextureIdx :
-                                      GrCustomStageUnitTest::kAlphaTextureIdx;
-    Direction dir = random->nextBool() ? kX_Direction : kY_Direction;
-    static const int kMaxRadius = 10;
-    int radius = random->nextRangeU(1, kMaxRadius);
-    MorphologyType type = random->nextBool() ? GrContext::kErode_MorphologyType :
-                                               GrContext::kDilate_MorphologyType;
-
-    return SkNEW_ARGS(GrMorphologyEffect, (textures[texIdx], dir, radius, type));
-}
diff --git a/src/gpu/effects/GrMorphologyEffect.h b/src/gpu/effects/GrMorphologyEffect.h
index bb65de7..e69de29 100644
--- a/src/gpu/effects/GrMorphologyEffect.h
+++ b/src/gpu/effects/GrMorphologyEffect.h
@@ -1,49 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrMorphologyEffect_DEFINED
-#define GrMorphologyEffect_DEFINED
-
-#include "GrContext.h"
-#include "Gr1DKernelEffect.h"
-
-class GrGLMorphologyEffect;
-
-/**
- * Morphology effects. Depending upon the type of morphology, either the
- * component-wise min (Erode_Type) or max (Dilate_Type) of all pixels in the
- * kernel is selected as the new color. The new color is modulated by the input
- * color.
- */
-class GrMorphologyEffect : public Gr1DKernelEffect {
-
-public:
-
-    typedef GrContext::MorphologyType MorphologyType;
-
-    GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType);
-    virtual ~GrMorphologyEffect();
-
-    MorphologyType type() const { return fType; }
-
-    static const char* Name() { return "Morphology"; }
-
-    typedef GrGLMorphologyEffect GLProgramStage;
-
-    virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
-    virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
-
-protected:
-
-    MorphologyType fType;
-
-private:
-    GR_DECLARE_CUSTOM_STAGE_TEST;
-
-    typedef Gr1DKernelEffect INHERITED;
-};
-#endif