SkMorphologyImageFilter.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. /*
  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. #include "include/effects/SkMorphologyImageFilter.h"
  8. #include "include/core/SkBitmap.h"
  9. #include "include/core/SkRect.h"
  10. #include "include/private/SkColorData.h"
  11. #include "src/core/SkImageFilterPriv.h"
  12. #include "src/core/SkReadBuffer.h"
  13. #include "src/core/SkSpecialImage.h"
  14. #include "src/core/SkWriteBuffer.h"
  15. #if SK_SUPPORT_GPU
  16. #include "include/gpu/GrContext.h"
  17. #include "include/gpu/GrTexture.h"
  18. #include "include/private/GrRecordingContext.h"
  19. #include "src/gpu/GrContextPriv.h"
  20. #include "src/gpu/GrCoordTransform.h"
  21. #include "src/gpu/GrFixedClip.h"
  22. #include "src/gpu/GrRecordingContextPriv.h"
  23. #include "src/gpu/GrRenderTargetContext.h"
  24. #include "src/gpu/GrTextureProxy.h"
  25. #include "src/gpu/SkGr.h"
  26. #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
  27. #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
  28. #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
  29. #include "src/gpu/glsl/GrGLSLUniformHandler.h"
  30. #endif
  31. sk_sp<SkImageFilter> SkDilateImageFilter::Make(int radiusX, int radiusY,
  32. sk_sp<SkImageFilter> input,
  33. const CropRect* cropRect) {
  34. if (radiusX < 0 || radiusY < 0) {
  35. return nullptr;
  36. }
  37. return sk_sp<SkImageFilter>(new SkDilateImageFilter(radiusX, radiusY,
  38. std::move(input),
  39. cropRect));
  40. }
  41. sk_sp<SkImageFilter> SkErodeImageFilter::Make(int radiusX, int radiusY,
  42. sk_sp<SkImageFilter> input,
  43. const CropRect* cropRect) {
  44. if (radiusX < 0 || radiusY < 0) {
  45. return nullptr;
  46. }
  47. return sk_sp<SkImageFilter>(new SkErodeImageFilter(radiusX, radiusY,
  48. std::move(input),
  49. cropRect));
  50. }
  51. SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX,
  52. int radiusY,
  53. sk_sp<SkImageFilter> input,
  54. const CropRect* cropRect)
  55. : INHERITED(&input, 1, cropRect)
  56. , fRadius(SkISize::Make(radiusX, radiusY)) {
  57. }
  58. void SkMorphologyImageFilter::flatten(SkWriteBuffer& buffer) const {
  59. this->INHERITED::flatten(buffer);
  60. buffer.writeInt(fRadius.fWidth);
  61. buffer.writeInt(fRadius.fHeight);
  62. }
  63. static void call_proc_X(SkMorphologyImageFilter::Proc procX,
  64. const SkBitmap& src, SkBitmap* dst,
  65. int radiusX, const SkIRect& bounds) {
  66. procX(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0),
  67. radiusX, bounds.width(), bounds.height(),
  68. src.rowBytesAsPixels(), dst->rowBytesAsPixels());
  69. }
  70. static void call_proc_Y(SkMorphologyImageFilter::Proc procY,
  71. const SkPMColor* src, int srcRowBytesAsPixels, SkBitmap* dst,
  72. int radiusY, const SkIRect& bounds) {
  73. procY(src, dst->getAddr32(0, 0),
  74. radiusY, bounds.height(), bounds.width(),
  75. srcRowBytesAsPixels, dst->rowBytesAsPixels());
  76. }
  77. SkRect SkMorphologyImageFilter::computeFastBounds(const SkRect& src) const {
  78. SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
  79. bounds.outset(SkIntToScalar(fRadius.width()), SkIntToScalar(fRadius.height()));
  80. return bounds;
  81. }
  82. SkIRect SkMorphologyImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
  83. MapDirection, const SkIRect* inputRect) const {
  84. SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()),
  85. SkIntToScalar(this->radius().height()));
  86. ctm.mapVectors(&radius, 1);
  87. return src.makeOutset(SkScalarCeilToInt(radius.x()), SkScalarCeilToInt(radius.y()));
  88. }
  89. sk_sp<SkFlattenable> SkErodeImageFilter::CreateProc(SkReadBuffer& buffer) {
  90. SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
  91. const int width = buffer.readInt();
  92. const int height = buffer.readInt();
  93. return Make(width, height, common.getInput(0), &common.cropRect());
  94. }
  95. sk_sp<SkFlattenable> SkDilateImageFilter::CreateProc(SkReadBuffer& buffer) {
  96. SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
  97. const int width = buffer.readInt();
  98. const int height = buffer.readInt();
  99. return Make(width, height, common.getInput(0), &common.cropRect());
  100. }
  101. #if SK_SUPPORT_GPU
  102. ///////////////////////////////////////////////////////////////////////////////
  103. /**
  104. * Morphology effects. Depending upon the type of morphology, either the
  105. * component-wise min (Erode_Type) or max (Dilate_Type) of all pixels in the
  106. * kernel is selected as the new color. The new color is modulated by the input
  107. * color.
  108. */
  109. class GrMorphologyEffect : public GrFragmentProcessor {
  110. public:
  111. enum class Direction { kX, kY };
  112. enum class Type { kErode, kDilate };
  113. static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy, Direction dir,
  114. int radius, Type type) {
  115. return std::unique_ptr<GrFragmentProcessor>(
  116. new GrMorphologyEffect(std::move(proxy), dir, radius, type, nullptr));
  117. }
  118. static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy, Direction dir,
  119. int radius, Type type, const float bounds[2]) {
  120. return std::unique_ptr<GrFragmentProcessor>(
  121. new GrMorphologyEffect(std::move(proxy), dir, radius, type, bounds));
  122. }
  123. Type type() const { return fType; }
  124. bool useRange() const { return fUseRange; }
  125. const float* range() const { return fRange; }
  126. Direction direction() const { return fDirection; }
  127. int radius() const { return fRadius; }
  128. int width() const { return 2 * fRadius + 1; }
  129. const char* name() const override { return "Morphology"; }
  130. std::unique_ptr<GrFragmentProcessor> clone() const override {
  131. return std::unique_ptr<GrFragmentProcessor>(new GrMorphologyEffect(*this));
  132. }
  133. private:
  134. GrCoordTransform fCoordTransform;
  135. TextureSampler fTextureSampler;
  136. Direction fDirection;
  137. int fRadius;
  138. Type fType;
  139. bool fUseRange;
  140. float fRange[2];
  141. GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
  142. void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
  143. bool onIsEqual(const GrFragmentProcessor&) const override;
  144. const TextureSampler& onTextureSampler(int i) const override { return fTextureSampler; }
  145. GrMorphologyEffect(sk_sp<GrTextureProxy>, Direction, int radius, Type, const float range[2]);
  146. explicit GrMorphologyEffect(const GrMorphologyEffect&);
  147. GR_DECLARE_FRAGMENT_PROCESSOR_TEST
  148. typedef GrFragmentProcessor INHERITED;
  149. };
  150. ///////////////////////////////////////////////////////////////////////////////
  151. class GrGLMorphologyEffect : public GrGLSLFragmentProcessor {
  152. public:
  153. void emitCode(EmitArgs&) override;
  154. static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
  155. protected:
  156. void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
  157. private:
  158. GrGLSLProgramDataManager::UniformHandle fPixelSizeUni;
  159. GrGLSLProgramDataManager::UniformHandle fRangeUni;
  160. typedef GrGLSLFragmentProcessor INHERITED;
  161. };
  162. void GrGLMorphologyEffect::emitCode(EmitArgs& args) {
  163. const GrMorphologyEffect& me = args.fFp.cast<GrMorphologyEffect>();
  164. GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
  165. fPixelSizeUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, "PixelSize");
  166. const char* pixelSizeInc = uniformHandler->getUniformCStr(fPixelSizeUni);
  167. fRangeUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat2_GrSLType, "Range");
  168. const char* range = uniformHandler->getUniformCStr(fRangeUni);
  169. GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
  170. SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
  171. const char* func;
  172. switch (me.type()) {
  173. case GrMorphologyEffect::Type::kErode:
  174. fragBuilder->codeAppendf("\t\t%s = half4(1, 1, 1, 1);\n", args.fOutputColor);
  175. func = "min";
  176. break;
  177. case GrMorphologyEffect::Type::kDilate:
  178. fragBuilder->codeAppendf("\t\t%s = half4(0, 0, 0, 0);\n", args.fOutputColor);
  179. func = "max";
  180. break;
  181. default:
  182. SK_ABORT("Unexpected type");
  183. func = ""; // suppress warning
  184. break;
  185. }
  186. const char* dir;
  187. switch (me.direction()) {
  188. case GrMorphologyEffect::Direction::kX:
  189. dir = "x";
  190. break;
  191. case GrMorphologyEffect::Direction::kY:
  192. dir = "y";
  193. break;
  194. default:
  195. SK_ABORT("Unknown filter direction.");
  196. dir = ""; // suppress warning
  197. }
  198. int width = me.width();
  199. // float2 coord = coord2D;
  200. fragBuilder->codeAppendf("\t\tfloat2 coord = %s;\n", coords2D.c_str());
  201. // coord.x -= radius * pixelSize;
  202. fragBuilder->codeAppendf("\t\tcoord.%s -= %d.0 * %s; \n", dir, me.radius(), pixelSizeInc);
  203. if (me.useRange()) {
  204. // highBound = min(highBound, coord.x + (width-1) * pixelSize);
  205. fragBuilder->codeAppendf("\t\tfloat highBound = min(%s.y, coord.%s + %f * %s);",
  206. range, dir, float(width - 1), pixelSizeInc);
  207. // coord.x = max(lowBound, coord.x);
  208. fragBuilder->codeAppendf("\t\tcoord.%s = max(%s.x, coord.%s);", dir, range, dir);
  209. }
  210. fragBuilder->codeAppendf("\t\tfor (int i = 0; i < %d; i++) {\n", width);
  211. fragBuilder->codeAppendf("\t\t\t%s = %s(%s, ", args.fOutputColor, func, args.fOutputColor);
  212. fragBuilder->appendTextureLookup(args.fTexSamplers[0], "coord");
  213. fragBuilder->codeAppend(");\n");
  214. // coord.x += pixelSize;
  215. fragBuilder->codeAppendf("\t\t\tcoord.%s += %s;\n", dir, pixelSizeInc);
  216. if (me.useRange()) {
  217. // coord.x = min(highBound, coord.x);
  218. fragBuilder->codeAppendf("\t\t\tcoord.%s = min(highBound, coord.%s);", dir, dir);
  219. }
  220. fragBuilder->codeAppend("\t\t}\n");
  221. fragBuilder->codeAppendf("%s *= %s;\n", args.fOutputColor, args.fInputColor);
  222. }
  223. void GrGLMorphologyEffect::GenKey(const GrProcessor& proc,
  224. const GrShaderCaps&, GrProcessorKeyBuilder* b) {
  225. const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>();
  226. uint32_t key = static_cast<uint32_t>(m.radius());
  227. key |= (static_cast<uint32_t>(m.type()) << 8);
  228. key |= (static_cast<uint32_t>(m.direction()) << 9);
  229. if (m.useRange()) {
  230. key |= 1 << 10;
  231. }
  232. b->add32(key);
  233. }
  234. void GrGLMorphologyEffect::onSetData(const GrGLSLProgramDataManager& pdman,
  235. const GrFragmentProcessor& proc) {
  236. const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>();
  237. GrSurfaceProxy* proxy = m.textureSampler(0).proxy();
  238. GrTexture& texture = *proxy->peekTexture();
  239. float pixelSize = 0.0f;
  240. switch (m.direction()) {
  241. case GrMorphologyEffect::Direction::kX:
  242. pixelSize = 1.0f / texture.width();
  243. break;
  244. case GrMorphologyEffect::Direction::kY:
  245. pixelSize = 1.0f / texture.height();
  246. break;
  247. default:
  248. SK_ABORT("Unknown filter direction.");
  249. }
  250. pdman.set1f(fPixelSizeUni, pixelSize);
  251. if (m.useRange()) {
  252. const float* range = m.range();
  253. if (GrMorphologyEffect::Direction::kY == m.direction() &&
  254. proxy->origin() == kBottomLeft_GrSurfaceOrigin) {
  255. pdman.set2f(fRangeUni, 1.0f - (range[1]*pixelSize), 1.0f - (range[0]*pixelSize));
  256. } else {
  257. pdman.set2f(fRangeUni, range[0] * pixelSize, range[1] * pixelSize);
  258. }
  259. }
  260. }
  261. ///////////////////////////////////////////////////////////////////////////////
  262. GrMorphologyEffect::GrMorphologyEffect(sk_sp<GrTextureProxy> proxy,
  263. Direction direction,
  264. int radius,
  265. Type type,
  266. const float range[2])
  267. : INHERITED(kGrMorphologyEffect_ClassID,
  268. ModulateForClampedSamplerOptFlags(proxy->config()))
  269. , fCoordTransform(proxy.get())
  270. , fTextureSampler(std::move(proxy))
  271. , fDirection(direction)
  272. , fRadius(radius)
  273. , fType(type)
  274. , fUseRange(SkToBool(range)) {
  275. // Make sure the sampler's ctor uses the clamp wrap mode
  276. SkASSERT(fTextureSampler.samplerState().wrapModeX() == GrSamplerState::WrapMode::kClamp &&
  277. fTextureSampler.samplerState().wrapModeY() == GrSamplerState::WrapMode::kClamp);
  278. this->addCoordTransform(&fCoordTransform);
  279. this->setTextureSamplerCnt(1);
  280. if (fUseRange) {
  281. fRange[0] = range[0];
  282. fRange[1] = range[1];
  283. }
  284. }
  285. GrMorphologyEffect::GrMorphologyEffect(const GrMorphologyEffect& that)
  286. : INHERITED(kGrMorphologyEffect_ClassID, that.optimizationFlags())
  287. , fCoordTransform(that.fCoordTransform)
  288. , fTextureSampler(that.fTextureSampler)
  289. , fDirection(that.fDirection)
  290. , fRadius(that.fRadius)
  291. , fType(that.fType)
  292. , fUseRange(that.fUseRange) {
  293. this->addCoordTransform(&fCoordTransform);
  294. this->setTextureSamplerCnt(1);
  295. if (that.fUseRange) {
  296. fRange[0] = that.fRange[0];
  297. fRange[1] = that.fRange[1];
  298. }
  299. }
  300. void GrMorphologyEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
  301. GrProcessorKeyBuilder* b) const {
  302. GrGLMorphologyEffect::GenKey(*this, caps, b);
  303. }
  304. GrGLSLFragmentProcessor* GrMorphologyEffect::onCreateGLSLInstance() const {
  305. return new GrGLMorphologyEffect;
  306. }
  307. bool GrMorphologyEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
  308. const GrMorphologyEffect& s = sBase.cast<GrMorphologyEffect>();
  309. return (this->radius() == s.radius() &&
  310. this->direction() == s.direction() &&
  311. this->useRange() == s.useRange() &&
  312. this->type() == s.type());
  313. }
  314. ///////////////////////////////////////////////////////////////////////////////
  315. GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMorphologyEffect);
  316. #if GR_TEST_UTILS
  317. std::unique_ptr<GrFragmentProcessor> GrMorphologyEffect::TestCreate(GrProcessorTestData* d) {
  318. int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
  319. : GrProcessorUnitTest::kAlphaTextureIdx;
  320. sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);
  321. Direction dir = d->fRandom->nextBool() ? Direction::kX : Direction::kY;
  322. static const int kMaxRadius = 10;
  323. int radius = d->fRandom->nextRangeU(1, kMaxRadius);
  324. Type type = d->fRandom->nextBool() ? GrMorphologyEffect::Type::kErode
  325. : GrMorphologyEffect::Type::kDilate;
  326. return GrMorphologyEffect::Make(std::move(proxy), dir, radius, type);
  327. }
  328. #endif
  329. static void apply_morphology_rect(GrRenderTargetContext* renderTargetContext,
  330. const GrClip& clip,
  331. sk_sp<GrTextureProxy> proxy,
  332. const SkIRect& srcRect,
  333. const SkIRect& dstRect,
  334. int radius,
  335. GrMorphologyEffect::Type morphType,
  336. const float bounds[2],
  337. GrMorphologyEffect::Direction direction) {
  338. GrPaint paint;
  339. paint.addColorFragmentProcessor(GrMorphologyEffect::Make(std::move(proxy),
  340. direction, radius, morphType,
  341. bounds));
  342. paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
  343. renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(),
  344. SkRect::Make(dstRect), SkRect::Make(srcRect));
  345. }
  346. static void apply_morphology_rect_no_bounds(GrRenderTargetContext* renderTargetContext,
  347. const GrClip& clip,
  348. sk_sp<GrTextureProxy> proxy,
  349. const SkIRect& srcRect,
  350. const SkIRect& dstRect,
  351. int radius,
  352. GrMorphologyEffect::Type morphType,
  353. GrMorphologyEffect::Direction direction) {
  354. GrPaint paint;
  355. paint.addColorFragmentProcessor(GrMorphologyEffect::Make(std::move(proxy),
  356. direction, radius, morphType));
  357. paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
  358. renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(),
  359. SkRect::Make(dstRect), SkRect::Make(srcRect));
  360. }
  361. static void apply_morphology_pass(GrRenderTargetContext* renderTargetContext,
  362. const GrClip& clip,
  363. sk_sp<GrTextureProxy> textureProxy,
  364. const SkIRect& srcRect,
  365. const SkIRect& dstRect,
  366. int radius,
  367. GrMorphologyEffect::Type morphType,
  368. GrMorphologyEffect::Direction direction) {
  369. float bounds[2] = { 0.0f, 1.0f };
  370. SkIRect lowerSrcRect = srcRect, lowerDstRect = dstRect;
  371. SkIRect middleSrcRect = srcRect, middleDstRect = dstRect;
  372. SkIRect upperSrcRect = srcRect, upperDstRect = dstRect;
  373. if (direction == GrMorphologyEffect::Direction::kX) {
  374. bounds[0] = SkIntToScalar(srcRect.left()) + 0.5f;
  375. bounds[1] = SkIntToScalar(srcRect.right()) - 0.5f;
  376. lowerSrcRect.fRight = srcRect.left() + radius;
  377. lowerDstRect.fRight = dstRect.left() + radius;
  378. upperSrcRect.fLeft = srcRect.right() - radius;
  379. upperDstRect.fLeft = dstRect.right() - radius;
  380. middleSrcRect.inset(radius, 0);
  381. middleDstRect.inset(radius, 0);
  382. } else {
  383. bounds[0] = SkIntToScalar(srcRect.top()) + 0.5f;
  384. bounds[1] = SkIntToScalar(srcRect.bottom()) - 0.5f;
  385. lowerSrcRect.fBottom = srcRect.top() + radius;
  386. lowerDstRect.fBottom = dstRect.top() + radius;
  387. upperSrcRect.fTop = srcRect.bottom() - radius;
  388. upperDstRect.fTop = dstRect.bottom() - radius;
  389. middleSrcRect.inset(0, radius);
  390. middleDstRect.inset(0, radius);
  391. }
  392. if (middleSrcRect.width() <= 0) {
  393. // radius covers srcRect; use bounds over entire draw
  394. apply_morphology_rect(renderTargetContext, clip, std::move(textureProxy),
  395. srcRect, dstRect, radius, morphType, bounds, direction);
  396. } else {
  397. // Draw upper and lower margins with bounds; middle without.
  398. apply_morphology_rect(renderTargetContext, clip, textureProxy,
  399. lowerSrcRect, lowerDstRect, radius, morphType, bounds, direction);
  400. apply_morphology_rect(renderTargetContext, clip, textureProxy,
  401. upperSrcRect, upperDstRect, radius, morphType, bounds, direction);
  402. apply_morphology_rect_no_bounds(renderTargetContext, clip, std::move(textureProxy),
  403. middleSrcRect, middleDstRect, radius, morphType, direction);
  404. }
  405. }
  406. static sk_sp<SkSpecialImage> apply_morphology(
  407. GrRecordingContext* context,
  408. SkSpecialImage* input,
  409. const SkIRect& rect,
  410. GrMorphologyEffect::Type morphType,
  411. SkISize radius,
  412. const SkImageFilter::OutputProperties& outputProperties) {
  413. sk_sp<GrTextureProxy> srcTexture(input->asTextureProxyRef(context));
  414. SkASSERT(srcTexture);
  415. sk_sp<SkColorSpace> colorSpace = sk_ref_sp(outputProperties.colorSpace());
  416. GrColorType colorType = SkColorTypeToGrColorType(outputProperties.colorType());
  417. // setup new clip
  418. const GrFixedClip clip(SkIRect::MakeWH(srcTexture->width(), srcTexture->height()));
  419. const SkIRect dstRect = SkIRect::MakeWH(rect.width(), rect.height());
  420. SkIRect srcRect = rect;
  421. SkASSERT(radius.width() > 0 || radius.height() > 0);
  422. if (radius.fWidth > 0) {
  423. sk_sp<GrRenderTargetContext> dstRTContext(context->priv().makeDeferredRenderTargetContext(
  424. SkBackingFit::kApprox,
  425. rect.width(),
  426. rect.height(),
  427. colorType,
  428. colorSpace,
  429. 1,
  430. GrMipMapped::kNo,
  431. kBottomLeft_GrSurfaceOrigin,
  432. nullptr,
  433. SkBudgeted::kYes,
  434. srcTexture->isProtected() ? GrProtected::kYes : GrProtected::kNo));
  435. if (!dstRTContext) {
  436. return nullptr;
  437. }
  438. apply_morphology_pass(dstRTContext.get(), clip, std::move(srcTexture), srcRect, dstRect,
  439. radius.fWidth, morphType, GrMorphologyEffect::Direction::kX);
  440. SkIRect clearRect = SkIRect::MakeXYWH(dstRect.fLeft, dstRect.fBottom,
  441. dstRect.width(), radius.fHeight);
  442. SkPMColor4f clearColor = GrMorphologyEffect::Type::kErode == morphType
  443. ? SK_PMColor4fWHITE : SK_PMColor4fTRANSPARENT;
  444. dstRTContext->clear(&clearRect, clearColor, GrRenderTargetContext::CanClearFullscreen::kNo);
  445. srcTexture = dstRTContext->asTextureProxyRef();
  446. srcRect = dstRect;
  447. }
  448. if (radius.fHeight > 0) {
  449. sk_sp<GrRenderTargetContext> dstRTContext(context->priv().makeDeferredRenderTargetContext(
  450. SkBackingFit::kApprox,
  451. rect.width(),
  452. rect.height(),
  453. colorType,
  454. colorSpace,
  455. 1,
  456. GrMipMapped::kNo,
  457. kBottomLeft_GrSurfaceOrigin,
  458. nullptr,
  459. SkBudgeted::kYes,
  460. srcTexture->isProtected() ? GrProtected::kYes : GrProtected::kNo));
  461. if (!dstRTContext) {
  462. return nullptr;
  463. }
  464. apply_morphology_pass(dstRTContext.get(), clip, std::move(srcTexture), srcRect, dstRect,
  465. radius.fHeight, morphType, GrMorphologyEffect::Direction::kY);
  466. srcTexture = dstRTContext->asTextureProxyRef();
  467. }
  468. return SkSpecialImage::MakeDeferredFromGpu(context,
  469. SkIRect::MakeWH(rect.width(), rect.height()),
  470. kNeedNewImageUniqueID_SpecialImage,
  471. std::move(srcTexture), std::move(colorSpace),
  472. &input->props());
  473. }
  474. #endif
  475. namespace {
  476. enum MorphType { kDilate, kErode };
  477. enum class MorphDirection { kX, kY };
  478. #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
  479. template<MorphType type, MorphDirection direction>
  480. static void morph(const SkPMColor* src, SkPMColor* dst,
  481. int radius, int width, int height, int srcStride, int dstStride) {
  482. const int srcStrideX = direction == MorphDirection::kX ? 1 : srcStride;
  483. const int dstStrideX = direction == MorphDirection::kX ? 1 : dstStride;
  484. const int srcStrideY = direction == MorphDirection::kX ? srcStride : 1;
  485. const int dstStrideY = direction == MorphDirection::kX ? dstStride : 1;
  486. radius = SkMin32(radius, width - 1);
  487. const SkPMColor* upperSrc = src + radius * srcStrideX;
  488. for (int x = 0; x < width; ++x) {
  489. const SkPMColor* lp = src;
  490. const SkPMColor* up = upperSrc;
  491. SkPMColor* dptr = dst;
  492. for (int y = 0; y < height; ++y) {
  493. __m128i extreme = (type == kDilate) ? _mm_setzero_si128()
  494. : _mm_set1_epi32(0xFFFFFFFF);
  495. for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
  496. __m128i src_pixel = _mm_cvtsi32_si128(*p);
  497. extreme = (type == kDilate) ? _mm_max_epu8(src_pixel, extreme)
  498. : _mm_min_epu8(src_pixel, extreme);
  499. }
  500. *dptr = _mm_cvtsi128_si32(extreme);
  501. dptr += dstStrideY;
  502. lp += srcStrideY;
  503. up += srcStrideY;
  504. }
  505. if (x >= radius) { src += srcStrideX; }
  506. if (x + radius < width - 1) { upperSrc += srcStrideX; }
  507. dst += dstStrideX;
  508. }
  509. }
  510. #elif defined(SK_ARM_HAS_NEON)
  511. template<MorphType type, MorphDirection direction>
  512. static void morph(const SkPMColor* src, SkPMColor* dst,
  513. int radius, int width, int height, int srcStride, int dstStride) {
  514. const int srcStrideX = direction == MorphDirection::kX ? 1 : srcStride;
  515. const int dstStrideX = direction == MorphDirection::kX ? 1 : dstStride;
  516. const int srcStrideY = direction == MorphDirection::kX ? srcStride : 1;
  517. const int dstStrideY = direction == MorphDirection::kX ? dstStride : 1;
  518. radius = SkMin32(radius, width - 1);
  519. const SkPMColor* upperSrc = src + radius * srcStrideX;
  520. for (int x = 0; x < width; ++x) {
  521. const SkPMColor* lp = src;
  522. const SkPMColor* up = upperSrc;
  523. SkPMColor* dptr = dst;
  524. for (int y = 0; y < height; ++y) {
  525. uint8x8_t extreme = vdup_n_u8(type == kDilate ? 0 : 255);
  526. for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
  527. uint8x8_t src_pixel = vreinterpret_u8_u32(vdup_n_u32(*p));
  528. extreme = (type == kDilate) ? vmax_u8(src_pixel, extreme)
  529. : vmin_u8(src_pixel, extreme);
  530. }
  531. *dptr = vget_lane_u32(vreinterpret_u32_u8(extreme), 0);
  532. dptr += dstStrideY;
  533. lp += srcStrideY;
  534. up += srcStrideY;
  535. }
  536. if (x >= radius) src += srcStrideX;
  537. if (x + radius < width - 1) upperSrc += srcStrideX;
  538. dst += dstStrideX;
  539. }
  540. }
  541. #else
  542. template<MorphType type, MorphDirection direction>
  543. static void morph(const SkPMColor* src, SkPMColor* dst,
  544. int radius, int width, int height, int srcStride, int dstStride) {
  545. const int srcStrideX = direction == MorphDirection::kX ? 1 : srcStride;
  546. const int dstStrideX = direction == MorphDirection::kX ? 1 : dstStride;
  547. const int srcStrideY = direction == MorphDirection::kX ? srcStride : 1;
  548. const int dstStrideY = direction == MorphDirection::kX ? dstStride : 1;
  549. radius = SkMin32(radius, width - 1);
  550. const SkPMColor* upperSrc = src + radius * srcStrideX;
  551. for (int x = 0; x < width; ++x) {
  552. const SkPMColor* lp = src;
  553. const SkPMColor* up = upperSrc;
  554. SkPMColor* dptr = dst;
  555. for (int y = 0; y < height; ++y) {
  556. // If we're maxing (dilate), start from 0; if minning (erode), start from 255.
  557. const int start = (type == kDilate) ? 0 : 255;
  558. int B = start, G = start, R = start, A = start;
  559. for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
  560. int b = SkGetPackedB32(*p),
  561. g = SkGetPackedG32(*p),
  562. r = SkGetPackedR32(*p),
  563. a = SkGetPackedA32(*p);
  564. if (type == kDilate) {
  565. B = SkTMax(b, B);
  566. G = SkTMax(g, G);
  567. R = SkTMax(r, R);
  568. A = SkTMax(a, A);
  569. } else {
  570. B = SkTMin(b, B);
  571. G = SkTMin(g, G);
  572. R = SkTMin(r, R);
  573. A = SkTMin(a, A);
  574. }
  575. }
  576. *dptr = SkPackARGB32(A, R, G, B);
  577. dptr += dstStrideY;
  578. lp += srcStrideY;
  579. up += srcStrideY;
  580. }
  581. if (x >= radius) { src += srcStrideX; }
  582. if (x + radius < width - 1) { upperSrc += srcStrideX; }
  583. dst += dstStrideX;
  584. }
  585. }
  586. #endif
  587. } // namespace
  588. sk_sp<SkSpecialImage> SkMorphologyImageFilter::onFilterImage(SkSpecialImage* source,
  589. const Context& ctx,
  590. SkIPoint* offset) const {
  591. SkIPoint inputOffset = SkIPoint::Make(0, 0);
  592. sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
  593. if (!input) {
  594. return nullptr;
  595. }
  596. SkIRect bounds;
  597. input = this->applyCropRectAndPad(this->mapContext(ctx), input.get(), &inputOffset, &bounds);
  598. if (!input) {
  599. return nullptr;
  600. }
  601. SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()),
  602. SkIntToScalar(this->radius().height()));
  603. ctx.ctm().mapVectors(&radius, 1);
  604. int width = SkScalarFloorToInt(radius.fX);
  605. int height = SkScalarFloorToInt(radius.fY);
  606. if (width < 0 || height < 0) {
  607. return nullptr;
  608. }
  609. SkIRect srcBounds = bounds;
  610. srcBounds.offset(-inputOffset);
  611. if (0 == width && 0 == height) {
  612. offset->fX = bounds.left();
  613. offset->fY = bounds.top();
  614. return input->makeSubset(srcBounds);
  615. }
  616. #if SK_SUPPORT_GPU
  617. if (source->isTextureBacked()) {
  618. auto context = source->getContext();
  619. // Ensure the input is in the destination color space. Typically applyCropRect will have
  620. // called pad_image to account for our dilation of bounds, so the result will already be
  621. // moved to the destination color space. If a filter DAG avoids that, then we use this
  622. // fall-back, which saves us from having to do the xform during the filter itself.
  623. input = ImageToColorSpace(input.get(), ctx.outputProperties());
  624. auto type = (kDilate_Op == this->op()) ? GrMorphologyEffect::Type::kDilate
  625. : GrMorphologyEffect::Type::kErode;
  626. sk_sp<SkSpecialImage> result(apply_morphology(context, input.get(), srcBounds, type,
  627. SkISize::Make(width, height),
  628. ctx.outputProperties()));
  629. if (result) {
  630. offset->fX = bounds.left();
  631. offset->fY = bounds.top();
  632. }
  633. return result;
  634. }
  635. #endif
  636. SkBitmap inputBM;
  637. if (!input->getROPixels(&inputBM)) {
  638. return nullptr;
  639. }
  640. if (inputBM.colorType() != kN32_SkColorType) {
  641. return nullptr;
  642. }
  643. SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(),
  644. inputBM.colorType(), inputBM.alphaType());
  645. SkBitmap dst;
  646. if (!dst.tryAllocPixels(info)) {
  647. return nullptr;
  648. }
  649. SkMorphologyImageFilter::Proc procX, procY;
  650. if (kDilate_Op == this->op()) {
  651. procX = &morph<kDilate, MorphDirection::kX>;
  652. procY = &morph<kDilate, MorphDirection::kY>;
  653. } else {
  654. procX = &morph<kErode, MorphDirection::kX>;
  655. procY = &morph<kErode, MorphDirection::kY>;
  656. }
  657. if (width > 0 && height > 0) {
  658. SkBitmap tmp;
  659. if (!tmp.tryAllocPixels(info)) {
  660. return nullptr;
  661. }
  662. call_proc_X(procX, inputBM, &tmp, width, srcBounds);
  663. SkIRect tmpBounds = SkIRect::MakeWH(srcBounds.width(), srcBounds.height());
  664. call_proc_Y(procY,
  665. tmp.getAddr32(tmpBounds.left(), tmpBounds.top()), tmp.rowBytesAsPixels(),
  666. &dst, height, tmpBounds);
  667. } else if (width > 0) {
  668. call_proc_X(procX, inputBM, &dst, width, srcBounds);
  669. } else if (height > 0) {
  670. call_proc_Y(procY,
  671. inputBM.getAddr32(srcBounds.left(), srcBounds.top()),
  672. inputBM.rowBytesAsPixels(),
  673. &dst, height, srcBounds);
  674. }
  675. offset->fX = bounds.left();
  676. offset->fY = bounds.top();
  677. return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()),
  678. dst, &source->props());
  679. }