44a274f2f79c4c7cafee63b127bbfcbd05028eb4
[framework/uifw/efl.git] / src / lib / ecore_buffer / ecore_buffer.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8
9 #include "Eina.h"
10 #include "Ecore.h"
11
12 #include "Ecore_Buffer.h"
13 #include "ecore_buffer_private.h"
14
15 typedef struct _Ecore_Buffer_Module Ecore_Buffer_Module;
16 typedef struct _Ecore_Buffer_Cb_Data Ecore_Buffer_Cb_Data;
17
18 struct _Ecore_Buffer_Module
19 {
20      Ecore_Buffer_Backend *be;
21      Ecore_Buffer_Module_Data data;
22 };
23
24 struct _Ecore_Buffer
25 {
26    unsigned int width;
27    unsigned int height;
28    int format;
29    unsigned int flags;
30
31    Ecore_Buffer_Data buffer_data;
32    Ecore_Buffer_Module *bm;
33
34    Eina_Hash *data;
35    Eina_Inlist *free_callbacks;
36 };
37
38 struct _Ecore_Buffer_Cb_Data
39 {
40    EINA_INLIST;
41    Ecore_Buffer_Cb cb;
42    void *data;
43 };
44
45 static Eina_Hash *_backends;
46 static Eina_Array *_modules;
47 static int _ecore_buffer_init_count = 0;
48 static int _ecore_buffer_log_dom = -1;
49
50 #ifdef ERR
51 #undef ERR
52 #endif
53 #define ERR(...) EINA_LOG_DOM_ERR(_ecore_buffer_log_dom, __VA_ARGS__)
54
55 #ifdef DBG
56 #undef DBG
57 #endif
58 #define DBG(...) EINA_LOG_DOM_DBG(_ecore_buffer_log_dom, __VA_ARGS__)
59
60 #ifndef PACKAGE_LIB_DIR
61 #define PACKAGE_LIB_DIR ""
62 #endif
63 #ifndef MODULE_ARCH
64 #define MODULE_ARCH ""
65 #endif
66
67 static Ecore_Buffer_Module *
68 _ecore_buffer_get_backend(const char *name)
69 {
70    Ecore_Buffer_Module *bm = NULL;
71    Eina_Iterator *backend_name_itr;
72    const char *backend_name = NULL;
73
74    backend_name = name;
75
76    if (backend_name == NULL)
77      {
78         backend_name = (const char*)getenv("ECORE_BUFFER_ENGINE");
79         if (!backend_name)
80           {
81              backend_name_itr = eina_hash_iterator_data_new(_backends);
82              while((!bm) &&
83                    (eina_iterator_next(backend_name_itr, (void **)&bm)));
84              eina_iterator_free(backend_name_itr);
85           }
86      }
87    else
88      bm = eina_hash_find(_backends, backend_name);
89
90    if ((!bm) || (!bm->be) || (!bm->be->init))
91      return NULL;
92
93    bm->data = bm->be->init(NULL, NULL);
94
95    return bm;
96 }
97
98 static Eina_Bool
99 _ecore_buffer_backends_free(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
100 {
101    Ecore_Buffer_Module *bm = data;
102
103    if (!bm)
104      return EINA_FALSE;
105
106    if (bm->data)
107      bm->be->shutdown(bm->data);
108
109    return EINA_TRUE;
110 }
111
112 EAPI Eina_Bool
113 ecore_buffer_register(Ecore_Buffer_Backend *be)
114 {
115    Ecore_Buffer_Module *bm;
116
117    EINA_SAFETY_ON_NULL_RETURN_VAL(be, 0);
118
119    bm = calloc(1, sizeof(Ecore_Buffer_Module));
120    if (!bm)
121      return EINA_FALSE;
122
123    bm->be = be;
124    bm->data = NULL;
125
126    return eina_hash_add(_backends, be->name, bm);
127 }
128
129 EAPI void
130 ecore_buffer_unregister(Ecore_Buffer_Backend *be)
131 {
132    Ecore_Buffer_Module *bm;
133
134    EINA_SAFETY_ON_NULL_RETURN(be);
135
136    bm = eina_hash_find(_backends, be->name);
137    if (!bm)
138      return;
139
140    eina_hash_del(_backends, be->name, bm);
141    free(bm);
142 }
143
144 EAPI Eina_Bool
145 ecore_buffer_init(void)
146 {
147    char *path;
148
149    if (++_ecore_buffer_init_count > 1)
150      return EINA_TRUE;
151
152    _ecore_buffer_log_dom = eina_log_domain_register("ecore_buffer", EINA_COLOR_BLUE);
153    if (_ecore_buffer_log_dom < 0)
154      {
155         EINA_LOG_ERR("Could not register log domain: ecore_buffer");
156         goto err;
157      }
158
159    _backends = eina_hash_string_superfast_new(NULL);
160
161    /* dynamic backends */
162    _modules = eina_module_arch_list_get(NULL,
163                                         PACKAGE_LIB_DIR "/ecore_buffer/modules",
164                                         MODULE_ARCH);
165
166    path = eina_module_symbol_path_get((const void *)ecore_buffer_init,
167                                       "/ecore_buffer/modules");
168
169    _modules = eina_module_arch_list_get(_modules, path, MODULE_ARCH);
170    if (path)
171      free(path);
172
173    /* fallback using module where in build directory */
174    if ((!_modules) ||
175        (eina_array_count(_modules) == 0))
176      {
177         ERR("No available module in library directy: %s",
178             PACKAGE_LIB_DIR "/ecore_buffer/modules");
179         ERR("Fallback to load module where in build directory :%s",
180             PACKAGE_BUILD_DIR "/src/modules/");
181         _modules = eina_module_list_get(NULL,
182                                         PACKAGE_BUILD_DIR "/src/modules/",
183                                         EINA_TRUE, NULL, NULL);
184      }
185
186    if ((!_modules) ||
187        (eina_array_count(_modules) == 0))
188      {
189         ERR("no ecore_buffer modules able to be loaded.");
190         eina_hash_free(_backends);
191         eina_log_domain_unregister(_ecore_buffer_log_dom);
192         _ecore_buffer_log_dom = -1;
193         goto err;
194      }
195
196    // XXX: MODFIX: do not list ALL modules and load them ALL! this is
197    // wrong. load the module we need WHEN we need it (by name etc. etc.
198    // from api).
199    eina_module_list_load(_modules);
200
201    return EINA_TRUE;
202
203 err:
204    _ecore_buffer_init_count--;
205    return EINA_FALSE;
206 }
207
208 EAPI Eina_Bool
209 ecore_buffer_shutdown(void)
210 {
211    if (_ecore_buffer_init_count < 1)
212      {
213         WARN("Ecore_Buffer shut down called without init");
214         return EINA_FALSE;
215      }
216
217    if (--_ecore_buffer_init_count != 0)
218      return EINA_FALSE;
219
220    /* dynamic backends */
221    eina_hash_foreach(_backends, _ecore_buffer_backends_free, NULL);
222
223    eina_module_list_free(_modules);
224    if (_modules)
225      eina_array_free(_modules);
226
227    if (_backends)
228      eina_hash_free(_backends);
229
230    eina_log_domain_unregister(_ecore_buffer_log_dom);
231    _ecore_buffer_log_dom = -1;
232
233    return EINA_TRUE;
234 }
235
236 EAPI Ecore_Buffer*
237 ecore_buffer_new(const char *engine, unsigned int width, unsigned int height, Ecore_Buffer_Format format, unsigned int flags)
238 {
239    Ecore_Buffer_Module *bm;
240    Ecore_Buffer *bo;
241    void *bo_data;
242
243    bm = _ecore_buffer_get_backend(engine);
244    if (!bm)
245      {
246         ERR("Failed to get backend: %s", engine);
247         return NULL;
248      }
249
250    EINA_SAFETY_ON_NULL_RETURN_VAL(bm->be, NULL);
251
252    if (!bm->be->buffer_alloc)
253      {
254         ERR("Not supported create buffer");
255         return NULL;
256      }
257
258    bo = calloc(1, sizeof(Ecore_Buffer));
259    if (!bo)
260      return NULL;
261
262    bo_data = bm->be->buffer_alloc(bm->data, width, height, format, flags);
263    if (!bo_data)
264      {
265         free(bo);
266         return NULL;
267      }
268
269    bo->bm = bm;
270    bo->width = width;
271    bo->height = height;
272    bo->format = format;
273    bo->flags = flags;
274    bo->buffer_data = bo_data;
275
276    return bo;
277 }
278
279 EAPI Ecore_Buffer *
280 ecore_buffer_new_with_tbm_surface(const char *engine, void *tbm_surface, unsigned int flags)
281 {
282    Ecore_Buffer_Module *bm;
283    Ecore_Buffer *bo;
284    int w = 0, h = 0;
285    Ecore_Buffer_Format format = 0;
286    void *bo_data;
287
288    bm = _ecore_buffer_get_backend(engine);
289    if (!bm)
290      {
291         ERR("Failed to get Backend: %s", engine);
292         return NULL;
293      }
294
295    EINA_SAFETY_ON_NULL_RETURN_VAL(bm->be, NULL);
296
297    if (!bm->be->buffer_alloc_with_tbm_surface)
298      {
299         ERR("Not supported create buffer with tbm_surface");
300         return NULL;
301      }
302
303    bo = calloc(1, sizeof(Ecore_Buffer));
304    if (!bo)
305      return NULL;
306
307    bo_data = bm->be->buffer_alloc_with_tbm_surface(bm->data, tbm_surface,
308                                                    &w, &h, &format, flags);
309    if (!bo_data)
310      {
311         free(bo);
312         return NULL;
313      }
314
315    bo->bm = bm;
316    bo->flags = flags;
317    bo->buffer_data = bo_data;
318    bo->width = w;
319    bo->height = h;
320    bo->format = format;
321
322    return bo;
323 }
324
325 EAPI void
326 ecore_buffer_free(Ecore_Buffer *buf)
327 {
328    Ecore_Buffer_Cb_Data *free_cb;
329
330    EINA_SAFETY_ON_NULL_RETURN(buf);
331
332    //Call free_cb
333    while (buf->free_callbacks)
334      {
335         free_cb = EINA_INLIST_CONTAINER_GET(buf->free_callbacks, Ecore_Buffer_Cb_Data);
336         buf->free_callbacks = eina_inlist_remove(buf->free_callbacks, buf->free_callbacks);
337
338         free_cb->cb(buf, free_cb->data);
339         free(free_cb);
340      }
341
342    EINA_SAFETY_ON_NULL_RETURN(buf->bm);
343    EINA_SAFETY_ON_NULL_RETURN(buf->bm->be);
344    EINA_SAFETY_ON_NULL_RETURN(buf->bm->be->buffer_free);
345
346    buf->bm->be->buffer_free(buf->bm->data, buf->buffer_data);
347
348    //Free User Data
349    if (buf->data)
350      eina_hash_free(buf->data);
351
352    free(buf);
353 }
354
355 EAPI Ecore_Pixmap
356 ecore_buffer_pixmap_get(Ecore_Buffer *buf)
357 {
358    EINA_SAFETY_ON_NULL_RETURN_VAL(buf, 0);
359    EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm, 0);
360    EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm->be, 0);
361
362    if (!buf->bm->be->pixmap_get)
363      return 0;
364
365    return buf->bm->be->pixmap_get(buf->bm->data, buf->buffer_data);
366 }
367
368 EAPI void *
369 ecore_buffer_tbm_surface_get(Ecore_Buffer *buf)
370 {
371    EINA_SAFETY_ON_NULL_RETURN_VAL(buf, NULL);
372    EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm, NULL);
373    EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm->be, NULL);
374
375    if (!buf->bm->be->tbm_surface_get)
376      {
377         ERR("TBM is not supported\n");
378         return NULL;
379      }
380
381    return buf->bm->be->tbm_surface_get(buf->bm->data, buf->buffer_data);
382 }
383
384 EAPI Eina_Bool
385 ecore_buffer_size_get(Ecore_Buffer *buf, unsigned int *width, unsigned int *height)
386 {
387    EINA_SAFETY_ON_NULL_RETURN_VAL(buf, EINA_FALSE);
388
389    if (width) *width = buf->width;
390    if (height) *height = buf->height;
391
392    return EINA_TRUE;
393 }
394
395 EAPI unsigned int
396 ecore_buffer_format_get(Ecore_Buffer *buf)
397 {
398    EINA_SAFETY_ON_NULL_RETURN_VAL(buf, 0);
399
400    return buf->format;
401 }
402
403 EAPI unsigned int
404 ecore_buffer_flags_get(Ecore_Buffer *buf)
405 {
406    EINA_SAFETY_ON_NULL_RETURN_VAL(buf, 0);
407
408    return buf->flags;
409 }
410
411 EAPI void
412 ecore_buffer_free_callback_add(Ecore_Buffer *buf, Ecore_Buffer_Cb func, void *data)
413 {
414    EINA_SAFETY_ON_NULL_RETURN(buf);
415    EINA_SAFETY_ON_NULL_RETURN(func);
416
417    Ecore_Buffer_Cb_Data *free_cb;
418
419    free_cb = calloc(sizeof(Ecore_Buffer_Cb_Data), 1);
420    if (!free_cb)
421      return;
422
423    free_cb->cb = func;
424    free_cb->data = data;
425    buf->free_callbacks = eina_inlist_append(buf->free_callbacks, EINA_INLIST_GET(free_cb));
426 }
427
428 EAPI void
429 ecore_buffer_free_callback_remove(Ecore_Buffer *buf, Ecore_Buffer_Cb func, void *data)
430 {
431    Ecore_Buffer_Cb_Data *free_cb;
432
433    EINA_SAFETY_ON_NULL_RETURN(buf);
434    EINA_SAFETY_ON_NULL_RETURN(func);
435
436    if (buf->free_callbacks)
437      {
438         Eina_Inlist *itrn;
439         EINA_INLIST_FOREACH_SAFE(buf->free_callbacks, itrn, free_cb)
440           {
441              if (free_cb->cb == func && free_cb->data == data)
442                {
443                   buf->free_callbacks =
444                      eina_inlist_remove(buf->free_callbacks,
445                                         EINA_INLIST_GET(free_cb));
446                   free(free_cb);
447                }
448           }
449      }
450 }
451
452 const char *
453 _ecore_buffer_engine_name_get(Ecore_Buffer *buf)
454 {
455    EINA_SAFETY_ON_NULL_RETURN_VAL(buf, 0);
456    EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm, 0);
457    EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm->be, 0);
458
459    return buf->bm->be->name;
460 }
461
462 Ecore_Export_Type
463 _ecore_buffer_export(Ecore_Buffer *buf, int *id)
464 {
465    Ecore_Export_Type type = EXPORT_TYPE_INVALID;
466    int ret_id;
467
468    EINA_SAFETY_ON_NULL_RETURN_VAL(buf, type);
469    EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm, type);
470    EINA_SAFETY_ON_NULL_RETURN_VAL(buf->bm->be, type);
471
472    if (!buf->bm->be->buffer_export)
473      return type;
474
475    type = buf->bm->be->buffer_export(buf->bm->data, buf->buffer_data, &ret_id);
476
477    if (id) *id = ret_id;
478
479    return type;
480 }
481
482 Ecore_Buffer *
483 _ecore_buffer_import(const char *engine, int width, int height, Ecore_Buffer_Format format, Ecore_Export_Type type, int export_id, unsigned int flags)
484 {
485    Ecore_Buffer_Module *bm;
486    Ecore_Buffer *bo;
487    void *bo_data;
488
489    bm = _ecore_buffer_get_backend(engine);
490    if (!bm)
491      {
492         ERR("Filed to get Backend: %s", engine);
493         return NULL;
494      }
495
496    EINA_SAFETY_ON_NULL_RETURN_VAL(bm->be, NULL);
497
498    if (!bm->be->buffer_import)
499      {
500         ERR("Not supported import buffer");
501         return NULL;
502      }
503
504    bo = calloc(1, sizeof(Ecore_Buffer));
505    if (!bo)
506      return NULL;
507
508    bo_data = bm->be->buffer_import(bm->data, width, height, format, type, export_id, flags);
509    if (!bo_data)
510      {
511         free(bo);
512         return NULL;
513      }
514
515    bo->bm = bm;
516    bo->width = width;
517    bo->height = height;
518    bo->format = format;
519    bo->flags = flags;
520    bo->buffer_data = bo_data;
521
522    return bo;
523 }