summaryrefslogtreecommitdiff
path: root/src/modules/evas/engines/software_generic/filters
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2017-01-17 21:18:46 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2017-04-14 11:26:43 +0900
commita8d283567a21b2716cdc0b888a49bda46abfb95c (patch)
tree57e86ec6081fb9f4e08771786ce82da08292eaf0 /src/modules/evas/engines/software_generic/filters
parent46542ea74884675fcdae77a05b88e3d1cfa62e86 (diff)
evas filters: Move blur to software generic (8/8)
This completes the series of refactoring patches, where only the filter implementation is moved to the engine rather than inside evas itself.
Diffstat (limited to 'src/modules/evas/engines/software_generic/filters')
-rw-r--r--src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_.c248
-rw-r--r--src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_i386.c25
-rw-r--r--src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_neon.c25
-rw-r--r--src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_sse3.c25
-rw-r--r--src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_.c296
-rw-r--r--src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_i386.c25
-rw-r--r--src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_neon.c25
-rw-r--r--src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_sse3.c25
-rw-r--r--src/modules/evas/engines/software_generic/filters/blur/blur_gaussian_alpha_.c84
-rw-r--r--src/modules/evas/engines/software_generic/filters/blur/blur_gaussian_rgba_.c103
-rw-r--r--src/modules/evas/engines/software_generic/filters/evas_engine_filter.h1
-rw-r--r--src/modules/evas/engines/software_generic/filters/evas_filter_blur.c429
12 files changed, 1311 insertions, 0 deletions
diff --git a/src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_.c b/src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_.c
new file mode 100644
index 0000000000..ba7ceeb371
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_.c
@@ -0,0 +1,248 @@
1/* @file blur_box_alpha_.c
2 * Defines the following functions:
3 * _box_blur_alpha_horiz_step
4 * _box_blur_alpha_vert_step
5 */
6
7#include "evas_filter_private.h"
8
9static inline void
10_box_blur_alpha_horiz_step(const DATA8* restrict const srcdata,
11 DATA8* restrict const dstdata,
12 const int* restrict const radii,
13 const int len,
14 const int loops)
15{
16 const DATA8* restrict src;
17 DATA8* restrict dst;
18 DATA8* restrict span1;
19 DATA8* restrict span2;
20
21#if DIV_USING_BITSHIFT
22 int pow2_shifts[6] = {0};
23 int numerators[6] = {0};
24 for (int run = 0; radii[run]; run++)
25 {
26 const int div = radii[run] * 2 + 1;
27 pow2_shifts[run] = evas_filter_smallest_pow2_larger_than(div << 10);
28 numerators[run] = (1 << pow2_shifts[run]) / (div);
29 }
30#endif
31
32 span1 = alloca(len);
33 span2 = alloca(len);
34 memset(span1, 0, len);
35 memset(span2, 0, len);
36
37 // For each line, apply as many blurs as requested
38 for (int l = 0; l < loops; l++)
39 {
40 int run;
41
42 // New line: reset source & destination pointers
43 src = srcdata + len * l;
44 if (!radii[1]) // Only one run
45 dst = dstdata + len * l;
46 else
47 dst = span1;
48
49 // Apply blur with current radius
50 for (run = 0; radii[run]; run++)
51 {
52 const int radius = radii[run];
53 const int left = MIN(radius, len);
54
55#if DIV_USING_BITSHIFT
56 const int pow2 = pow2_shifts[run];
57 const int numerator = numerators[run];
58#else
59 const int divider = 2 * radius + 1;
60#endif
61
62 const DATA8* restrict sl = src;
63 const DATA8* restrict sr = src;
64 const DATA8* restrict sre = src + len;
65 const DATA8* restrict sle = src + len - radius;
66 DATA8* restrict d = dst;
67 int acc = 0, count = 0;
68
69 // Read-ahead & accumulate
70 for (int x = left; x > 0; x--)
71 {
72 acc += *sr++;
73 count++;
74 }
75
76 // Left edge
77 for (int x = left; x > 0; x--)
78 {
79 if (sr < sre)
80 {
81 acc += *sr++;
82 count++;
83 }
84
85 *d++ = acc / count;
86 }
87
88 // Middle part, normal blur
89 while (sr < sre)
90 {
91 acc += *sr++;
92 *d++ = DIVIDE(acc);
93 acc -= *sl++;
94 }
95
96 // Right edge
97 count = 2 * radius + 1;
98 while (sl < sle)
99 {
100 *d++ = acc / (--count);
101 acc -= *sl++;
102 }
103
104 // More runs to go: swap spans
105 if (radii[run + 1])
106 {
107 src = dst;
108 if (radii[run + 2])
109 {
110 // Two more runs: swap
111 DATA8* swap = span1;
112 span1 = span2;
113 span2 = swap;
114 dst = span1;
115 }
116 else
117 {
118 // Last run: write directly to dstdata
119 dst = dstdata + len * l;
120 }
121 }
122 }
123 }
124}
125
126// ATTENTION: Make sure the below code's inner loop is the SAME as above.
127
128static inline void
129_box_blur_alpha_vert_step(const DATA8* restrict const srcdata,
130 DATA8* restrict const dstdata,
131 const int* restrict const radii,
132 const int len,
133 const int loops)
134{
135 /* Note: This function tries to optimize cache hits by working on
136 * contiguous horizontal spans.
137 */
138
139 const int step = loops;
140 DATA8* restrict src;
141 DATA8* restrict dst;
142 DATA8* restrict span1;
143 DATA8* restrict span2;
144
145#if DIV_USING_BITSHIFT
146 int pow2_shifts[6] = {0};
147 int numerators[6] = {0};
148 for (int run = 0; radii[run]; run++)
149 {
150 const int div = radii[run] * 2 + 1;
151 pow2_shifts[run] = evas_filter_smallest_pow2_larger_than(div << 10);
152 numerators[run] = (1 << pow2_shifts[run]) / (div);
153 }
154#endif
155
156 span1 = alloca(len);
157 span2 = alloca(len);
158
159 // For each line, apply as many blurs as requested
160 for (int l = 0; l < loops; l++)
161 {
162 int run;
163
164 // Rotate input into work span
165 const DATA8* srcptr = srcdata + l;
166 DATA8* s = span1;
167 for (int k = len; k; --k)
168 {
169 *s++ = *srcptr;
170 srcptr += step;
171 }
172
173 src = span1;
174 dst = span2;
175
176 // Apply blur with current radius
177 for (run = 0; radii[run]; run++)
178 {
179 const int radius = radii[run];
180 const int left = MIN(radius, len);
181
182#if DIV_USING_BITSHIFT
183 const int pow2 = pow2_shifts[run];
184 const int numerator = numerators[run];
185#else
186 const int divider = 2 * radius + 1;
187#endif
188
189 const DATA8* restrict sl = src;
190 const DATA8* restrict sr = src;
191 const DATA8* restrict sre = src + len;
192 const DATA8* restrict sle = src + len - radius;
193 DATA8* restrict d = dst;
194 int acc = 0, count = 0;
195
196 // Read-ahead & accumulate
197 for (int x = left; x > 0; x--)
198 {
199 acc += *sr++;
200 count++;
201 }
202
203 // Left edge
204 for (int x = left; x > 0; x--)
205 {
206 if (sr < sre)
207 {
208 acc += *sr++;
209 count++;
210 }
211
212 *d++ = acc / count;
213 }
214
215 // Middle part, normal blur
216 while (sr < sre)
217 {
218 acc += *sr++;
219 *d++ = DIVIDE(acc);
220 acc -= *sl++;
221 }
222
223 // Right edge
224 count = 2 * radius + 1;
225 while (sl < sle)
226 {
227 *d++ = acc / (--count);
228 acc -= *sl++;
229 }
230
231 // More runs to go: swap spans
232 if (radii[run + 1])
233 {
234 DATA8* swap = src;
235 src = dst;
236 dst = swap;
237 }
238 }
239
240 // Last run: rotate & copy back to destination
241 DATA8* restrict dstptr = dstdata + l;
242 for (int k = len; k; --k)
243 {
244 *dstptr = *dst++;
245 dstptr += step;
246 }
247 }
248}
diff --git a/src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_i386.c b/src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_i386.c
new file mode 100644
index 0000000000..16644315b4
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_i386.c
@@ -0,0 +1,25 @@
1#ifdef BUILD_MMX
2
3static inline void
4_box_blur_alpha_horiz_step_mmx(const DATA8* restrict const srcdata,
5 DATA8* restrict const dstdata,
6 const int* restrict const radii,
7 const int len,
8 const int loops)
9{
10 // TODO: implement optimized code here and remove the following line:
11 _box_blur_alpha_horiz_step(srcdata, dstdata, radii, len, loops);
12}
13
14static inline void
15_box_blur_alpha_vert_step_mmx(const DATA8* restrict const srcdata,
16 DATA8* restrict const dstdata,
17 const int* restrict const radii,
18 const int len,
19 const int loops)
20{
21 // TODO: implement optimized code here and remove the following line:
22 _box_blur_alpha_vert_step(srcdata, dstdata, radii, len, loops);
23}
24
25#endif
diff --git a/src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_neon.c b/src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_neon.c
new file mode 100644
index 0000000000..b8d95244e5
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_neon.c
@@ -0,0 +1,25 @@
1#ifdef BUILD_NEON
2
3static inline void
4_box_blur_alpha_horiz_step_neon(const DATA8* restrict const srcdata,
5 DATA8* restrict const dstdata,
6 const int* restrict const radii,
7 const int len,
8 const int loops)
9{
10 // TODO: implement optimized code here and remove the following line:
11 _box_blur_alpha_horiz_step(srcdata, dstdata, radii, len, loops);
12}
13
14static inline void
15_box_blur_alpha_vert_step_neon(const DATA8* restrict const srcdata,
16 DATA8* restrict const dstdata,
17 const int* restrict const radii,
18 const int len,
19 const int loops)
20{
21 // TODO: implement optimized code here and remove the following line:
22 _box_blur_alpha_vert_step(srcdata, dstdata, radii, len, loops);
23}
24
25#endif
diff --git a/src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_sse3.c b/src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_sse3.c
new file mode 100644
index 0000000000..17a19f12c0
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/blur/blur_box_alpha_sse3.c
@@ -0,0 +1,25 @@
1#ifdef BUILD_SSE3
2
3static inline void
4_box_blur_alpha_horiz_step_sse3(const DATA8* restrict const srcdata,
5 DATA8* restrict const dstdata,
6 const int* restrict const radii,
7 const int len,
8 const int loops)
9{
10 // TODO: implement optimized code here and remove the following line:
11 _box_blur_alpha_horiz_step(srcdata, dstdata, radii, len, loops);
12}
13
14static inline void
15_box_blur_alpha_vert_step_sse3(const DATA8* restrict const srcdata,
16 DATA8* restrict const dstdata,
17 const int* restrict const radii,
18 const int len,
19 const int loops)
20{
21 // TODO: implement optimized code here and remove the following line:
22 _box_blur_alpha_vert_step(srcdata, dstdata, radii, len, loops);
23}
24
25#endif
diff --git a/src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_.c b/src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_.c
new file mode 100644
index 0000000000..8d90b4df2e
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_.c
@@ -0,0 +1,296 @@
1/* @file blur_box_rgba_.c
2 * Should define the functions:
3 * - _box_blur_horiz_rgba_step
4 * - _box_blur_vert_rgba_step
5 */
6
7#include "evas_filter_private.h"
8
9static inline void
10_box_blur_rgba_horiz_step(const DATA32* restrict const srcdata,
11 DATA32* restrict const dstdata,
12 const int* restrict const radii,
13 const int len,
14 const int loops)
15{
16 const DATA32* restrict src;
17 DATA32* restrict dst;
18 DATA32* restrict span1;
19 DATA32* restrict span2;
20
21#if DIV_USING_BITSHIFT
22 int pow2_shifts[6] = {0};
23 int numerators[6] = {0};
24 for (int run = 0; radii[run]; run++)
25 {
26 const int div = radii[run] * 2 + 1;
27 pow2_shifts[run] = evas_filter_smallest_pow2_larger_than(div << 10);
28 numerators[run] = (1 << pow2_shifts[run]) / (div);
29 }
30#endif
31
32 span1 = alloca(len * sizeof(DATA32));
33 span2 = alloca(len * sizeof(DATA32));
34 memset(span1, 0, len * sizeof(DATA32));
35 memset(span2, 0, len * sizeof(DATA32));
36
37 // For each line, apply as many blurs as requested
38 for (int l = 0; l < loops; l++)
39 {
40 int run;
41
42 // New line: reset source & destination pointers
43 src = srcdata + len * l;
44 if (!radii[1]) // Only one run
45 dst = dstdata + len * l;
46 else
47 dst = span1;
48
49 // Apply blur with current radius
50 for (run = 0; radii[run]; run++)
51 {
52 const int radius = radii[run];
53 const int left = MIN(radius, len);
54
55#if DIV_USING_BITSHIFT
56 const int pow2 = pow2_shifts[run];
57 const int numerator = numerators[run];
58#else
59 const int divider = 2 * radius + 1;
60#endif
61
62 const DATA8* restrict sl = (DATA8 *) src;
63 const DATA8* restrict sr = (DATA8 *) src;
64 const DATA8* restrict sre = (DATA8 *) (src + len);
65 const DATA8* restrict sle = (DATA8 *) (src + len - radius);
66 DATA8* restrict d = (DATA8 *) dst;
67 int acc[4] = {0};
68 int count = 0;
69
70 // Read-ahead
71 for (int x = left; x > 0; x--)
72 {
73 for (int k = 0; k < 4; k++)
74 acc[k] += sr[k];
75 sr += sizeof(DATA32);
76 count++;
77 }
78
79 // Left
80 for (int x = left; x > 0; x--)
81 {
82 if (sr < sre)
83 {
84 for (int k = 0; k < 4; k++)
85 acc[k] += sr[k];
86 sr += sizeof(DATA32);
87 count++;
88 }
89
90 d[ALPHA] = acc[ALPHA] / count;
91 d[RED] = acc[RED] / count;
92 d[GREEN] = acc[GREEN] / count;
93 d[BLUE] = acc[BLUE] / count;
94 d += sizeof(DATA32);
95 }
96
97 // Main part
98 for (; sr < sre; sr += sizeof(DATA32), sl += sizeof(DATA32))
99 {
100 for (int k = 0; k < 4; k++)
101 acc[k] += sr[k];
102
103 d[ALPHA] = DIVIDE(acc[ALPHA]);
104 d[RED] = DIVIDE(acc[RED]);
105 d[GREEN] = DIVIDE(acc[GREEN]);
106 d[BLUE] = DIVIDE(acc[BLUE]);
107 d += sizeof(DATA32);
108
109 for (int k = 0; k < 4; k++)
110 acc[k] -= sl[k];
111 }
112
113 // Right part
114 count = 2 * radius + 1;
115 for (; sl < sle; sl += sizeof(DATA32))
116 {
117 const int divider = --count;
118 d[ALPHA] = acc[ALPHA] / divider;
119 d[RED] = acc[RED] / divider;
120 d[GREEN] = acc[GREEN] / divider;
121 d[BLUE] = acc[BLUE] / divider;
122 d += sizeof(DATA32);
123
124 for (int k = 0; k < 4; k++)
125 acc[k] -= sl[k];
126 }
127
128 // More runs to go: swap spans
129 if (radii[run + 1])
130 {
131 src = dst;
132 if (radii[run + 2])
133 {
134 // Two more runs: swap
135 DATA32* swap = span1;
136 span1 = span2;
137 span2 = swap;
138 dst = span1;
139 }
140 else
141 {
142 // Last run: write directly to dstdata
143 dst = dstdata + len * l;
144 }
145 }
146 }
147 }
148}
149
150static inline void
151_box_blur_rgba_vert_step(const DATA32* restrict const srcdata,
152 DATA32* restrict const dstdata,
153 const int* restrict const radii,
154 const int len,
155 const int loops)
156{
157 /* Note: This function tries to optimize cache hits by working on
158 * contiguous horizontal spans.
159 */
160
161 const int step = loops;
162 DATA32* restrict src;
163 DATA32* restrict dst;
164 DATA32* restrict span1;
165 DATA32* restrict span2;
166
167#if DIV_USING_BITSHIFT
168 int pow2_shifts[6] = {0};
169 int numerators[6] = {0};
170 for (int run = 0; radii[run]; run++)
171 {
172 const int div = radii[run] * 2 + 1;
173 pow2_shifts[run] = evas_filter_smallest_pow2_larger_than(div << 10);
174 numerators[run] = (1 << pow2_shifts[run]) / (div);
175 }
176#endif
177
178 span1 = alloca(len * sizeof(DATA32));
179 span2 = alloca(len * sizeof(DATA32));
180 memset(span1, 0, len * sizeof(DATA32));
181 memset(span2, 0, len * sizeof(DATA32));
182
183 // For each line, apply as many blurs as requested
184 for (int l = 0; l < loops; l++)
185 {
186 int run;
187
188 // Rotate input into work span
189 const DATA32* srcptr = srcdata + l;
190 DATA32* s = span1;
191 for (int k = len; k; --k)
192 {
193 *s++ = *srcptr;
194 srcptr += step;
195 }
196
197 src = span1;
198 dst = span2;
199
200 // Apply blur with current radius
201 for (run = 0; radii[run]; run++)
202 {
203 const int radius = radii[run];
204 const int left = MIN(radius, len);
205
206#if DIV_USING_BITSHIFT
207 const int pow2 = pow2_shifts[run];
208 const int numerator = numerators[run];
209#else
210 const int divider = 2 * radius + 1;
211#endif
212
213 const DATA8* restrict sl = (DATA8 *) src;
214 const DATA8* restrict sr = (DATA8 *) src;
215 const DATA8* restrict sre = (DATA8 *) (src + len);
216 const DATA8* restrict sle = (DATA8 *) (src + len - radius);
217 DATA8* restrict d = (DATA8 *) dst;
218 int acc[4] = {0};
219 int count = 0;
220
221 // Read-ahead
222 for (int x = left; x > 0; x--)
223 {
224 for (int k = 0; k < 4; k++)
225 acc[k] += sr[k];
226 sr += sizeof(DATA32);
227 count++;
228 }
229
230 // Left
231 for (int x = left; x > 0; x--)
232 {
233 if (sr < sre)
234 {
235 for (int k = 0; k < 4; k++)
236 acc[k] += sr[k];
237 sr += sizeof(DATA32);
238 count++;
239 }
240
241 d[ALPHA] = acc[ALPHA] / count;
242 d[RED] = acc[RED] / count;
243 d[GREEN] = acc[GREEN] / count;
244 d[BLUE] = acc[BLUE] / count;
245 d += sizeof(DATA32);
246 }
247
248 // Main part
249 for (; sr < sre; sr += sizeof(DATA32), sl += sizeof(DATA32))
250 {
251 for (int k = 0; k < 4; k++)
252 acc[k] += sr[k];
253
254 d[ALPHA] = DIVIDE(acc[ALPHA]);
255 d[RED] = DIVIDE(acc[RED]);
256 d[GREEN] = DIVIDE(acc[GREEN]);
257 d[BLUE] = DIVIDE(acc[BLUE]);
258 d += sizeof(DATA32);
259
260 for (int k = 0; k < 4; k++)
261 acc[k] -= sl[k];
262 }
263
264 // Right part
265 count = 2 * radius + 1;
266 for (; sl < sle; sl += sizeof(DATA32))
267 {
268 const int divider = --count;
269 d[ALPHA] = acc[ALPHA] / divider;
270 d[RED] = acc[RED] / divider;
271 d[GREEN] = acc[GREEN] / divider;
272 d[BLUE] = acc[BLUE] / divider;
273 d += sizeof(DATA32);
274
275 for (int k = 0; k < 4; k++)
276 acc[k] -= sl[k];
277 }
278
279 // More runs to go: swap spans
280 if (radii[run + 1])
281 {
282 DATA32* swap = src;
283 src = dst;
284 dst = swap;
285 }
286 }
287
288 // Last run: rotate & copy back to destination
289 DATA32* restrict dstptr = dstdata + l;
290 for (int k = len; k; --k)
291 {
292 *dstptr = *dst++;
293 dstptr += step;
294 }
295 }
296}
diff --git a/src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_i386.c b/src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_i386.c
new file mode 100644
index 0000000000..7f0f76b550
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_i386.c
@@ -0,0 +1,25 @@
1#ifdef BUILD_MMX
2
3static inline void
4_box_blur_rgba_horiz_step_mmx(const DATA32* restrict const srcdata,
5 DATA32* restrict const dstdata,
6 const int* restrict const radii,
7 const int len,
8 const int loops)
9{
10 // TODO: implement optimized code here and remove the following line:
11 _box_blur_rgba_horiz_step(srcdata, dstdata, radii, len, loops);
12}
13
14static inline void
15_box_blur_rgba_vert_step_mmx(const DATA32* restrict const srcdata,
16 DATA32* restrict const dstdata,
17 const int* restrict const radii,
18 const int len,
19 const int loops)
20{
21 // TODO: implement optimized code here and remove the following line:
22 _box_blur_rgba_vert_step(srcdata, dstdata, radii, len, loops);
23}
24
25#endif
diff --git a/src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_neon.c b/src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_neon.c
new file mode 100644
index 0000000000..9206df539b
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_neon.c
@@ -0,0 +1,25 @@
1#ifdef BUILD_NEON
2
3static inline void
4_box_blur_rgba_horiz_step_neon(const DATA32* restrict const srcdata,
5 DATA32* restrict const dstdata,
6 const int* restrict const radii,
7 const int len,
8 const int loops)
9{
10 // TODO: implement optimized code here and remove the following line:
11 _box_blur_rgba_horiz_step(srcdata, dstdata, radii, len, loops);
12}
13
14static inline void
15_box_blur_rgba_vert_step_neon(const DATA32* restrict const srcdata,
16 DATA32* restrict const dstdata,
17 const int* restrict const radii,
18 const int len,
19 const int loops)
20{
21 // TODO: implement optimized code here and remove the following line:
22 _box_blur_rgba_vert_step(srcdata, dstdata, radii, len, loops);
23}
24
25#endif
diff --git a/src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_sse3.c b/src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_sse3.c
new file mode 100644
index 0000000000..03ae282460
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/blur/blur_box_rgba_sse3.c
@@ -0,0 +1,25 @@
1#ifdef BUILD_SSE3
2
3static inline void
4_box_blur_rgba_horiz_step_sse3(const DATA32* restrict const srcdata,
5 DATA32* restrict const dstdata,
6 const int* restrict const radii,
7 const int len,
8 const int loops)
9{
10 // TODO: implement optimized code here and remove the following line:
11 _box_blur_rgba_horiz_step(srcdata, dstdata, radii, len, loops);
12}
13
14static inline void
15_box_blur_rgba_vert_step_sse3(const DATA32* restrict const srcdata,
16 DATA32* restrict const dstdata,
17 const int* restrict const radii,
18 const int len,
19 const int loops)
20{
21 // TODO: implement optimized code here and remove the following line:
22 _box_blur_rgba_vert_step(srcdata, dstdata, radii, len, loops);
23}
24
25#endif
diff --git a/src/modules/evas/engines/software_generic/filters/blur/blur_gaussian_alpha_.c b/src/modules/evas/engines/software_generic/filters/blur/blur_gaussian_alpha_.c
new file mode 100644
index 0000000000..5a72fa5f77
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/blur/blur_gaussian_alpha_.c
@@ -0,0 +1,84 @@
1/* @file blur_gaussian_alpha_.c
2 * Should define the functions:
3 * - _gaussian_blur_horiz_alpha_step
4 * - _gaussian_blur_vert_alpha_step
5 */
6
7/* Datatypes and MIN macro */
8#include "evas_filter_private.h"
9
10#if !defined (FUNCTION_NAME) || !defined (STEP)
11# error Must define FUNCTION_NAME and STEP
12#endif
13
14static inline void
15FUNCTION_NAME(const DATA8* restrict srcdata, DATA8* restrict dstdata,
16 const int radius, const int len,
17 const int loops, const int loopstep,
18 const int* restrict weights, const int pow2_divider)
19{
20 int i, j, k, acc, divider;
21 const int diameter = 2 * radius + 1;
22 const int left = MIN(radius, len);
23 const int right = MIN(radius, (len - radius));
24 const DATA8* restrict s;
25 const DATA8* restrict src;
26 DATA8* restrict dst;
27
28 for (i = loops; i; --i)
29 {
30 src = srcdata;
31 dst = dstdata;
32
33 // left
34 for (k = 0; k < left; k++, dst += STEP)
35 {
36 acc = 0;
37 divider = 0;
38 s = src;
39 for (j = 0; j <= k + radius; j++, s += STEP)
40 {
41 acc += (*s) * weights[j + radius - k];
42 divider += weights[j + radius - k];
43 }
44 if (!divider) goto error;
45 *dst = acc / divider;
46 }
47
48 // middle
49 for (k = radius; k < (len - radius); k++, src += STEP, dst += STEP)
50 {
51 acc = 0;
52 s = src;
53 for (j = 0; j < diameter; j++, s += STEP)
54 acc += (*s) * weights[j];
55 *dst = acc >> pow2_divider;
56 }
57
58 // right
59 for (k = 0; k < right; k++, dst += STEP, src += STEP)
60 {
61 acc = 0;
62 divider = 0;
63 s = src;
64 for (j = 0; j < 2 * radius - k; j++, s += STEP)
65 {
66 acc += (*s) * weights[j];
67 divider += weights[j];
68 }
69 if (!divider) goto error;
70 *dst = acc / divider;
71 }
72
73 dstdata += loopstep;
74 srcdata += loopstep;
75 }
76
77 return;
78
79error:
80 CRI("Avoided division by 0.");
81}
82
83#undef FUNCTION_NAME
84#undef STEP
diff --git a/src/modules/evas/engines/software_generic/filters/blur/blur_gaussian_rgba_.c b/src/modules/evas/engines/software_generic/filters/blur/blur_gaussian_rgba_.c
new file mode 100644
index 0000000000..3a862fea8b
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/blur/blur_gaussian_rgba_.c
@@ -0,0 +1,103 @@
1/* @file blur_gaussian_rgba_.c
2 * Should define the functions:
3 * - _gaussian_blur_horiz_rgba_step
4 * - _gaussian_blur_vert_rgba_step
5 */
6
7#include "evas_filter_private.h"
8
9#if !defined (FUNCTION_NAME) || !defined (STEP)
10# error Must define FUNCTION_NAME and STEP
11#endif
12
13static inline void
14FUNCTION_NAME(const DATA32* restrict srcdata, DATA32* restrict dstdata,
15 const int radius, const int len,
16 const int loops, const int loopstep,
17 const int* restrict weights, const int pow2_divider)
18{
19 const int diameter = 2 * radius + 1;
20 const int left = MIN(radius, len);
21 const int right = MIN(radius, (len - radius));
22 const DATA32* restrict src;
23 DATA32* restrict dst;
24 int i, j, k;
25
26 for (i = loops; i; --i)
27 {
28 src = srcdata;
29 dst = dstdata;
30
31 // left
32 for (k = 0; k < left; k++, dst += STEP)
33 {
34 int acc[4] = {0};
35 int divider = 0;
36 const DATA32* restrict s = src;
37 for (j = 0; j <= k + radius; j++, s += STEP)
38 {
39 const int weightidx = j + radius - k;
40 acc[ALPHA] += A_VAL(s) * weights[weightidx];
41 acc[RED] += R_VAL(s) * weights[weightidx];
42 acc[GREEN] += G_VAL(s) * weights[weightidx];
43 acc[BLUE] += B_VAL(s) * weights[weightidx];
44 divider += weights[weightidx];
45 }
46 if (!divider) goto error;
47 A_VAL(dst) = acc[ALPHA] / divider;
48 R_VAL(dst) = acc[RED] / divider;
49 G_VAL(dst) = acc[GREEN] / divider;
50 B_VAL(dst) = acc[BLUE] / divider;
51 }
52
53 // middle
54 for (k = len - (2 * radius); k > 0; k--, src += STEP, dst += STEP)
55 {
56 int acc[4] = {0};
57 const DATA32* restrict s = src;
58 for (j = 0; j < diameter; j++, s += STEP)
59 {
60 acc[ALPHA] += A_VAL(s) * weights[j];
61 acc[RED] += R_VAL(s) * weights[j];
62 acc[GREEN] += G_VAL(s) * weights[j];
63 acc[BLUE] += B_VAL(s) * weights[j];
64 }
65 A_VAL(dst) = acc[ALPHA] >> pow2_divider;
66 R_VAL(dst) = acc[RED] >> pow2_divider;
67 G_VAL(dst) = acc[GREEN] >> pow2_divider;
68 B_VAL(dst) = acc[BLUE] >> pow2_divider;
69 }
70
71 // right
72 for (k = 0; k < right; k++, dst += STEP, src += STEP)
73 {
74 int acc[4] = {0};
75 int divider = 0;
76 const DATA32* restrict s = src;
77 for (j = 0; j < 2 * radius - k; j++, s += STEP)
78 {
79 acc[ALPHA] += A_VAL(s) * weights[j];
80 acc[RED] += R_VAL(s) * weights[j];
81 acc[GREEN] += G_VAL(s) * weights[j];
82 acc[BLUE] += B_VAL(s) * weights[j];
83 divider += weights[j];
84 }
85 if (!divider) goto error;
86 A_VAL(dst) = acc[ALPHA] / divider;
87 R_VAL(dst) = acc[RED] / divider;
88 G_VAL(dst) = acc[GREEN] / divider;
89 B_VAL(dst) = acc[BLUE] / divider;
90 }
91
92 dstdata += loopstep;
93 srcdata += loopstep;
94 }
95
96 return;
97
98error:
99 CRI("Avoided division by 0.");
100}
101
102#undef FUNCTION_NAME
103#undef STEP
diff --git a/src/modules/evas/engines/software_generic/filters/evas_engine_filter.h b/src/modules/evas/engines/software_generic/filters/evas_engine_filter.h
index 2ae3618d4f..9d67574e56 100644
--- a/src/modules/evas/engines/software_generic/filters/evas_engine_filter.h
+++ b/src/modules/evas/engines/software_generic/filters/evas_engine_filter.h
@@ -5,6 +5,7 @@
5#include "draw.h" 5#include "draw.h"
6 6
7Evas_Filter_Apply_Func eng_filter_blend_func_get(Evas_Filter_Command *cmd); 7Evas_Filter_Apply_Func eng_filter_blend_func_get(Evas_Filter_Command *cmd);
8Evas_Filter_Apply_Func eng_filter_blur_func_get(Evas_Filter_Command *cmd);
8Evas_Filter_Apply_Func eng_filter_bump_func_get(Evas_Filter_Command *cmd); 9Evas_Filter_Apply_Func eng_filter_bump_func_get(Evas_Filter_Command *cmd);
9Evas_Filter_Apply_Func eng_filter_curve_func_get(Evas_Filter_Command *cmd); 10Evas_Filter_Apply_Func eng_filter_curve_func_get(Evas_Filter_Command *cmd);
10Evas_Filter_Apply_Func eng_filter_displace_func_get(Evas_Filter_Command *cmd); 11Evas_Filter_Apply_Func eng_filter_displace_func_get(Evas_Filter_Command *cmd);
diff --git a/src/modules/evas/engines/software_generic/filters/evas_filter_blur.c b/src/modules/evas/engines/software_generic/filters/evas_filter_blur.c
new file mode 100644
index 0000000000..1dd59fde7f
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/evas_filter_blur.c
@@ -0,0 +1,429 @@
1#include "evas_filter_private.h"
2
3#include <math.h>
4#include <time.h>
5
6// FIXME: Add proper stride support
7
8static int
9_box_blur_auto_radius(int *radii, int r)
10{
11 if (r <= 2)
12 {
13 radii[0] = r;
14 radii[1] = 0;
15 WRN("Radius is too small for auto box blur: %d", r);
16 return 1;
17 }
18 else if (r <= 6)
19 {
20 radii[0] = r / 2;
21 radii[1] = r - radii[0] - 1;
22 radii[2] = 0;
23 XDBG("Using auto radius for %d: %d %d", r, radii[0], radii[1]);
24 return 2;
25 }
26 else
27 {
28 radii[0] = (r + 3) / 3;
29 radii[1] = (r + 2) / 3;
30 radii[2] = r - radii[0] - radii[1];
31 radii[3] = 0;
32 XDBG("Using auto radius for %d: %d %d %d", r, radii[0], radii[1], radii[2]);
33 return 3;
34 }
35}
36
37#include "./blur/blur_box_rgba_.c"
38#ifdef BUILD_MMX
39#include "./blur/blur_box_rgba_i386.c"
40#endif
41#ifdef BUILD_SSE3
42#include "./blur/blur_box_rgba_sse3.c"
43#endif
44#ifdef BUILD_NEON
45#include "./blur/blur_box_rgba_neon.c"
46#endif
47
48static void
49_box_blur_horiz_rgba(uint32_t *src, uint32_t *dst, int* radii, int w, int h)
50{
51 DEBUG_TIME_BEGIN();
52
53#ifdef BUILD_SSE3
54 if (eina_cpu_features_get() & EINA_CPU_SSE3)
55 {
56 _box_blur_rgba_horiz_step_sse3(src, dst, radii, w, h);
57 goto end;
58 }
59#endif
60#ifdef BUILD_MMX
61 if (eina_cpu_features_get() & EINA_CPU_MMX)
62 {
63 _box_blur_rgba_horiz_step_mmx(src, dst, radii, w, h);
64 goto end;
65 }
66#endif
67#ifdef BUILD_NEON
68 if (eina_cpu_features_get() & EINA_CPU_NEON)
69 {
70 _box_blur_rgba_horiz_step_neon(src, dst, radii, w, h);
71 goto end;
72 }
73#endif
74 _box_blur_rgba_horiz_step(src, dst, radii, w, h);
75
76end:
77 DEBUG_TIME_END();
78}
79
80static void
81_box_blur_vert_rgba(uint32_t *src, uint32_t *dst, int* radii, int w, int h)
82{
83 DEBUG_TIME_BEGIN();
84
85#ifdef BUILD_SSE3
86 if (eina_cpu_features_get() & EINA_CPU_SSE3)
87 {
88 _box_blur_rgba_vert_step_sse3(src, dst, radii, h, w);
89 goto end;
90 }
91#endif
92#ifdef BUILD_MMX
93 if (eina_cpu_features_get() & EINA_CPU_MMX)
94 {
95 _box_blur_rgba_vert_step_mmx(src, dst, radii, h, w);
96 goto end;
97 }
98#endif
99#ifdef BUILD_NEON
100 if (eina_cpu_features_get() & EINA_CPU_NEON)
101 {
102 _box_blur_rgba_vert_step_neon(src, dst, radii, h, w);
103 goto end;
104 }
105#endif
106 _box_blur_rgba_vert_step(src, dst, radii, h, w);
107
108end:
109 DEBUG_TIME_END();
110}
111
112#include "./blur/blur_box_alpha_.c"
113#ifdef BUILD_MMX
114#include "./blur/blur_box_alpha_i386.c"
115#endif
116#ifdef BUILD_SSE3
117#include "./blur/blur_box_alpha_sse3.c"
118#endif
119#ifdef BUILD_NEON
120#include "./blur/blur_box_alpha_neon.c"
121#endif
122
123static void
124_box_blur_horiz_alpha(const DATA8 *src, DATA8 *dst, int* radii, int w, int h)
125{
126 DEBUG_TIME_BEGIN();
127
128#ifdef BUILD_SSE3
129 if (eina_cpu_features_get() & EINA_CPU_SSE3)
130 {
131 _box_blur_alpha_horiz_step_sse3(src, dst, radii, w, h);
132 goto end;
133 }
134#endif
135#ifdef BUILD_MMX
136 if (eina_cpu_features_get() & EINA_CPU_MMX)
137 {
138 _box_blur_alpha_horiz_step_mmx(src, dst, radii, w, h);
139 goto end;
140 }
141#endif
142#ifdef BUILD_NEON
143 if (eina_cpu_features_get() & EINA_CPU_NEON)
144 {
145 _box_blur_alpha_horiz_step_neon(src, dst, radii, w, h);
146 goto end;
147 }
148#endif
149 _box_blur_alpha_horiz_step(src, dst, radii, w, h);
150
151end:
152 DEBUG_TIME_END();
153}
154
155static void
156_box_blur_vert_alpha(const DATA8 *src, DATA8 *dst, int* radii, int w, int h)
157{
158 DEBUG_TIME_BEGIN();
159
160#ifdef BUILD_SSE3
161 if (eina_cpu_features_get() & EINA_CPU_SSE3)
162 {
163 _box_blur_alpha_vert_step_sse3(src, dst, radii, h, w);
164 goto end;
165 }
166#endif
167#ifdef BUILD_MMX
168 if (eina_cpu_features_get() & EINA_CPU_MMX)
169 {
170 _box_blur_alpha_vert_step_mmx(src, dst, radii, h, w);
171 goto end;
172 }
173#endif
174#ifdef BUILD_NEON
175 if (eina_cpu_features_get() & EINA_CPU_NEON)
176 {
177 _box_blur_alpha_vert_step_neon(src, dst, radii, h, w);
178 goto end;
179 }
180#endif
181 _box_blur_alpha_vert_step(src, dst, radii, h, w);
182
183end:
184 DEBUG_TIME_END();
185}
186
187static Eina_Bool
188_box_blur_apply(Evas_Filter_Command *cmd, Eina_Bool vert, Eina_Bool rgba)
189{
190 unsigned int src_len, src_stride, dst_len, dst_stride;
191 Eina_Bool ret = EINA_TRUE;
192 int radii[7] = {0};
193 unsigned int r;
194 void *src, *dst;
195
196 r = abs(vert ? cmd->blur.dy : cmd->blur.dx);
197 src = _buffer_map_all(cmd->input->buffer, &src_len, E_READ, rgba ? E_ARGB : E_ALPHA, &src_stride);
198 dst = _buffer_map_all(cmd->output->buffer, &dst_len, E_WRITE, rgba ? E_ARGB : E_ALPHA, &dst_stride);
199
200 if (cmd->blur.auto_count)
201 _box_blur_auto_radius(radii, r);
202 else for (int k = 0; k < cmd->blur.count; k++)
203 radii[k] = r;
204
205 if (src && dst)
206 {
207 if (rgba)
208 {
209 if (!vert)
210 _box_blur_horiz_rgba(src, dst, radii, cmd->input->w, cmd->input->h);
211 else
212 _box_blur_vert_rgba(src, dst, radii, cmd->input->w, cmd->input->h);
213 }
214 else
215 {
216 if (!vert)
217 _box_blur_horiz_alpha(src, dst, radii, cmd->input->w, cmd->input->h);
218 else
219 _box_blur_vert_alpha(src, dst, radii, cmd->input->w, cmd->input->h);
220 }
221 }
222 else ret = EINA_FALSE;
223
224 ector_buffer_unmap(cmd->input->buffer, src, src_len);
225 ector_buffer_unmap(cmd->output->buffer, dst, dst_len);
226
227 return ret;
228}
229
230static Eina_Bool
231_box_blur_horiz_apply_alpha(Evas_Filter_Command *cmd)
232{
233 return _box_blur_apply(cmd, 0, 0);
234}
235
236static Eina_Bool
237_box_blur_vert_apply_alpha(Evas_Filter_Command *cmd)
238{
239 return _box_blur_apply(cmd, 1, 0);
240}
241
242static Eina_Bool
243_box_blur_horiz_apply_rgba(Evas_Filter_Command *cmd)
244{
245 return _box_blur_apply(cmd, 0, 1);
246}
247
248static Eina_Bool
249_box_blur_vert_apply_rgba(Evas_Filter_Command *cmd)
250{
251 return _box_blur_apply(cmd, 1, 1);
252}
253
254/* Gaussian blur */
255
256static void
257_sin_blur_weights_get(int *weights, int *pow2_divider, int radius)
258{
259 const int diameter = 2 * radius + 1;
260 double x, divider, sum = 0.0;
261 double dweights[diameter];
262 int k, nextpow2, isum = 0;
263 const int FAKE_PI = 3.0;
264
265 /* Base curve:
266 * f(x) = sin(x+pi/2)/2+1/2
267 */
268
269 for (k = 0; k < diameter; k++)
270 {
271 x = ((double) k / (double) (diameter - 1)) * FAKE_PI * 2.0 - FAKE_PI;
272 dweights[k] = ((sin(x + M_PI_2) + 1.0) / 2.0) * 1024.0;
273 sum += dweights[k];
274 }
275
276 // Now we need to normalize to have a 2^N divider.
277 nextpow2 = log2(2 * sum);
278 divider = (double) (1 << nextpow2);
279
280 for (k = 0; k < diameter; k++)
281 {
282 weights[k] = round(dweights[k] * divider / sum);
283 isum += weights[k];
284 }
285
286 // Final correction. The difference SHOULD be small...
287 weights[radius] += (int) divider - isum;
288
289 if (pow2_divider)
290 *pow2_divider = nextpow2;
291}
292
293#define FUNCTION_NAME _gaussian_blur_horiz_alpha_step
294#define STEP 1
295#include "./blur/blur_gaussian_alpha_.c"
296
297// Step size is w (row by row), loops = w, so STEP = 'loops'
298#define FUNCTION_NAME _gaussian_blur_vert_alpha_step
299#define STEP loops
300#include "./blur/blur_gaussian_alpha_.c"
301
302#define FUNCTION_NAME _gaussian_blur_horiz_rgba_step
303#define STEP 1
304#include "./blur/blur_gaussian_rgba_.c"
305
306#define FUNCTION_NAME _gaussian_blur_vert_rgba_step
307#define STEP loops
308#include "./blur/blur_gaussian_rgba_.c"
309
310static Eina_Bool
311_gaussian_blur_apply(Evas_Filter_Command *cmd, Eina_Bool vert, Eina_Bool rgba)
312{
313 unsigned int src_len, src_stride, dst_len, dst_stride, radius;
314 Eina_Bool ret = EINA_TRUE;
315 int pow2_div = 0, w, h;
316 void *src, *dst;
317 int *weights;
318
319 radius = abs(vert ? cmd->blur.dy : cmd->blur.dx);
320 src = _buffer_map_all(cmd->input->buffer, &src_len, E_READ, rgba ? E_ARGB : E_ALPHA, &src_stride);
321 dst = _buffer_map_all(cmd->output->buffer, &dst_len, E_WRITE, rgba ? E_ARGB : E_ALPHA, &dst_stride);
322 w = cmd->input->w;
323 h = cmd->input->h;
324
325 weights = alloca((2 * radius + 1) * sizeof(int));
326 _sin_blur_weights_get(weights, &pow2_div, radius);
327
328 if (src && dst)
329 {
330 DEBUG_TIME_BEGIN();
331 if (rgba)
332 {
333 if (!vert)
334 _gaussian_blur_horiz_rgba_step(src, dst, radius, w, h, w, weights, pow2_div);
335 else
336 _gaussian_blur_vert_rgba_step(src, dst, radius, h, w, 1, weights, pow2_div);
337 }
338 else
339 {
340 if (!vert)
341 _gaussian_blur_horiz_alpha_step(src, dst, radius, w, h, w, weights, pow2_div);
342 else
343 _gaussian_blur_vert_alpha_step(src, dst, radius, h, w, 1, weights, pow2_div);
344 }
345 DEBUG_TIME_END();
346 }
347 else ret = EINA_FALSE;
348
349 ector_buffer_unmap(cmd->input->buffer, src, src_len);
350 ector_buffer_unmap(cmd->output->buffer, dst, dst_len);
351
352 return ret;
353}
354
355static Eina_Bool
356_gaussian_blur_horiz_apply_alpha(Evas_Filter_Command *cmd)
357{
358 return _gaussian_blur_apply(cmd, 0, 0);
359}
360
361static Eina_Bool
362_gaussian_blur_vert_apply_alpha(Evas_Filter_Command *cmd)
363{
364 return _gaussian_blur_apply(cmd, 1, 0);
365}
366
367static Eina_Bool
368_gaussian_blur_horiz_apply_rgba(Evas_Filter_Command *cmd)
369{
370 return _gaussian_blur_apply(cmd, 0, 1);
371}
372
373static Eina_Bool
374_gaussian_blur_vert_apply_rgba(Evas_Filter_Command *cmd)
375{
376 return _gaussian_blur_apply(cmd, 1, 1);
377}
378
379/* Main entry point */
380
381Evas_Filter_Apply_Func
382eng_filter_blur_func_get(Evas_Filter_Command *cmd)
383{
384 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, NULL);
385 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, NULL);
386 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, NULL);
387 EINA_SAFETY_ON_FALSE_RETURN_VAL(cmd->mode == EVAS_FILTER_MODE_BLUR, NULL);
388
389 switch (cmd->blur.type)
390 {
391 case EVAS_FILTER_BLUR_BOX:
392 if (!cmd->output->alpha_only)
393 {
394 if (cmd->blur.dx)
395 return _box_blur_horiz_apply_rgba;
396 else if (cmd->blur.dy)
397 return _box_blur_vert_apply_rgba;
398 }
399 else
400 {
401 if (cmd->blur.dx)
402 return _box_blur_horiz_apply_alpha;
403 else if (cmd->blur.dy)
404 return _box_blur_vert_apply_alpha;
405 }
406 break;
407 case EVAS_FILTER_BLUR_GAUSSIAN:
408 if (!cmd->output->alpha_only)
409 {
410 if (cmd->blur.dx)
411 return _gaussian_blur_horiz_apply_rgba;
412 else if (cmd->blur.dy)
413 return _gaussian_blur_vert_apply_rgba;
414 }
415 else
416 {
417 if (cmd->blur.dx)
418 return _gaussian_blur_horiz_apply_alpha;
419 else if (cmd->blur.dy)
420 return _gaussian_blur_vert_apply_alpha;
421 }
422 break;
423 default:
424 CRI("Unsupported blur type %d", cmd->blur.type);
425 return NULL;
426 }
427
428 return NULL;
429}