summaryrefslogtreecommitdiff
path: root/src/lib/evas/canvas/evas_filter_mixin.c
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2015-06-17 16:26:30 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2015-06-25 14:36:09 +0900
commit64fd278c62e3286c453885216d2d0c86a01ce9fc (patch)
treed4463d71e84454bb354b4da152a60d51b4f506c6 /src/lib/evas/canvas/evas_filter_mixin.c
parenta18107309dc5233e76b77016b6eb3ef09ddf25ec (diff)
Evas filters: EO-ify the filters API
This creates the new interface Efl.Gfx.Filter And the implementation is a mixin (evas_filter_mixin.c): Evas.Filter All the filter rendering code has now been moved to this new file. TODO: Merge image filtering.
Diffstat (limited to 'src/lib/evas/canvas/evas_filter_mixin.c')
-rw-r--r--src/lib/evas/canvas/evas_filter_mixin.c512
1 files changed, 512 insertions, 0 deletions
diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c
new file mode 100644
index 0000000..20aa8cc
--- /dev/null
+++ b/src/lib/evas/canvas/evas_filter_mixin.c
@@ -0,0 +1,512 @@
1#include "evas_common_private.h"
2#include "evas_private.h"
3#include "../../lib/efl/interfaces/efl_gfx_filter.eo.h"
4#include "evas_filter.eo.h"
5#include "evas_filter.h"
6
7#define MY_CLASS EVAS_FILTER_MIXIN
8
9#define ENFN obj->layer->evas->engine.func
10#define ENDT obj->layer->evas->engine.data.output
11
12typedef struct _Evas_Filter_Data Evas_Filter_Data;
13struct _Evas_Filter_Data
14{
15 const Evas_Object_Filter_Data *data;
16};
17
18static void
19_filter_cb(Evas_Filter_Context *ctx, void *data, Eina_Bool success)
20{
21 Eo *eo_obj = data;
22
23 // Destroy context as we won't reuse it.
24 evas_filter_context_destroy(ctx);
25
26 // Redraw text with normal styles in case of failure
27 if (!success)
28 {
29 Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
30
31 ERR("Filter failed at runtime!");
32 eo_do(eo_obj,
33 evas_filter_invalid_set(EINA_TRUE);
34 evas_filter_dirty());
35 evas_object_change(eo_obj, obj);
36 evas_object_clip_dirty(eo_obj, obj);
37 evas_object_coords_recalc(eo_obj, obj);
38 evas_object_inform_call_resize(eo_obj);
39 }
40}
41
42static void
43_filter_source_hash_free_cb(void *data)
44{
45 Evas_Filter_Proxy_Binding *pb = data;
46 Evas_Object_Protected_Data *proxy, *source;
47 Evas_Filter_Data *pd;
48
49 proxy = eo_data_scope_get(pb->eo_proxy, EVAS_OBJECT_CLASS);
50 source = eo_data_scope_get(pb->eo_source, EVAS_OBJECT_CLASS);
51
52 if (source)
53 {
54 EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy,
55 Evas_Object_Proxy_Data, source_write)
56 source_write->proxies = eina_list_remove(source_write->proxies, pb->eo_proxy);
57 EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, source_write)
58 }
59
60 pd = eo_data_scope_get(pb->eo_proxy, MY_CLASS);
61
62 if (pd && proxy)
63 {
64 if (!eina_hash_population(pd->data->sources))
65 {
66 EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, proxy->proxy,
67 Evas_Object_Proxy_Data, proxy_write)
68 proxy_write->is_proxy = EINA_FALSE;
69 EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, proxy_write)
70 }
71 }
72
73 eina_stringshare_del(pb->name);
74 free(pb);
75}
76
77Eina_Bool
78evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
79 void *output, void *context, void *surface,
80 int x, int y, Eina_Bool do_async, Eina_Bool alpha)
81{
82 Evas_Filter_Data *pd = eo_data_scope_get(eo_obj, MY_CLASS);
83
84 if (!pd->data->invalid && (pd->data->chain || pd->data->code))
85 {
86 int X, Y, W, H, l = 0, r = 0, t = 0, b = 0;
87 Evas_Filter_Context *filter;
88 void *drawctx;
89 Eina_Bool ok;
90 void *previous = pd->data->output;
91 Evas_Object_Filter_Data *fcow =
92 eina_cow_write(evas_object_filter_cow, (const Eina_Cow_Data**)&(pd->data));
93
94 /* NOTE: Filter rendering is now done ENTIRELY on CPU.
95 * So we rely on cache/cache2 to allocate a real image buffer,
96 * that we can draw to. The OpenGL texture will be created only
97 * after the rendering has been done, as we simply push the output
98 * image to GL.
99 */
100
101 W = obj->cur->geometry.w;
102 H = obj->cur->geometry.h;
103 X = obj->cur->geometry.x;
104 Y = obj->cur->geometry.y;
105
106 // Prepare color multiplier
107 ENFN->context_color_set(output, context,
108 obj->cur->cache.clip.r,
109 obj->cur->cache.clip.g,
110 obj->cur->cache.clip.b,
111 obj->cur->cache.clip.a);
112 if (obj->cur->clipper)
113 ENFN->context_multiplier_set(output, context,
114 obj->cur->clipper->cur->cache.clip.r,
115 obj->cur->clipper->cur->cache.clip.g,
116 obj->cur->clipper->cur->cache.clip.b,
117 obj->cur->clipper->cur->cache.clip.a);
118 else
119 ENFN->context_multiplier_unset(output, context);
120
121 if (!fcow->chain)
122 {
123 Evas_Filter_Program *pgm;
124 pgm = evas_filter_program_new(obj->name ? obj->name : obj->type, alpha);
125 evas_filter_program_source_set_all(pgm, fcow->sources);
126 evas_filter_program_state_set(pgm, eo_obj, obj,
127 fcow->state.cur.name, fcow->state.cur.value,
128 fcow->state.next.name, fcow->state.next.value,
129 fcow->state.pos);
130 if (!evas_filter_program_parse(pgm, fcow->code))
131 {
132 ERR("Filter program parsing failed");
133 evas_filter_program_del(pgm);
134 fcow->invalid = EINA_TRUE;
135
136 eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&(pd->data),
137 fcow, EINA_TRUE);
138 return EINA_FALSE;
139 }
140 fcow->chain = pgm;
141 fcow->invalid = EINA_FALSE;
142 }
143 else if (previous && !fcow->changed)
144 {
145 Eina_Bool redraw;
146
147 redraw = evas_filter_program_state_set(fcow->chain, eo_obj, obj,
148 fcow->state.cur.name, fcow->state.cur.value,
149 fcow->state.next.name, fcow->state.next.value,
150 fcow->state.pos);
151 if (redraw)
152 DBG("Filter redraw by state change!");
153
154 // Scan proxies to find if any changed
155 if (!redraw && fcow->sources)
156 {
157 Evas_Filter_Proxy_Binding *pb;
158 Evas_Object_Protected_Data *source;
159 Eina_Iterator *iter;
160
161 iter = eina_hash_iterator_data_new(fcow->sources);
162 EINA_ITERATOR_FOREACH(iter, pb)
163 {
164 source = eo_data_scope_get(pb->eo_source, EVAS_OBJECT_CLASS);
165 if (source->changed)
166 {
167 redraw = EINA_TRUE;
168 break;
169 }
170 }
171 eina_iterator_free(iter);
172 }
173
174 if (!redraw)
175 {
176 // Render this image only
177 ENFN->image_draw(ENDT, context,
178 surface, previous,
179 0, 0, W, H, // src
180 X + x, Y + y, W, H, // dst
181 EINA_FALSE, // smooth
182 do_async);
183
184 eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&(pd->data),
185 fcow, EINA_TRUE);
186 return EINA_TRUE;
187 }
188 }
189 else
190 evas_filter_program_state_set(fcow->chain, eo_obj, obj,
191 fcow->state.cur.name, fcow->state.cur.value,
192 fcow->state.next.name, fcow->state.next.value,
193 fcow->state.pos);
194
195 filter = evas_filter_context_new(obj->layer->evas, do_async);
196
197 // Run script
198 ok = evas_filter_context_program_use(filter, fcow->chain);
199 if (!filter || !ok)
200 {
201 ERR("Parsing failed?");
202 evas_filter_context_destroy(filter);
203
204 eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&(pd->data),
205 fcow, EINA_TRUE);
206 return EINA_FALSE;
207 }
208
209 // Proxies
210 evas_filter_context_proxy_render_all(filter, eo_obj, EINA_FALSE);
211
212 // Draw Context
213 drawctx = ENFN->context_new(ENDT);
214 ENFN->context_color_set(ENDT, drawctx, 255, 255, 255, 255);
215
216 // Allocate all buffers now
217 evas_filter_context_buffers_allocate_all(filter);
218 evas_filter_target_set(filter, context, surface, X + x, Y + y);
219
220 // Steal output and release previous
221 fcow->output = evas_filter_buffer_backing_steal(filter, EVAS_FILTER_BUFFER_OUTPUT_ID);
222 if (fcow->output != previous)
223 evas_filter_buffer_backing_release(filter, previous);
224
225 evas_filter_program_padding_get(fcow->chain, &l, &r, &t, &b);
226 eo_do(eo_obj, evas_filter_input_render(filter, drawctx, l, r, t, b, do_async));
227#warning TODO: draw text into input buffer
228#if 0
229 // Render text to input buffer
230 EINA_INLIST_FOREACH(EINA_INLIST_GET(pd->items), it)
231 if ((pd->font) && (it->text_props.len > 0))
232 {
233 evas_filter_font_draw(filter, drawctx, EVAS_FILTER_BUFFER_INPUT_ID, pd->font,
234 sl + it->x,
235 st + (int) pd->max_ascent,
236 &it->text_props,
237 do_async);
238 }
239#endif
240
241 ENFN->context_free(ENDT, drawctx);
242
243 // Add post-run callback and run filter
244 evas_filter_context_post_run_callback_set(filter, _filter_cb, eo_obj);
245 ok = evas_filter_run(filter);
246 fcow->changed = EINA_FALSE;
247 if (!ok) fcow->invalid = EINA_TRUE;
248
249 eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data **) &(pd->data), fcow, EINA_TRUE);
250
251 if (ok)
252 {
253 DBG("Effect rendering done.");
254 return EINA_TRUE;
255 }
256 else
257 {
258 ERR("Rendering failed.");
259 return EINA_FALSE;
260 }
261 }
262 return EINA_FALSE;
263}
264
265EOLIAN void
266_evas_filter_efl_gfx_filter_program_set(Eo *eo_obj, Evas_Filter_Data *pd,
267 const char *code)
268{
269 Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
270 Evas_Filter_Program *pgm = NULL;
271
272 if (!pd) return;
273 if (pd->data->code == code) return;
274 if (pd->data->code && code && !strcmp(code, pd->data->code)) return;
275
276 evas_object_async_block(obj);
277 EINA_COW_WRITE_BEGIN(evas_object_filter_cow, pd->data, Evas_Object_Filter_Data, fcow)
278 {
279 // Parse filter program
280 evas_filter_program_del(fcow->chain);
281 if (code)
282 {
283 pgm = evas_filter_program_new("Evas_Text", EINA_TRUE);
284 evas_filter_program_source_set_all(pgm, fcow->sources);
285 evas_filter_program_state_set(pgm, eo_obj, obj,
286 fcow->state.cur.name, fcow->state.cur.value,
287 fcow->state.next.name, fcow->state.next.value,
288 fcow->state.pos);
289 if (!evas_filter_program_parse(pgm, code))
290 {
291 ERR("Parsing failed!");
292 evas_filter_program_del(pgm);
293 pgm = NULL;
294 }
295 }
296 fcow->chain = pgm;
297 fcow->changed = EINA_TRUE;
298 fcow->invalid = (pgm == NULL);
299 eina_stringshare_replace(&fcow->code, code);
300 }
301 EINA_COW_WRITE_END(evas_object_filter_cow, pd->data, fcow);
302
303 // Update object
304 eo_do(eo_obj, evas_filter_dirty());
305 evas_object_change(eo_obj, obj);
306 evas_object_clip_dirty(eo_obj, obj);
307 evas_object_coords_recalc(eo_obj, obj);
308 evas_object_inform_call_resize(eo_obj);
309}
310
311EOLIAN const char *
312_evas_filter_efl_gfx_filter_program_get(Eo *eo_obj EINA_UNUSED, Evas_Filter_Data *pd)
313{
314 return pd->data->code;
315}
316
317EOLIAN void
318_evas_filter_efl_gfx_filter_source_set(Eo *eo_obj, Evas_Filter_Data *pd,
319 const char *name, Efl_Gfx_Base *eo_source)
320{
321 Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
322 Evas_Filter_Proxy_Binding *pb, *pb_old = NULL;
323 Evas_Object_Protected_Data *source = NULL;
324 Evas_Object_Filter_Data *fcow = NULL;
325
326 if (eo_source)
327 source = eo_data_scope_get(eo_source, EVAS_OBJECT_CLASS);
328
329 evas_object_async_block(obj);
330 if (!name)
331 {
332 if (!eo_source || !pd->data->sources) return;
333 if (eina_hash_del_by_data(pd->data->sources, eo_source))
334 goto update;
335 return;
336 }
337
338 if (!source && !pd->data->sources)
339 return;
340
341 if (pd->data->sources)
342 {
343 pb_old = eina_hash_find(pd->data->sources, name);
344 if (pb_old && (pb_old->eo_source == eo_source)) return;
345 }
346
347 fcow = eina_cow_write(evas_object_filter_cow, (const Eina_Cow_Data**)&pd->data);
348
349 if (!fcow->sources)
350 fcow->sources = eina_hash_string_small_new(EINA_FREE_CB(_filter_source_hash_free_cb));
351 else if (pb_old)
352 eina_hash_del(fcow->sources, name, pb_old);
353
354 if (!source)
355 {
356 pb_old = eina_hash_find(fcow->sources, name);
357 if (!pb_old)
358 {
359 eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&pd->data, fcow, EINA_TRUE);
360 return;
361 }
362 eina_hash_del_by_key(fcow->sources, name);
363 goto update;
364 }
365
366 pb = calloc(1, sizeof(*pb));
367 pb->eo_proxy = eo_obj;
368 pb->eo_source = eo_source;
369 pb->name = eina_stringshare_add(name);
370
371 if (!eina_list_data_find(source->proxy->proxies, eo_obj))
372 {
373 EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy, Evas_Object_Proxy_Data, source_write)
374 source_write->proxies = eina_list_append(source_write->proxies, eo_obj);
375 EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, source_write)
376 }
377
378 if (!obj->proxy->is_proxy)
379 {
380 EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, obj->proxy, Evas_Object_Proxy_Data, proxy_write)
381 proxy_write->is_proxy = EINA_TRUE;
382 EINA_COW_WRITE_END(evas_object_proxy_cow, obj->proxy, proxy_write)
383 }
384
385 eina_hash_add(fcow->sources, pb->name, pb);
386 evas_filter_program_source_set_all(fcow->chain, fcow->sources);
387
388 // Update object
389update:
390 if (fcow)
391 {
392 fcow->changed = EINA_TRUE;
393 fcow->invalid = EINA_FALSE;
394 eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&pd->data, fcow, EINA_TRUE);
395 }
396
397 eo_do(eo_obj, evas_filter_dirty());
398 evas_object_change(eo_obj, obj);
399 evas_object_clip_dirty(eo_obj, obj);
400 evas_object_coords_recalc(eo_obj, obj);
401 evas_object_inform_call_resize(eo_obj);
402}
403
404EOLIAN void
405_evas_filter_efl_gfx_filter_source_get(Eo *eo_obj EINA_UNUSED, Evas_Filter_Data *pd,
406 const char *name, Efl_Gfx_Base **source)
407{
408 if (!source) return;
409 *source = eina_hash_find(pd->data->sources, name);
410}
411
412EOLIAN void
413_evas_filter_efl_gfx_filter_state_set(Eo *eo_obj, Evas_Filter_Data *pd,
414 const char *cur_state, double cur_val,
415 const char *next_state, double next_val,
416 double pos)
417{
418 Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
419
420 evas_object_async_block(obj);
421 if ((cur_state != pd->data->state.cur.name) || (cur_val != pd->data->state.cur.value) ||
422 (next_state != pd->data->state.next.name) || (next_val != pd->data->state.next.value) ||
423 (pos != pd->data->state.pos))
424 {
425 EINA_COW_WRITE_BEGIN(evas_object_filter_cow, pd->data, Evas_Object_Filter_Data, fcow)
426 {
427 fcow->changed = 1;
428 fcow->state.cur.name = cur_state;
429 fcow->state.cur.value = cur_val;
430 fcow->state.next.name = next_state;
431 fcow->state.next.value = next_val;
432 fcow->state.pos = pos;
433
434 if (pd->data->chain)
435 {
436 evas_filter_program_state_set(pd->data->chain, eo_obj, obj,
437 fcow->state.cur.name, fcow->state.cur.value,
438 fcow->state.next.name, fcow->state.next.value,
439 fcow->state.pos);
440 }
441 }
442 EINA_COW_WRITE_END(evas_object_filter_cow, pd->data, fcow);
443
444 // Mark as changed
445 eo_do(eo_obj, evas_filter_dirty());
446 evas_object_change(eo_obj, obj);
447 evas_object_clip_dirty(eo_obj, obj);
448 evas_object_coords_recalc(eo_obj, obj);
449 evas_object_inform_call_resize(eo_obj);
450 }
451}
452
453EOLIAN void
454_evas_filter_efl_gfx_filter_padding_get(Eo *eo_obj EINA_UNUSED, Evas_Filter_Data *pd,
455 int *l, int *r, int *t, int *b)
456{
457 if (!pd->data->chain)
458 {
459 if (l) *l = 0;
460 if (r) *r = 0;
461 if (t) *t = 0;
462 if (b) *b = 0;
463 return;
464 }
465 evas_filter_program_padding_get(pd->data->chain, l, r, t, b);
466}
467
468EOLIAN void
469_evas_filter_changed_set(Eo *eo_obj EINA_UNUSED, Evas_Filter_Data *pd, Eina_Bool val)
470{
471 if ((evas_object_filter_cow_default != pd->data) && (pd->data->changed != val))
472 {
473 EINA_COW_WRITE_BEGIN(evas_object_filter_cow, pd->data, Evas_Object_Filter_Data, fcow)
474 fcow->changed = val;
475 EINA_COW_WRITE_END(evas_object_filter_cow, pd->data, fcow);
476 }
477}
478
479EOLIAN void
480_evas_filter_invalid_set(Eo *eo_obj EINA_UNUSED, Evas_Filter_Data *pd, Eina_Bool val)
481{
482 if (pd->data->invalid != val)
483 {
484 EINA_COW_WRITE_BEGIN(evas_object_filter_cow, pd->data, Evas_Object_Filter_Data, fcow)
485 fcow->invalid = val;
486 EINA_COW_WRITE_END(evas_object_filter_cow, pd->data, fcow);
487 }
488}
489
490EOLIAN void
491_evas_filter_constructor(Eo *eo_obj EINA_UNUSED, Evas_Filter_Data *pd)
492{
493 pd->data = eina_cow_alloc(evas_object_filter_cow);
494}
495
496EOLIAN void
497_evas_filter_destructor(Eo *eo_obj, Evas_Filter_Data *pd)
498{
499 Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
500
501 if (!pd->data) return;
502 if (evas_object_filter_cow_default == pd->data) return;
503
504 if (pd->data->output)
505 ENFN->image_free(ENDT, pd->data->output);
506 eina_hash_free(pd->data->sources);
507 evas_filter_program_del(pd->data->chain);
508 eina_stringshare_del(pd->data->code);
509 eina_cow_free(evas_object_filter_cow, (const Eina_Cow_Data **) &pd->data);
510}
511
512#include "evas_filter.eo.c"