blob: 09d79265ca4d72f9d65de679582e6f3a93eb1232 [file] [log] [blame]
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00001/*
2 * Copyright 2012 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkMorphologyImageFilter.h"
djsollen@google.com64a0ec32012-06-12 15:17:27 +00009#include "SkBitmap.h"
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000010#include "SkColorPriv.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000011#include "SkFlattenableBuffers.h"
12#include "SkRect.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000013#if SK_SUPPORT_GPU
senorblanco@chromium.org302cffb2012-08-01 20:16:34 +000014#include "GrContext.h"
15#include "GrTexture.h"
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +000016#include "GrTBackendEffectFactory.h"
bsalomon@google.comd698f772012-10-25 13:22:00 +000017#include "gl/GrGLEffect.h"
bsalomon@google.comb4a55b72012-11-02 20:45:37 +000018#include "gl/GrGLEffectMatrix.h"
senorblanco@chromium.org84207c42012-08-22 20:51:19 +000019#include "effects/Gr1DKernelEffect.h"
senorblanco@chromium.orgc2594f42013-01-30 19:08:47 +000020#include "SkImageFilterUtils.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000021#endif
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000022
23SkMorphologyImageFilter::SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer)
24 : INHERITED(buffer) {
tomhudson@google.com75589252012-04-10 17:42:21 +000025 fRadius.fWidth = buffer.readInt();
26 fRadius.fHeight = buffer.readInt();
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000027}
28
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +000029SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input)
30 : INHERITED(input), fRadius(SkISize::Make(radiusX, radiusY)) {
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000031}
32
33
djsollen@google.com54924242012-03-29 15:18:04 +000034void SkMorphologyImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000035 this->INHERITED::flatten(buffer);
tomhudson@google.com75589252012-04-10 17:42:21 +000036 buffer.writeInt(fRadius.fWidth);
37 buffer.writeInt(fRadius.fHeight);
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000038}
39
40static void erode(const SkPMColor* src, SkPMColor* dst,
41 int radius, int width, int height,
42 int srcStrideX, int srcStrideY,
43 int dstStrideX, int dstStrideY)
44{
senorblanco@chromium.org56dd6302012-04-10 17:25:44 +000045 radius = SkMin32(radius, width - 1);
46 const SkPMColor* upperSrc = src + radius * srcStrideX;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000047 for (int x = 0; x < width; ++x) {
48 const SkPMColor* lp = src;
49 const SkPMColor* up = upperSrc;
50 SkPMColor* dptr = dst;
51 for (int y = 0; y < height; ++y) {
52 int minB = 255, minG = 255, minR = 255, minA = 255;
53 for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
54 int b = SkGetPackedB32(*p);
55 int g = SkGetPackedG32(*p);
56 int r = SkGetPackedR32(*p);
57 int a = SkGetPackedA32(*p);
58 if (b < minB) minB = b;
59 if (g < minG) minG = g;
60 if (r < minR) minR = r;
61 if (a < minA) minA = a;
62 }
63 *dptr = SkPackARGB32(minA, minR, minG, minB);
64 dptr += dstStrideY;
65 lp += srcStrideY;
66 up += srcStrideY;
67 }
68 if (x >= radius) src += srcStrideX;
69 if (x + radius < width - 1) upperSrc += srcStrideX;
70 dst += dstStrideX;
71 }
72}
73
74static void erodeX(const SkBitmap& src, SkBitmap* dst, int radiusX)
75{
76 erode(src.getAddr32(0, 0), dst->getAddr32(0, 0),
77 radiusX, src.width(), src.height(),
78 1, src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels());
79}
80
81static void erodeY(const SkBitmap& src, SkBitmap* dst, int radiusY)
82{
83 erode(src.getAddr32(0, 0), dst->getAddr32(0, 0),
84 radiusY, src.height(), src.width(),
85 src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1);
86}
87
88static void dilate(const SkPMColor* src, SkPMColor* dst,
89 int radius, int width, int height,
90 int srcStrideX, int srcStrideY,
91 int dstStrideX, int dstStrideY)
92{
senorblanco@chromium.org56dd6302012-04-10 17:25:44 +000093 radius = SkMin32(radius, width - 1);
94 const SkPMColor* upperSrc = src + radius * srcStrideX;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000095 for (int x = 0; x < width; ++x) {
96 const SkPMColor* lp = src;
97 const SkPMColor* up = upperSrc;
98 SkPMColor* dptr = dst;
99 for (int y = 0; y < height; ++y) {
100 int maxB = 0, maxG = 0, maxR = 0, maxA = 0;
101 for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
102 int b = SkGetPackedB32(*p);
103 int g = SkGetPackedG32(*p);
104 int r = SkGetPackedR32(*p);
105 int a = SkGetPackedA32(*p);
106 if (b > maxB) maxB = b;
107 if (g > maxG) maxG = g;
108 if (r > maxR) maxR = r;
109 if (a > maxA) maxA = a;
110 }
111 *dptr = SkPackARGB32(maxA, maxR, maxG, maxB);
112 dptr += dstStrideY;
113 lp += srcStrideY;
114 up += srcStrideY;
115 }
116 if (x >= radius) src += srcStrideX;
117 if (x + radius < width - 1) upperSrc += srcStrideX;
118 dst += dstStrideX;
119 }
120}
121
122static void dilateX(const SkBitmap& src, SkBitmap* dst, int radiusX)
123{
124 dilate(src.getAddr32(0, 0), dst->getAddr32(0, 0),
125 radiusX, src.width(), src.height(),
126 1, src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels());
127}
128
129static void dilateY(const SkBitmap& src, SkBitmap* dst, int radiusY)
130{
131 dilate(src.getAddr32(0, 0), dst->getAddr32(0, 0),
132 radiusY, src.height(), src.width(),
133 src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1);
134}
135
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +0000136bool SkErodeImageFilter::onFilterImage(Proxy* proxy,
137 const SkBitmap& source, const SkMatrix& ctm,
138 SkBitmap* dst, SkIPoint* offset) {
139 SkBitmap src = this->getInputResult(proxy, source, ctm, offset);
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000140 if (src.config() != SkBitmap::kARGB_8888_Config) {
141 return false;
142 }
143
144 SkAutoLockPixels alp(src);
145 if (!src.getPixels()) {
146 return false;
147 }
148
149 dst->setConfig(src.config(), src.width(), src.height());
150 dst->allocPixels();
151
152 int width = radius().width();
153 int height = radius().height();
154
155 if (width < 0 || height < 0) {
156 return false;
157 }
158
159 if (width == 0 && height == 0) {
160 src.copyTo(dst, dst->config());
161 return true;
162 }
163
164 SkBitmap temp;
165 temp.setConfig(dst->config(), dst->width(), dst->height());
166 if (!temp.allocPixels()) {
167 return false;
168 }
169
170 if (width > 0 && height > 0) {
171 erodeX(src, &temp, width);
172 erodeY(temp, dst, height);
173 } else if (width > 0) {
174 erodeX(src, dst, width);
175 } else if (height > 0) {
176 erodeY(src, dst, height);
177 }
178 return true;
179}
180
senorblanco@chromium.orgf1369ce2012-08-20 14:53:21 +0000181bool SkDilateImageFilter::onFilterImage(Proxy* proxy,
182 const SkBitmap& source, const SkMatrix& ctm,
183 SkBitmap* dst, SkIPoint* offset) {
184 SkBitmap src = this->getInputResult(proxy, source, ctm, offset);
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000185 if (src.config() != SkBitmap::kARGB_8888_Config) {
186 return false;
187 }
188
189 SkAutoLockPixels alp(src);
190 if (!src.getPixels()) {
191 return false;
192 }
193
194 dst->setConfig(src.config(), src.width(), src.height());
195 dst->allocPixels();
196
197 int width = radius().width();
198 int height = radius().height();
199
200 if (width < 0 || height < 0) {
201 return false;
202 }
203
204 if (width == 0 && height == 0) {
205 src.copyTo(dst, dst->config());
206 return true;
207 }
208
209 SkBitmap temp;
210 temp.setConfig(dst->config(), dst->width(), dst->height());
211 if (!temp.allocPixels()) {
212 return false;
213 }
214
215 if (width > 0 && height > 0) {
216 dilateX(src, &temp, width);
217 dilateY(temp, dst, height);
218 } else if (width > 0) {
219 dilateX(src, dst, width);
220 } else if (height > 0) {
221 dilateY(src, dst, height);
222 }
223 return true;
224}
225
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000226#if SK_SUPPORT_GPU
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000227
228///////////////////////////////////////////////////////////////////////////////
229
230class GrGLMorphologyEffect;
231
232/**
233 * Morphology effects. Depending upon the type of morphology, either the
234 * component-wise min (Erode_Type) or max (Dilate_Type) of all pixels in the
235 * kernel is selected as the new color. The new color is modulated by the input
236 * color.
237 */
238class GrMorphologyEffect : public Gr1DKernelEffect {
239
240public:
241
242 enum MorphologyType {
243 kErode_MorphologyType,
244 kDilate_MorphologyType,
245 };
246
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000247 static GrEffectRef* Create(GrTexture* tex, Direction dir, int radius, MorphologyType type) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000248 AutoEffectUnref effect(SkNEW_ARGS(GrMorphologyEffect, (tex, dir, radius, type)));
bsalomon@google.coma1ebbe42013-01-16 15:51:47 +0000249 return CreateEffectRef(effect);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000250 }
251
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000252 virtual ~GrMorphologyEffect();
253
254 MorphologyType type() const { return fType; }
255
256 static const char* Name() { return "Morphology"; }
257
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000258 typedef GrGLMorphologyEffect GLEffect;
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000259
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000260 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000261 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000262
263protected:
264
265 MorphologyType fType;
266
267private:
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000268 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000269
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000270 GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType);
271
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000272 GR_DECLARE_EFFECT_TEST;
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000273
274 typedef Gr1DKernelEffect INHERITED;
275};
276
277///////////////////////////////////////////////////////////////////////////////
278
senorblanco@chromium.orgc2594f42013-01-30 19:08:47 +0000279class GrGLMorphologyEffect : public GrGLEffect {
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000280public:
bsalomon@google.com6340a412013-01-22 19:55:59 +0000281 GrGLMorphologyEffect (const GrBackendEffectFactory&, const GrEffectRef&);
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000282
bsalomon@google.com47d7a882012-10-29 12:47:51 +0000283 virtual void emitCode(GrGLShaderBuilder*,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000284 const GrEffectStage&,
bsalomon@google.com47d7a882012-10-29 12:47:51 +0000285 EffectKey,
286 const char* vertexCoords,
287 const char* outputColor,
288 const char* inputColor,
289 const TextureSamplerArray&) SK_OVERRIDE;
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000290
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000291 static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000292
bsalomon@google.com28a15fb2012-10-26 17:53:18 +0000293 virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000294
295private:
296 int width() const { return GrMorphologyEffect::WidthFromRadius(fRadius); }
297
298 int fRadius;
299 GrMorphologyEffect::MorphologyType fType;
300 GrGLUniformManager::UniformHandle fImageIncrementUni;
bsalomon@google.comb4a55b72012-11-02 20:45:37 +0000301 GrGLEffectMatrix fEffectMatrix;
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000302
bsalomon@google.com47d7a882012-10-29 12:47:51 +0000303 typedef GrGLEffect INHERITED;
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000304};
305
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000306GrGLMorphologyEffect::GrGLMorphologyEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com6340a412013-01-22 19:55:59 +0000307 const GrEffectRef& effect)
bsalomon@google.com374e7592012-10-23 17:30:45 +0000308 : INHERITED(factory)
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000309 , fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000310 const GrMorphologyEffect& m = CastEffect<GrMorphologyEffect>(effect);
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000311 fRadius = m.radius();
312 fType = m.type();
313}
314
bsalomon@google.com47d7a882012-10-29 12:47:51 +0000315void GrGLMorphologyEffect::emitCode(GrGLShaderBuilder* builder,
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000316 const GrEffectStage&,
bsalomon@google.comb4a55b72012-11-02 20:45:37 +0000317 EffectKey key,
bsalomon@google.com47d7a882012-10-29 12:47:51 +0000318 const char* vertexCoords,
319 const char* outputColor,
320 const char* inputColor,
321 const TextureSamplerArray& samplers) {
bsalomon@google.comb4a55b72012-11-02 20:45:37 +0000322 const char* coords;
323 fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, vertexCoords, &coords);
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000324 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
325 kVec2f_GrSLType, "ImageIncrement");
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000326
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000327 SkString* code = &builder->fFSCode;
328
329 const char* func;
330 switch (fType) {
331 case GrMorphologyEffect::kErode_MorphologyType:
bsalomon@google.com868a8e72012-08-30 19:11:34 +0000332 code->appendf("\t\t%s = vec4(1, 1, 1, 1);\n", outputColor);
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000333 func = "min";
334 break;
335 case GrMorphologyEffect::kDilate_MorphologyType:
bsalomon@google.com868a8e72012-08-30 19:11:34 +0000336 code->appendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000337 func = "max";
338 break;
339 default:
340 GrCrash("Unexpected type");
341 func = ""; // suppress warning
342 break;
343 }
344 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
345
bsalomon@google.comb4a55b72012-11-02 20:45:37 +0000346 code->appendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords, fRadius, imgInc);
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000347 code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
bsalomon@google.com868a8e72012-08-30 19:11:34 +0000348 code->appendf("\t\t\t%s = %s(%s, ", outputColor, func, outputColor);
bsalomon@google.comf06df1b2012-09-06 20:22:31 +0000349 builder->appendTextureLookup(&builder->fFSCode, samplers[0], "coord");
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000350 code->appendf(");\n");
351 code->appendf("\t\t\tcoord += %s;\n", imgInc);
352 code->appendf("\t\t}\n");
bsalomon@google.com868a8e72012-08-30 19:11:34 +0000353 GrGLSLMulVarBy4f(code, 2, outputColor, inputColor);
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000354}
355
bsalomon@google.com2eaaefd2012-10-29 19:51:22 +0000356GrGLEffect::EffectKey GrGLMorphologyEffect::GenKey(const GrEffectStage& s, const GrGLCaps&) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000357 const GrMorphologyEffect& m = GetEffectFromStage<GrMorphologyEffect>(s);
bsalomon@google.com46fba0d2012-10-25 21:42:05 +0000358 EffectKey key = static_cast<EffectKey>(m.radius());
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000359 key |= (m.type() << 8);
bsalomon@google.comb4a55b72012-11-02 20:45:37 +0000360 key <<= GrGLEffectMatrix::kKeyBits;
361 EffectKey matrixKey = GrGLEffectMatrix::GenKey(m.getMatrix(),
362 s.getCoordChangeMatrix(),
363 m.texture(0));
364 return key | matrixKey;
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000365}
366
bsalomon@google.com28a15fb2012-10-26 17:53:18 +0000367void GrGLMorphologyEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000368 const Gr1DKernelEffect& kern = GetEffectFromStage<Gr1DKernelEffect>(stage);
bsalomon@google.com2d0bade2012-10-26 19:01:17 +0000369 GrTexture& texture = *kern.texture(0);
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000370 // the code we generated was for a specific kernel radius
371 GrAssert(kern.radius() == fRadius);
372 float imageIncrement[2] = { 0 };
373 switch (kern.direction()) {
374 case Gr1DKernelEffect::kX_Direction:
375 imageIncrement[0] = 1.0f / texture.width();
376 break;
377 case Gr1DKernelEffect::kY_Direction:
378 imageIncrement[1] = 1.0f / texture.height();
379 break;
380 default:
381 GrCrash("Unknown filter direction.");
382 }
383 uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
bsalomon@google.comb4a55b72012-11-02 20:45:37 +0000384 fEffectMatrix.setData(uman, kern.getMatrix(), stage.getCoordChangeMatrix(), kern.texture(0));
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000385}
386
387///////////////////////////////////////////////////////////////////////////////
388
389GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture,
390 Direction direction,
391 int radius,
392 MorphologyType type)
393 : Gr1DKernelEffect(texture, direction, radius)
394 , fType(type) {
395}
396
397GrMorphologyEffect::~GrMorphologyEffect() {
398}
399
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000400const GrBackendEffectFactory& GrMorphologyEffect::getFactory() const {
401 return GrTBackendEffectFactory<GrMorphologyEffect>::getInstance();
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000402}
403
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000404bool GrMorphologyEffect::onIsEqual(const GrEffect& sBase) const {
bsalomon@google.com6340a412013-01-22 19:55:59 +0000405 const GrMorphologyEffect& s = CastEffect<GrMorphologyEffect>(sBase);
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000406 return (this->texture(0) == s.texture(0) &&
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000407 this->radius() == s.radius() &&
408 this->direction() == s.direction() &&
409 this->type() == s.type());
410}
411
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000412void GrMorphologyEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
413 // This is valid because the color components of the result of the kernel all come
414 // exactly from existing values in the source texture.
415 this->updateConstantColorComponentsForModulation(color, validFlags);
416}
417
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000418///////////////////////////////////////////////////////////////////////////////
419
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000420GR_DEFINE_EFFECT_TEST(GrMorphologyEffect);
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000421
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000422GrEffectRef* GrMorphologyEffect::TestCreate(SkRandom* random,
423 GrContext* context,
424 GrTexture* textures[]) {
bsalomon@google.com6f261be2012-10-24 19:07:10 +0000425 int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
426 GrEffectUnitTest::kAlphaTextureIdx;
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000427 Direction dir = random->nextBool() ? kX_Direction : kY_Direction;
428 static const int kMaxRadius = 10;
429 int radius = random->nextRangeU(1, kMaxRadius);
430 MorphologyType type = random->nextBool() ? GrMorphologyEffect::kErode_MorphologyType :
431 GrMorphologyEffect::kDilate_MorphologyType;
432
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000433 return GrMorphologyEffect::Create(textures[texIdx], dir, radius, type);
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000434}
435
436namespace {
437
438void apply_morphology_pass(GrContext* context,
439 GrTexture* texture,
senorblanco@chromium.orgc2594f42013-01-30 19:08:47 +0000440 const SkIRect& rect,
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000441 int radius,
442 GrMorphologyEffect::MorphologyType morphType,
443 Gr1DKernelEffect::Direction direction) {
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000444 GrPaint paint;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000445 paint.colorStage(0)->setEffect(GrMorphologyEffect::Create(texture,
446 direction,
447 radius,
448 morphType))->unref();
senorblanco@chromium.orgc2594f42013-01-30 19:08:47 +0000449 context->drawRect(paint, SkRect::MakeFromIRect(rect));
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000450}
451
452GrTexture* apply_morphology(GrTexture* srcTexture,
senorblanco@chromium.orgc2594f42013-01-30 19:08:47 +0000453 const SkIRect& rect,
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000454 GrMorphologyEffect::MorphologyType morphType,
455 SkISize radius) {
456 GrContext* context = srcTexture->getContext();
457 srcTexture->ref();
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000458
459 GrContext::AutoMatrix am;
460 am.setIdentity(context);
461
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000462 GrContext::AutoClip acs(context, GrRect::MakeWH(SkIntToScalar(srcTexture->width()),
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000463 SkIntToScalar(srcTexture->height())));
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000464
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000465 GrTextureDesc desc;
466 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
senorblanco@chromium.orgc2594f42013-01-30 19:08:47 +0000467 desc.fWidth = rect.width();
468 desc.fHeight = rect.height();
469 desc.fConfig = kSkia8888_GrPixelConfig;
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000470
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000471 if (radius.fWidth > 0) {
472 GrAutoScratchTexture ast(context, desc);
473 GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget());
474 apply_morphology_pass(context, srcTexture, rect, radius.fWidth,
475 morphType, Gr1DKernelEffect::kX_Direction);
senorblanco@chromium.orgc2594f42013-01-30 19:08:47 +0000476 SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
477 rect.width(), radius.fHeight);
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000478 context->clear(&clearRect, 0x0);
479 srcTexture->unref();
480 srcTexture = ast.detach();
481 }
482 if (radius.fHeight > 0) {
483 GrAutoScratchTexture ast(context, desc);
484 GrContext::AutoRenderTarget art(context, ast.texture()->asRenderTarget());
485 apply_morphology_pass(context, srcTexture, rect, radius.fHeight,
486 morphType, Gr1DKernelEffect::kY_Direction);
487 srcTexture->unref();
488 srcTexture = ast.detach();
489 }
490 return srcTexture;
491}
492
493};
494
senorblanco@chromium.orgc2594f42013-01-30 19:08:47 +0000495bool SkDilateImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
496 SkBitmap inputBM;
497 if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &inputBM)) {
498 return false;
499 }
500 GrTexture* input = (GrTexture*) inputBM.getTexture();
501 SkIRect bounds;
502 src.getBounds(&bounds);
503 SkAutoTUnref<GrTexture> resultTex(apply_morphology(input, bounds,
504 GrMorphologyEffect::kDilate_MorphologyType, radius()));
505 return SkImageFilterUtils::WrapTexture(resultTex, src.width(), src.height(), result);
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000506}
507
senorblanco@chromium.orgc2594f42013-01-30 19:08:47 +0000508bool SkErodeImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
509 SkBitmap inputBM;
510 if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &inputBM)) {
511 return false;
512 }
513 GrTexture* input = (GrTexture*) inputBM.getTexture();
514 SkIRect bounds;
515 src.getBounds(&bounds);
516 SkAutoTUnref<GrTexture> resultTex(apply_morphology(input, bounds,
517 GrMorphologyEffect::kErode_MorphologyType, radius()));
518 return SkImageFilterUtils::WrapTexture(resultTex, src.width(), src.height(), result);
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000519}
520
senorblanco@chromium.org84207c42012-08-22 20:51:19 +0000521#endif