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 19:33:50 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2017-04-14 11:26:42 +0900
commit09ff5f419ec102e65dc37cabf53d9854c6da978e (patch)
tree5287d53f7b6bc31614841fa95486a3e5c97a9c8c /src/modules/evas/engines/software_generic/filters
parent0740010a061d15a4ecaa00dc21c10301e0af4847 (diff)
evas filters: Move mask to software generic (2/8)
Diffstat (limited to 'src/modules/evas/engines/software_generic/filters')
-rw-r--r--src/modules/evas/engines/software_generic/filters/evas_filter_mask.c454
1 files changed, 454 insertions, 0 deletions
diff --git a/src/modules/evas/engines/software_generic/filters/evas_filter_mask.c b/src/modules/evas/engines/software_generic/filters/evas_filter_mask.c
new file mode 100644
index 0000000000..18acf8c7d7
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/evas_filter_mask.c
@@ -0,0 +1,454 @@
1/* Implementation of some masking functions for the software engine */
2
3#include "../evas_engine_filter.h"
4#include "draw.h"
5
6// Naming convention: _func_engine_incolor_maskcolor_outcolor()
7static Eina_Bool _mask_cpu_alpha_alpha_alpha(Evas_Filter_Command *cmd);
8static Eina_Bool _mask_cpu_alpha_rgba_rgba(Evas_Filter_Command *cmd);
9static Eina_Bool _mask_cpu_alpha_alpha_rgba(Evas_Filter_Command *cmd);
10static Eina_Bool _mask_cpu_rgba_alpha_rgba(Evas_Filter_Command *cmd);
11static Eina_Bool _mask_cpu_rgba_rgba_rgba(Evas_Filter_Command *cmd);
12
13Evas_Filter_Apply_Func
14eng_filter_mask_func_get(Evas_Filter_Command *cmd)
15{
16 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, NULL);
17 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, NULL);
18 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, NULL);
19 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->mask, NULL);
20 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input->buffer, NULL);
21 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output->buffer, NULL);
22 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->mask->buffer, NULL);
23 EINA_SAFETY_ON_FALSE_RETURN_VAL((cmd->input->w > 0) && (cmd->input->h > 0), NULL);
24 EINA_SAFETY_ON_FALSE_RETURN_VAL((cmd->mask->w > 0) && (cmd->mask->h > 0), NULL);
25 EINA_SAFETY_ON_FALSE_RETURN_VAL(cmd->input->w == cmd->output->w, NULL);
26 EINA_SAFETY_ON_FALSE_RETURN_VAL(cmd->input->h == cmd->output->h, NULL);
27
28 if (cmd->input->alpha_only)
29 {
30 if (cmd->output->alpha_only)
31 {
32 if (!cmd->mask->alpha_only)
33 {
34 DBG("Input and output are Alpha but mask is RGBA. This is not "
35 "optimal (implicit conversion and loss of color).");
36 }
37 return _mask_cpu_alpha_alpha_alpha;
38 }
39 else if (!cmd->mask->alpha_only)
40 return _mask_cpu_alpha_rgba_rgba;
41 else
42 return _mask_cpu_alpha_alpha_rgba;
43 }
44 else
45 {
46 if (!cmd->output->alpha_only)
47 {
48 // rgba -> rgba
49 if (cmd->mask->alpha_only)
50 return _mask_cpu_rgba_alpha_rgba;
51 else
52 return _mask_cpu_rgba_rgba_rgba;
53 }
54 else
55 {
56 // rgba -> alpha
57 DBG("Input is RGBA but output is Alpha, losing colors.");
58 return _mask_cpu_alpha_alpha_alpha;
59 }
60 }
61}
62
63static Eina_Bool
64_mask_cpu_alpha_alpha_alpha(Evas_Filter_Command *cmd)
65{
66 unsigned int src_len = 0, src_stride, msk_len = 0, msk_stride, dst_len = 0, dst_stride;
67 Efl_Gfx_Render_Op render_op = cmd->draw.rop;
68 Evas_Filter_Buffer *msk_fb;
69 Draw_Func_Alpha func;
70 uint8_t *src_map = NULL, *dst, *dst_map = NULL, *msk, *msk_map = NULL;
71 int w, h, mw, mh, x, y, my;
72 int stepsize, stepcount, step;
73 Eina_Bool ret = EINA_FALSE;
74
75 /* Mechanism:
76 * 1. Stretch mask as requested in fillmode
77 * 2. Copy source to destination
78 * 3. Render mask into destination using alpha function
79 *
80 * FIXME: Could probably be optimized into a single op :)
81 */
82
83 w = cmd->input->w;
84 h = cmd->input->h;
85 mw = cmd->mask->w;
86 mh = cmd->mask->h;
87 stepsize = MIN(mw, w);
88 stepcount = w / stepsize;
89
90 // Stretch if necessary.
91 if ((mw != w || mh != h) && (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_XY))
92 {
93 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->ctx->buffer_scaled_get, EINA_FALSE);
94
95 if (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X)
96 mw = w;
97 if (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y)
98 mh = h;
99
100 BUFFERS_LOCK();
101 msk_fb = cmd->ctx->buffer_scaled_get(cmd->ctx, cmd->mask, mw, mh);
102 BUFFERS_UNLOCK();
103
104 EINA_SAFETY_ON_NULL_RETURN_VAL(msk_fb, EINA_FALSE);
105 msk_fb->locked = EINA_FALSE;
106 }
107 else msk_fb = cmd->mask;
108
109 msk_map = msk = _buffer_map_all(msk_fb->buffer, &msk_len, E_READ, E_ALPHA, &msk_stride);
110 dst_map = dst = _buffer_map_all(cmd->output->buffer, &dst_len, E_WRITE, E_ALPHA, &dst_stride);
111 EINA_SAFETY_ON_FALSE_GOTO(dst_map && msk_map, end);
112
113 // First pass: copy to dest
114 if (cmd->input->buffer != cmd->output->buffer)
115 {
116 src_map = _buffer_map_all(cmd->input->buffer, &src_len, E_READ, E_ALPHA, &src_stride);
117 EINA_SAFETY_ON_FALSE_GOTO(src_map, end);
118 if (dst_stride == src_stride)
119 memcpy(dst_map, src_map, dst_stride * h * sizeof(uint8_t));
120 else
121 {
122 for (y = 0; y < h; y++)
123 memcpy(dst_map + (y * dst_stride), src_map + (y * src_stride),
124 MIN(dst_stride, src_stride) * h * sizeof(uint8_t));
125 }
126 }
127
128 // Second pass: apply render op
129 func = efl_draw_alpha_func_get(render_op, EINA_FALSE);
130 for (y = 0, my = 0; y < h; y++, my++)
131 {
132 if (my >= mh) my = 0;
133
134 msk = msk_map + (my * msk_stride);
135 dst = dst_map + (y * dst_stride);
136
137 for (step = 0; step < stepcount; step++, dst += stepsize)
138 func(dst, msk, stepsize);
139
140 x = stepsize * stepcount;
141 if (x < w)
142 {
143 func(dst, msk, w - x);
144 }
145 }
146
147 ret = EINA_TRUE;
148
149end:
150 ector_buffer_unmap(cmd->input->buffer, src_map, src_len);
151 ector_buffer_unmap(msk_fb->buffer, msk_map, msk_len);
152 ector_buffer_unmap(cmd->output->buffer, dst_map, dst_len);
153 return ret;
154}
155
156static Eina_Bool
157_mask_cpu_rgba_alpha_rgba(Evas_Filter_Command *cmd)
158{
159 Evas_Filter_Buffer *fb;
160 Eina_Bool ok;
161
162 /* Mechanism:
163 * 1. Swap input and mask
164 * 2. Apply mask operation for alpha+rgba+rgba
165 * 3. Swap input and mask
166 */
167
168 fb = cmd->input;
169 cmd->input = cmd->mask;
170 cmd->mask = fb;
171
172 ok = _mask_cpu_alpha_rgba_rgba(cmd);
173
174 fb = cmd->input;
175 cmd->input = cmd->mask;
176 cmd->mask = fb;
177
178 return ok;
179}
180
181static Eina_Bool
182_mask_cpu_alpha_rgba_rgba(Evas_Filter_Command *cmd)
183{
184 unsigned int src_len, src_stride, msk_len, msk_stride, dst_len, dst_stride;
185 Efl_Gfx_Render_Op op = cmd->draw.rop;
186 Evas_Filter_Buffer *msk_fb;
187 RGBA_Comp_Func_Mask func1;
188 Draw_Func_ARGB_Mix3 func2;
189 uint8_t *src, *src_map = NULL, *msk_map = NULL, *dst_map = NULL;
190 uint32_t *dst, *msk, *span;
191 int w, h, mw, mh, x, y, my;
192 int stepsize, stepcount, step;
193 Eina_Bool ret = EINA_FALSE;
194 uint32_t color;
195
196 /* Mechanism:
197 * 1. Stretch mask as requested in fillmode
198 * 2. Render input to span using (using "mask" function)
199 * 3. Mix 3 RGBA images together into dest: span, mask, dest
200 *
201 * FIXME: Could probably be optimized into a single op :)
202 */
203
204 w = cmd->input->w;
205 h = cmd->input->h;
206 mw = cmd->mask->w;
207 mh = cmd->mask->h;
208 color = ARGB_JOIN(cmd->draw.A, cmd->draw.R, cmd->draw.G, cmd->draw.B);
209 stepsize = MIN(mw, w);
210 stepcount = w / stepsize;
211 span = alloca(stepsize * sizeof(uint32_t));
212
213 // Stretch if necessary.
214 if ((mw != w || mh != h) && (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_XY))
215 {
216 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->ctx->buffer_scaled_get, EINA_FALSE);
217
218 if (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X)
219 mw = w;
220 if (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y)
221 mh = h;
222
223 BUFFERS_LOCK();
224 msk_fb = cmd->ctx->buffer_scaled_get(cmd->ctx, cmd->mask, mw, mh);
225 BUFFERS_UNLOCK();
226
227 EINA_SAFETY_ON_NULL_RETURN_VAL(msk_fb, EINA_FALSE);
228 msk_fb->locked = EINA_FALSE;
229 }
230 else msk_fb = cmd->mask;
231
232 src_map = _buffer_map_all(cmd->input->buffer, &src_len, E_READ, E_ALPHA, &src_stride);
233 msk_map = _buffer_map_all(msk_fb->buffer, &msk_len, E_READ, E_ARGB, &msk_stride);
234 dst_map = _buffer_map_all(cmd->output->buffer, &dst_len, E_WRITE, E_ARGB, &dst_stride);
235 EINA_SAFETY_ON_FALSE_GOTO(src_map && dst_map && msk_map, end);
236
237 func1 = efl_draw_func_mask_span_get(op, 0xFFFFFFFF);
238 func2 = efl_draw_func_argb_mix3_get(op, color);
239 EINA_SAFETY_ON_FALSE_GOTO(func1 && func2, end);
240
241 // Apply mask using Gfx functions
242 for (y = 0, my = 0; y < h; y++, my++)
243 {
244 int len;
245
246 if (my >= mh) my = 0;
247
248 len = stepsize;
249 src = src_map + (y * src_stride);
250 msk = (uint32_t *) (msk_map + (my * msk_stride));
251 dst = (uint32_t *) (dst_map + (y * dst_stride));
252
253 for (step = 0; step < stepcount; step++, dst += stepsize, src += stepsize)
254 {
255 memset(span, 0, len * sizeof(uint32_t));
256 func1(span, src, len, 0xFFFFFFFF);
257 func2(dst, span, msk, len, color);
258 }
259
260 x = stepsize * stepcount;
261 if (x < w)
262 {
263 len = w - x;
264 memset(span, 0, len * sizeof(uint32_t));
265 func1(span, src, len, 0xFFFFFFFF);
266 func2(dst, span, msk, len, color);
267 }
268 }
269
270 ret = EINA_TRUE;
271
272end:
273 ector_buffer_unmap(cmd->input->buffer, src_map, src_len);
274 ector_buffer_unmap(msk_fb->buffer, msk_map, msk_len);
275 ector_buffer_unmap(cmd->output->buffer, dst_map, dst_len);
276 return ret;
277}
278
279static Eina_Bool
280_mask_cpu_alpha_alpha_rgba(Evas_Filter_Command *cmd)
281{
282 unsigned int src_len, src_stride, msk_len, msk_stride, dst_len, dst_stride;
283 uint8_t *src, *msk, *span, *src_map = NULL, *msk_map = NULL, *dst_map = NULL;
284 Evas_Filter_Buffer *msk_fb;
285 Draw_Func_Alpha func1;
286 RGBA_Comp_Func_Mask func2;
287 uint32_t *dst;
288 uint32_t color;
289 Efl_Gfx_Render_Op op = cmd->draw.rop;
290 int w, h, mw, mh, x, y, my;
291 int stepsize, stepcount, step;
292 Eina_Bool ret = EINA_FALSE;
293
294 /* Mechanism:
295 * 1. Copy mask to span buffer (1 line)
296 * 2. Multiply source by span (so that: span = mask * source)
297 * 3. Render span to destination using color (blend)
298 *
299 * FIXME: Could probably be optimized into a single op :)
300 */
301
302 w = cmd->input->w;
303 h = cmd->input->h;
304 mw = cmd->mask->w;
305 mh = cmd->mask->h;
306 color = ARGB_JOIN(cmd->draw.A, cmd->draw.R, cmd->draw.G, cmd->draw.B);
307 stepsize = MIN(mw, w);
308 stepcount = w / stepsize;
309 span = alloca(stepsize * sizeof(uint32_t));
310
311 // Stretch if necessary.
312 if ((mw != w || mh != h) && (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_XY))
313 {
314 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->ctx->buffer_scaled_get, EINA_FALSE);
315
316 if (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X)
317 mw = w;
318 if (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y)
319 mh = h;
320
321 BUFFERS_LOCK();
322 msk_fb = cmd->ctx->buffer_scaled_get(cmd->ctx, cmd->mask, mw, mh);
323 BUFFERS_UNLOCK();
324
325 EINA_SAFETY_ON_NULL_RETURN_VAL(msk_fb, EINA_FALSE);
326 msk_fb->locked = EINA_FALSE;
327 }
328 else msk_fb = cmd->mask;
329
330 src_map = _buffer_map_all(cmd->input->buffer, &src_len, E_READ, E_ALPHA, &src_stride);
331 msk_map = _buffer_map_all(msk_fb->buffer, &msk_len, E_READ, E_ALPHA, &msk_stride);
332 dst_map = _buffer_map_all(cmd->output->buffer, &dst_len, E_WRITE, E_ARGB, &dst_stride);
333 EINA_SAFETY_ON_FALSE_GOTO(src_map && dst_map && msk_map, end);
334
335 func1 = efl_draw_alpha_func_get(op, EINA_TRUE);
336 func2 = efl_draw_func_mask_span_get(op, color);
337 EINA_SAFETY_ON_FALSE_GOTO(func1 && func2, end);
338
339 for (y = 0, my = 0; y < h; y++, my++)
340 {
341 int len;
342
343 if (my >= mh) my = 0;
344
345 len = stepsize;
346 src = src_map + (y * src_stride);
347 msk = msk_map + (my * msk_stride);
348 dst = (uint32_t *) (dst_map + (y * dst_stride));
349
350 for (step = 0; step < stepcount; step++, dst += stepsize, src += stepsize)
351 {
352 memcpy(span, msk, len * sizeof(uint8_t));
353 func1(span, src, len);
354 func2(dst, span, len, color);
355 }
356
357 x = stepsize * stepcount;
358 if (x < w)
359 {
360 len = w - x;
361 memcpy(span, msk, len * sizeof(uint8_t));
362 func1(span, src, len);
363 func2(dst, span, len, color);
364 }
365 }
366
367 ret = EINA_TRUE;
368
369end:
370 ector_buffer_unmap(cmd->input->buffer, src_map, src_len);
371 ector_buffer_unmap(msk_fb->buffer, msk_map, msk_len);
372 ector_buffer_unmap(cmd->output->buffer, dst_map, dst_len);
373 return ret;
374}
375
376static Eina_Bool
377_mask_cpu_rgba_rgba_rgba(Evas_Filter_Command *cmd)
378{
379 unsigned int src_len, src_stride, msk_len, msk_stride, dst_len, dst_stride;
380 uint8_t *src_map = NULL, *msk_map = NULL, *dst_map = NULL;
381 Draw_Func_ARGB_Mix3 func;
382 Evas_Filter_Buffer *msk_fb;
383 uint32_t *dst, *msk, *src;
384 int w, h, mw, mh, x, y, my;
385 int stepsize, stepcount, step;
386 Eina_Bool ret = EINA_FALSE;
387 uint32_t color;
388
389 /* Mechanism:
390 * 1. Stretch mask as requested in fillmode
391 * 2. Mix 3 colors
392 */
393
394 w = cmd->input->w;
395 h = cmd->input->h;
396 mw = cmd->mask->w;
397 mh = cmd->mask->h;
398 color = ARGB_JOIN(cmd->draw.A, cmd->draw.R, cmd->draw.G, cmd->draw.B);
399 stepsize = MIN(mw, w);
400 stepcount = w / stepsize;
401
402 // Stretch if necessary.
403 if ((mw != w || mh != h) && (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_XY))
404 {
405 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->ctx->buffer_scaled_get, EINA_FALSE);
406
407 if (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_X)
408 mw = w;
409 if (cmd->draw.fillmode & EVAS_FILTER_FILL_MODE_STRETCH_Y)
410 mh = h;
411
412 BUFFERS_LOCK();
413 msk_fb = cmd->ctx->buffer_scaled_get(cmd->ctx, cmd->mask, mw, mh);
414 BUFFERS_UNLOCK();
415
416 EINA_SAFETY_ON_NULL_RETURN_VAL(msk_fb, EINA_FALSE);
417 msk_fb->locked = EINA_FALSE;
418 }
419 else msk_fb = cmd->mask;
420
421 src_map = _buffer_map_all(cmd->input->buffer, &src_len, E_READ, E_ARGB, &src_stride);
422 msk_map = _buffer_map_all(msk_fb->buffer, &msk_len, E_READ, E_ARGB, &msk_stride);
423 dst_map = _buffer_map_all(cmd->output->buffer, &dst_len, E_WRITE, E_ARGB, &dst_stride);
424 EINA_SAFETY_ON_FALSE_GOTO(src_map && dst_map && msk_map, end);
425
426 func = efl_draw_func_argb_mix3_get(cmd->draw.rop, color);
427
428 // Apply mask using Gfx functions
429 for (y = 0, my = 0; y < h; y++, my++)
430 {
431 if (my >= mh) my = 0;
432
433 src = (uint32_t *) (src_map + (y * src_stride));
434 msk = (uint32_t *) (msk_map + (my * msk_stride));
435 dst = (uint32_t *) (dst_map + (y * dst_stride));
436
437 for (step = 0; step < stepcount; step++, dst += stepsize, src += stepsize)
438 func(dst, src, msk, stepsize, color);
439
440 x = stepsize * stepcount;
441 if (x < w)
442 {
443 func(dst, src, msk, w - x, color);
444 }
445 }
446
447 ret = EINA_TRUE;
448
449end:
450 ector_buffer_unmap(cmd->input->buffer, src_map, src_len);
451 ector_buffer_unmap(msk_fb->buffer, msk_map, msk_len);
452 ector_buffer_unmap(cmd->output->buffer, dst_map, dst_len);
453 return ret;
454}