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