1/* 2 * Copyright 2015 Google Inc. 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#ifndef SkMorphologyImageFilter_opts_DEFINED 9#define SkMorphologyImageFilter_opts_DEFINED 10 11#include "SkColor.h" 12 13namespace SK_OPTS_NS { 14 15enum MorphType { kDilate, kErode }; 16enum class MorphDirection { kX, kY }; 17 18#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 19template<MorphType type, MorphDirection direction> 20static void morph(const SkPMColor* src, SkPMColor* dst, 21 int radius, int width, int height, int srcStride, int dstStride) { 22 const int srcStrideX = direction == MorphDirection::kX ? 1 : srcStride; 23 const int dstStrideX = direction == MorphDirection::kX ? 1 : dstStride; 24 const int srcStrideY = direction == MorphDirection::kX ? srcStride : 1; 25 const int dstStrideY = direction == MorphDirection::kX ? dstStride : 1; 26 radius = SkMin32(radius, width - 1); 27 const SkPMColor* upperSrc = src + radius * srcStrideX; 28 for (int x = 0; x < width; ++x) { 29 const SkPMColor* lp = src; 30 const SkPMColor* up = upperSrc; 31 SkPMColor* dptr = dst; 32 for (int y = 0; y < height; ++y) { 33 __m128i extreme = (type == kDilate) ? _mm_setzero_si128() 34 : _mm_set1_epi32(0xFFFFFFFF); 35 for (const SkPMColor* p = lp; p <= up; p += srcStrideX) { 36 __m128i src_pixel = _mm_cvtsi32_si128(*p); 37 extreme = (type == kDilate) ? _mm_max_epu8(src_pixel, extreme) 38 : _mm_min_epu8(src_pixel, extreme); 39 } 40 *dptr = _mm_cvtsi128_si32(extreme); 41 dptr += dstStrideY; 42 lp += srcStrideY; 43 up += srcStrideY; 44 } 45 if (x >= radius) { src += srcStrideX; } 46 if (x + radius < width - 1) { upperSrc += srcStrideX; } 47 dst += dstStrideX; 48 } 49} 50 51#elif defined(SK_ARM_HAS_NEON) 52template<MorphType type, MorphDirection direction> 53static void morph(const SkPMColor* src, SkPMColor* dst, 54 int radius, int width, int height, int srcStride, int dstStride) { 55 const int srcStrideX = direction == MorphDirection::kX ? 1 : srcStride; 56 const int dstStrideX = direction == MorphDirection::kX ? 1 : dstStride; 57 const int srcStrideY = direction == MorphDirection::kX ? srcStride : 1; 58 const int dstStrideY = direction == MorphDirection::kX ? dstStride : 1; 59 radius = SkMin32(radius, width - 1); 60 const SkPMColor* upperSrc = src + radius * srcStrideX; 61 for (int x = 0; x < width; ++x) { 62 const SkPMColor* lp = src; 63 const SkPMColor* up = upperSrc; 64 SkPMColor* dptr = dst; 65 for (int y = 0; y < height; ++y) { 66 uint8x8_t extreme = vdup_n_u8(type == kDilate ? 0 : 255); 67 for (const SkPMColor* p = lp; p <= up; p += srcStrideX) { 68 uint8x8_t src_pixel = vreinterpret_u8_u32(vdup_n_u32(*p)); 69 extreme = (type == kDilate) ? vmax_u8(src_pixel, extreme) 70 : vmin_u8(src_pixel, extreme); 71 } 72 *dptr = vget_lane_u32(vreinterpret_u32_u8(extreme), 0); 73 dptr += dstStrideY; 74 lp += srcStrideY; 75 up += srcStrideY; 76 } 77 if (x >= radius) src += srcStrideX; 78 if (x + radius < width - 1) upperSrc += srcStrideX; 79 dst += dstStrideX; 80 } 81} 82 83#else 84template<MorphType type, MorphDirection direction> 85static void morph(const SkPMColor* src, SkPMColor* dst, 86 int radius, int width, int height, int srcStride, int dstStride) { 87 const int srcStrideX = direction == MorphDirection::kX ? 1 : srcStride; 88 const int dstStrideX = direction == MorphDirection::kX ? 1 : dstStride; 89 const int srcStrideY = direction == MorphDirection::kX ? srcStride : 1; 90 const int dstStrideY = direction == MorphDirection::kX ? dstStride : 1; 91 radius = SkMin32(radius, width - 1); 92 const SkPMColor* upperSrc = src + radius * srcStrideX; 93 for (int x = 0; x < width; ++x) { 94 const SkPMColor* lp = src; 95 const SkPMColor* up = upperSrc; 96 SkPMColor* dptr = dst; 97 for (int y = 0; y < height; ++y) { 98 // If we're maxing (dilate), start from 0; if minning (erode), start from 255. 99 const int start = (type == kDilate) ? 0 : 255; 100 int B = start, G = start, R = start, A = start; 101 for (const SkPMColor* p = lp; p <= up; p += srcStrideX) { 102 int b = SkGetPackedB32(*p), 103 g = SkGetPackedG32(*p), 104 r = SkGetPackedR32(*p), 105 a = SkGetPackedA32(*p); 106 if (type == kDilate) { 107 B = SkTMax(b, B); 108 G = SkTMax(g, G); 109 R = SkTMax(r, R); 110 A = SkTMax(a, A); 111 } else { 112 B = SkTMin(b, B); 113 G = SkTMin(g, G); 114 R = SkTMin(r, R); 115 A = SkTMin(a, A); 116 } 117 } 118 *dptr = SkPackARGB32(A, R, G, B); 119 dptr += dstStrideY; 120 lp += srcStrideY; 121 up += srcStrideY; 122 } 123 if (x >= radius) { src += srcStrideX; } 124 if (x + radius < width - 1) { upperSrc += srcStrideX; } 125 dst += dstStrideX; 126 } 127} 128 129#endif 130 131static auto dilate_x = &morph<kDilate, MorphDirection::kX>, 132 dilate_y = &morph<kDilate, MorphDirection::kY>, 133 erode_x = &morph<kErode, MorphDirection::kX>, 134 erode_y = &morph<kErode, MorphDirection::kY>; 135 136} // namespace SK_OPTS_NS 137 138#endif//SkMorphologyImageFilter_opts_DEFINED 139 140