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
13 namespace SK_OPTS_NS {
14
15 enum MorphType { kDilate, kErode };
16 enum class MorphDirection { kX, kY };
17
18 #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
19 template<MorphType type, MorphDirection direction>
morph(const SkPMColor * src,SkPMColor * dst,int radius,int width,int height,int srcStride,int dstStride)20 static 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)
52 template<MorphType type, MorphDirection direction>
morph(const SkPMColor * src,SkPMColor * dst,int radius,int width,int height,int srcStride,int dstStride)53 static 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
84 template<MorphType type, MorphDirection direction>
morph(const SkPMColor * src,SkPMColor * dst,int radius,int width,int height,int srcStride,int dstStride)85 static 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
131 static 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