Various patches are applied
[platform/framework/web/data-provider-master.git] / src / buffer_handler.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <unistd.h> /* access */
19 #include <sys/mman.h>
20 #include <errno.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <sys/shm.h>
25 #include <sys/ipc.h>
26 #include <string.h>
27 #include <stdlib.h>
28
29 #include <Ecore.h>
30 #include <Ecore_X.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xutil.h>
33 #include <X11/Xproto.h>
34 #include <X11/extensions/Xdamage.h>
35 #include <X11/extensions/Xfixes.h>
36 #include <X11/extensions/XShm.h>
37
38 #include <dri2.h>
39 #include <xf86drm.h>
40 #include <xf86drmMode.h>
41 #include <tbm_bufmgr.h>
42
43 #include <dlog.h>
44 #include <packet.h>
45 #include <livebox-errno.h>
46
47 #include "debug.h"
48 #include "conf.h"
49 #include "util.h"
50 #include "instance.h"
51 #include "package.h"
52 #include "client_life.h"
53 #include "client_rpc.h"
54 #include "buffer_handler.h"
55
56 struct buffer {
57         enum {
58                 CREATED = 0x00beef00,
59                 DESTROYED = 0x00dead00,
60         } state;
61         enum buffer_type type;
62         int refcnt;
63         void *info;
64         char data[];
65 };
66
67 /*!
68  * \brief Allocate this in the buffer->data.
69  */
70 struct gem_data {
71         DRI2Buffer *dri2_buffer;
72         unsigned int attachments[1];
73         tbm_bo pixmap_bo;
74         int count;
75         int buf_count;
76         int w;
77         int h;
78         int depth;
79         Pixmap pixmap;
80         void *data; /* Gem layer */
81         int refcnt;
82
83         void *compensate_data; /* Check the pitch value, copy this to data */
84 };
85
86 struct buffer_info
87 {
88         void *buffer;
89         char *id;
90
91         enum buffer_type type;
92
93         int w;
94         int h;
95         int pixel_size;
96         int is_loaded;
97
98         struct inst_info *inst;
99 };
100
101 static struct {
102         tbm_bufmgr slp_bufmgr;
103         int evt_base;
104         int err_base;
105         int fd;
106         Eina_List *pixmap_list;
107 } s_info = {
108         .slp_bufmgr = NULL,
109         .evt_base = 0,
110         .err_base = 0,
111         .fd = -1,
112         .pixmap_list = NULL,
113 };
114
115 HAPI struct buffer_info *buffer_handler_create(struct inst_info *inst, enum buffer_type type, int w, int h, int pixel_size)
116 {
117         struct buffer_info *info;
118
119         info = malloc(sizeof(*info));
120         if (!info) {
121                 ErrPrint("Heap: %s\n", strerror(errno));
122                 return NULL;
123         }
124
125         switch (type) {
126         case BUFFER_TYPE_SHM:
127                 info->id = strdup(SCHEMA_SHM "-1");
128                 if (!info->id) {
129                         ErrPrint("Heap: %s\n", strerror(errno));
130                         DbgFree(info);
131                         return NULL;
132                 }
133                 break;
134         case BUFFER_TYPE_FILE:
135                 info->id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
136                 if (!info->id) {
137                         ErrPrint("Heap: %s\n", strerror(errno));
138                         DbgFree(info);
139                         return NULL;
140                 }
141                 break;
142         case BUFFER_TYPE_PIXMAP:
143                 info->id = strdup(SCHEMA_PIXMAP "0");
144                 if (!info->id) {
145                         ErrPrint("Heap: %s\n", strerror(errno));
146                         DbgFree(info);
147                         return NULL;
148                 }
149                 break;
150         default:
151                 ErrPrint("Invalid type\n");
152                 DbgFree(info);
153                 return NULL;
154         }
155
156         info->w = w;
157         info->h = h;
158         info->pixel_size = pixel_size;
159         info->type = type;
160         info->is_loaded = 0;
161         info->inst = inst;
162         info->buffer = NULL;
163
164         DbgPrint("%dx%d size buffer is created\n", w, h);
165         return info;
166 }
167
168 static inline struct buffer *create_pixmap(struct buffer_info *info)
169 {
170         struct gem_data *gem;
171         struct buffer *buffer;
172         Display *disp;
173         Window parent;
174         XGCValues gcv;
175         GC gc;
176
177         disp = ecore_x_display_get();
178         if (!disp)
179                 return NULL;
180
181         parent = DefaultRootWindow(disp);
182
183         buffer = calloc(1, sizeof(*buffer) + sizeof(*gem));
184         if (!buffer) {
185                 ErrPrint("Heap: %s\n", strerror(errno));
186                 return NULL;
187         }
188
189         gem = (struct gem_data *)buffer->data;
190
191         buffer->type = BUFFER_TYPE_PIXMAP;
192         buffer->refcnt = 1;
193         buffer->state = CREATED;
194
195         DbgPrint("Canvas %dx%d - %d is created\n", info->w, info->h, info->pixel_size);
196
197         gem->attachments[0] = DRI2BufferFrontLeft;
198         gem->count = 1;
199         gem->w = info->w; /*!< This can be changed by DRI2GetBuffers */
200         gem->h = info->h; /*!< This can be changed by DRI2GetBuffers */
201         gem->depth = info->pixel_size;
202         /*!
203          * \NOTE
204          * Use the 24 Bits
205          * 32 Bits is not supported for video playing.
206          * But for the transparent background, use the 32 bits, and give up video.
207          */
208         gem->pixmap = XCreatePixmap(disp, parent, info->w, info->h, (info->pixel_size << 3));
209         if (gem->pixmap == (Pixmap)0) {
210                 ErrPrint("Failed to create a pixmap\n");
211                 DbgFree(buffer);
212                 return NULL;
213         }
214
215         /*!
216          * \note
217          * Clear pixmap
218          */
219         memset(&gcv, 0, sizeof(gcv));
220         gc = XCreateGC(disp, gem->pixmap, GCForeground, &gcv);
221         if (gc) {
222                 XFillRectangle(disp, gem->pixmap, gc, 0, 0, info->w, info->h);
223                 XSync(disp, False);
224                 XFreeGC(disp, gc);
225         } else {
226                 XSync(disp, False);
227                 ErrPrint("Unable to clear the pixmap\n");
228         }
229
230         DbgPrint("Pixmap:0x%X is created\n", gem->pixmap);
231         return buffer;
232 }
233
234 static inline int create_gem(struct buffer *buffer)
235 {
236         struct gem_data *gem;
237         Display *disp;
238
239         disp = ecore_x_display_get();
240         if (!disp) {
241                 ErrPrint("Failed to get display\n");
242                 return LB_STATUS_ERROR_IO;
243         }
244
245         gem = (struct gem_data *)buffer->data;
246
247         if (s_info.fd < 0) {
248                 gem->data = calloc(1, gem->w * gem->h * gem->depth);
249                 if (!gem->data) {
250                         ErrPrint("Heap: %s\n", strerror(errno));
251                         return LB_STATUS_ERROR_MEMORY;
252                 }
253
254                 DbgPrint("DRI2(gem) is not supported - Fallback to the S/W Backend\n");
255                 return LB_STATUS_SUCCESS;
256         }
257
258         DRI2CreateDrawable(disp, gem->pixmap);
259         DbgPrint("DRI2CreateDrawable is done\n");
260
261         gem->dri2_buffer = DRI2GetBuffers(disp, gem->pixmap,
262                                         &gem->w, &gem->h, gem->attachments, gem->count, &gem->buf_count);
263         if (!gem->dri2_buffer || !gem->dri2_buffer->name) {
264                 ErrPrint("Failed to get a gem buffer\n");
265                 DRI2DestroyDrawable(disp, gem->pixmap);
266                 return LB_STATUS_ERROR_FAULT;
267         }
268         DbgPrint("dri2_buffer: %p, name: %p, %dx%d\n",
269                                 gem->dri2_buffer, gem->dri2_buffer->name, gem->w, gem->h);
270         DbgPrint("dri2_buffer->pitch : %d, buf_count: %d\n",
271                                 gem->dri2_buffer->pitch, gem->buf_count);
272
273         /*!
274          * \How can I destroy this?
275          */
276         gem->pixmap_bo = tbm_bo_import(s_info.slp_bufmgr, gem->dri2_buffer->name);
277         if (!gem->pixmap_bo) {
278                 ErrPrint("Failed to import BO\n");
279                 DRI2DestroyDrawable(disp, gem->pixmap);
280                 return LB_STATUS_ERROR_FAULT;
281         }
282
283         if (gem->dri2_buffer->pitch != gem->w * gem->depth) {
284                 gem->compensate_data = calloc(1, gem->w * gem->h * gem->depth);
285                 if (!gem->compensate_data) {
286                         ErrPrint("Failed to allocate heap\n");
287                 } else {
288                         DbgPrint("Allocate compensate buffer %p(%dx%d %d)\n",
289                                                                 gem->compensate_data,
290                                                                 gem->w, gem->h, gem->depth);
291                 }
292         }
293
294         return LB_STATUS_SUCCESS;
295 }
296
297 static inline void *acquire_gem(struct buffer *buffer)
298 {
299         struct gem_data *gem;
300
301         if (!buffer)
302                 return NULL;
303
304         gem = (struct gem_data *)buffer->data;
305         if (s_info.fd < 0) {
306                 DbgPrint("GEM is not supported - Use the fake gem buffer\n");
307         } else {
308                 if (!gem->pixmap_bo) {
309                         DbgPrint("GEM is not created\n");
310                         return NULL;
311                 }
312
313                 if (!gem->data) {
314                         tbm_bo_handle handle;
315
316                         if (gem->refcnt) {
317                                 ErrPrint("Already acquired. but the buffer is not valid\n");
318                                 return NULL;
319                         }
320
321                         handle = tbm_bo_map(gem->pixmap_bo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE);
322                         gem->data = handle.ptr;
323                 }
324         }
325
326         gem->refcnt++;
327
328         /*!
329          * \note
330          * If there is a compensate canvas buffer,
331          * use it
332          */
333         return gem->compensate_data ? gem->compensate_data : gem->data;
334 }
335
336 static inline void release_gem(struct buffer *buffer)
337 {
338         struct gem_data *gem;
339
340         gem = (struct gem_data *)buffer->data;
341         if (s_info.fd >= 0 && !gem->pixmap_bo) {
342                 DbgPrint("GEM is not created\n");
343                 return;
344         }
345
346         if (!gem->data) {
347                 if (gem->refcnt > 0) {
348                         ErrPrint("Reference count is not valid %d\n", gem->refcnt);
349                         gem->refcnt = 0;
350                 }
351                 return;
352         }
353
354         gem->refcnt--;
355         if (gem->refcnt == 0) {
356                 if (s_info.fd < 0) {
357                         DbgPrint("S/W Gem buffer has no reference\n");
358                 } else {
359                         /*!
360                          * \note
361                          * Update the gem buffer using compensate data buffer if it is exists
362                          */
363                         if (gem->compensate_data) {
364                                 register int x;
365                                 register int y;
366                                 int *gem_pixel;
367                                 int *pixel;
368                                 int gap;
369
370                                 pixel = gem->compensate_data;
371                                 gem_pixel = gem->data;
372                                 gap = gem->dri2_buffer->pitch - (gem->w * gem->depth);
373
374                                 for (y = 0; y < gem->h; y++) {
375                                         for (x = 0; x < gem->w; x++)
376                                                 *gem_pixel++ = *pixel++;
377
378                                         gem_pixel = (int *)(((char *)gem_pixel) + gap);
379                                 }
380                         }
381
382                         if (gem->pixmap_bo)
383                                 tbm_bo_unmap(gem->pixmap_bo);
384
385                         gem->data = NULL;
386                 }
387         } else if (gem->refcnt < 0) {
388                 DbgPrint("Invalid refcnt: %d (reset)\n", gem->refcnt);
389                 gem->refcnt = 0;
390         }
391 }
392
393 static inline int destroy_pixmap(struct buffer *buffer)
394 {
395         struct gem_data *gem;
396
397         gem = (struct gem_data *)buffer->data;
398
399         if (gem->pixmap) {
400                 Display *disp;
401
402                 disp = ecore_x_display_get();
403                 if (!disp)
404                         return LB_STATUS_ERROR_IO;
405
406                 DbgPrint("Free pixmap 0x%X\n", gem->pixmap);
407                 XFreePixmap(disp, gem->pixmap);
408         }
409
410         buffer->state = DESTROYED;
411         DbgFree(buffer);
412         return LB_STATUS_SUCCESS;
413 }
414
415 static inline int destroy_gem(struct buffer *buffer)
416 {
417         struct gem_data *gem;
418
419         if (!buffer)
420                 return LB_STATUS_ERROR_INVALID;
421
422         /*!
423          * Forcely release the acquire_buffer.
424          */
425         gem = (struct gem_data *)buffer->data;
426         if (!gem)
427                 return LB_STATUS_ERROR_FAULT;
428
429         if (s_info.fd >= 0) {
430                 if (gem->compensate_data) {
431                         DbgPrint("Release compensate buffer %p\n", gem->compensate_data);
432                         free(gem->compensate_data);
433                         gem->compensate_data = NULL;
434                 }
435
436                 if (gem->pixmap_bo) {
437                         DbgPrint("unref pixmap bo\n");
438                         tbm_bo_unref(gem->pixmap_bo);
439                         gem->pixmap_bo = NULL;
440
441                         DbgPrint("DRI2DestroyDrawable\n");
442                         DRI2DestroyDrawable(ecore_x_display_get(), gem->pixmap);
443                 }
444         } else if (gem->data) {
445                 DbgPrint("Release fake gem buffer\n");
446                 DbgFree(gem->data);
447                 gem->data = NULL;
448         }
449
450         return LB_STATUS_SUCCESS;
451 }
452
453 static inline int load_file_buffer(struct buffer_info *info)
454 {
455         struct buffer *buffer;
456         double timestamp;
457         int size;
458         char *new_id;
459         int len;
460
461         len = strlen(IMAGE_PATH) + 40;
462         new_id = malloc(len);
463         if (!new_id) {
464                 ErrPrint("Heap: %s\n", strerror(errno));
465                 return LB_STATUS_ERROR_MEMORY;
466         }
467
468         timestamp = util_timestamp();
469         snprintf(new_id, len, SCHEMA_FILE "%s%lf", IMAGE_PATH, timestamp);
470
471         size = sizeof(*buffer) + info->w * info->h * info->pixel_size;
472         if (!size) {
473                 ErrPrint("Canvas buffer size is ZERO\n");
474                 DbgFree(new_id);
475                 return LB_STATUS_ERROR_INVALID;
476         }
477
478         buffer = calloc(1, size);
479         if (!buffer) {
480                 ErrPrint("Failed to allocate buffer\n");
481                 DbgFree(new_id);
482                 return LB_STATUS_ERROR_MEMORY;
483         }
484
485         buffer->type = BUFFER_TYPE_FILE;
486         buffer->refcnt = 0;
487         buffer->state = CREATED;
488         buffer->info = info;
489
490         DbgFree(info->id);
491         info->id = new_id;
492         info->buffer = buffer;
493         info->is_loaded = 1;
494
495         DbgPrint("FILE type %d created\n", size);
496         return LB_STATUS_SUCCESS;
497 }
498
499 static inline int load_shm_buffer(struct buffer_info *info)
500 {
501         int id;
502         int size;
503         struct buffer *buffer; /* Just for getting a size */
504         char *new_id;
505         int len;
506
507         size = info->w * info->h * info->pixel_size;
508         if (!size) {
509                 ErrPrint("Invalid buffer size\n");
510                 return LB_STATUS_ERROR_INVALID;
511         }
512
513         id = shmget(IPC_PRIVATE, size + sizeof(*buffer), IPC_CREAT | 0666);
514         if (id < 0) {
515                 ErrPrint("shmget: %s\n", strerror(errno));
516                 return LB_STATUS_ERROR_FAULT;
517         }
518
519         buffer = shmat(id, NULL, 0);
520         if (buffer == (void *)-1) {
521                 ErrPrint("%s shmat: %s\n", info->id, strerror(errno));
522
523                 if (shmctl(id, IPC_RMID, 0) < 0)
524                         ErrPrint("%s shmctl: %s\n", info->id, strerror(errno));
525
526                 return LB_STATUS_ERROR_FAULT;
527         }
528
529         buffer->type = BUFFER_TYPE_SHM;
530         buffer->refcnt = id;
531         buffer->state = CREATED; /*!< Needless */
532         buffer->info = NULL; /*!< This has not to be used, every process will see this. So, don't try to save anything on here */
533
534         len = strlen(SCHEMA_SHM) + 30; /* strlen("shm://") + 30 */
535
536         new_id = malloc(len);
537         if (!new_id) {
538                 ErrPrint("Heap: %s\n", strerror(errno));
539                 if (shmdt(buffer) < 0)
540                         ErrPrint("shmdt: %s\n", strerror(errno));
541
542                 if (shmctl(id, IPC_RMID, 0) < 0)
543                         ErrPrint("shmctl: %s\n", strerror(errno));
544
545                 return LB_STATUS_ERROR_MEMORY;
546         }
547
548         snprintf(new_id, len, SCHEMA_SHM "%d", id);
549
550         DbgFree(info->id);
551         info->id = new_id;
552         info->buffer = buffer;
553         info->is_loaded = 1;
554         return LB_STATUS_SUCCESS;
555 }
556
557 static inline int load_pixmap_buffer(struct buffer_info *info)
558 {
559         struct buffer *buffer;
560         struct gem_data *gem;
561         char *new_id;
562         int len;
563
564         /*!
565          * \NOTE
566          * Before call the buffer_handler_pixmap_ref function,
567          * You should make sure that the is_loaded value is toggled (1)
568          * Or the buffer_handler_pixmap_ref function will return NULL
569          */
570         info->is_loaded = 1;
571
572         if (info->buffer)
573                 DbgPrint("Buffer is already exists, but override it with new one\n");
574
575         buffer = buffer_handler_pixmap_ref(info);
576         if (!buffer) {
577                 DbgPrint("Failed to make a reference of a pixmap\n");
578                 info->is_loaded = 0;
579                 return LB_STATUS_ERROR_FAULT;
580         }
581
582         len = strlen(SCHEMA_PIXMAP) + 30; /* strlen("pixmap://") + 30 */
583         new_id = malloc(len);
584         if (!new_id) {
585                 info->is_loaded = 0;
586                 ErrPrint("Heap: %s\n", strerror(errno));
587                 buffer_handler_pixmap_unref(buffer);
588                 return LB_STATUS_ERROR_MEMORY;
589         }
590
591         DbgPrint("Releaseo old id (%s)\n", info->id);
592         DbgFree(info->id);
593         info->id = new_id;
594
595         gem = (struct gem_data *)buffer->data;
596         DbgPrint("gem pointer: %p\n", gem);
597
598         snprintf(info->id, len, SCHEMA_PIXMAP "%d", (int)gem->pixmap);
599         DbgPrint("info->id: %s\n", info->id);
600
601         return LB_STATUS_SUCCESS;
602 }
603
604 HAPI int buffer_handler_load(struct buffer_info *info)
605 {
606         int ret;
607
608         if (!info) {
609                 DbgPrint("buffer handler is nil\n");
610                 return LB_STATUS_ERROR_INVALID;
611         }
612
613         if (info->is_loaded) {
614                 DbgPrint("Buffer is already loaded\n");
615                 return LB_STATUS_SUCCESS;
616         }
617
618         switch (info->type) {
619         case BUFFER_TYPE_FILE:
620                 ret = load_file_buffer(info);
621                 break;
622         case BUFFER_TYPE_SHM:
623                 ret = load_shm_buffer(info);
624                 break;
625         case BUFFER_TYPE_PIXMAP:
626                 ret = load_pixmap_buffer(info);
627                 break;
628         default:
629                 ErrPrint("Invalid buffer\n");
630                 ret = LB_STATUS_ERROR_INVALID;
631                 break;
632         }
633
634         return ret;
635 }
636
637 static inline int unload_file_buffer(struct buffer_info *info)
638 {
639         const char *path;
640         char *new_id;
641
642         new_id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
643         if (!new_id) {
644                 ErrPrint("Heap: %s\n", strerror(errno));
645                 return LB_STATUS_ERROR_MEMORY;
646         }
647
648         DbgFree(info->buffer);
649         info->buffer = NULL;
650
651         path = util_uri_to_path(info->id);
652         if (path && unlink(path) < 0)
653                 ErrPrint("unlink: %s\n", strerror(errno));
654
655         DbgFree(info->id);
656         info->id = new_id;
657         return LB_STATUS_SUCCESS;
658 }
659
660 static inline int unload_shm_buffer(struct buffer_info *info)
661 {
662         int id;
663         char *new_id;
664
665         new_id = strdup(SCHEMA_SHM "-1");
666         if (!new_id) {
667                 ErrPrint("Heap: %s\n", strerror(errno));
668                 return LB_STATUS_ERROR_MEMORY;
669         }
670
671         if (sscanf(info->id, SCHEMA_SHM "%d", &id) != 1) {
672                 ErrPrint("%s Invalid ID\n", info->id);
673                 DbgFree(new_id);
674                 return LB_STATUS_ERROR_INVALID;
675         }
676
677         if (id < 0) {
678                 ErrPrint("(%s) Invalid id: %d\n", info->id, id);
679                 DbgFree(new_id);
680                 return LB_STATUS_ERROR_INVALID;
681         }
682
683         if (shmdt(info->buffer) < 0)
684                 ErrPrint("Detach shm: %s\n", strerror(errno));
685
686         if (shmctl(id, IPC_RMID, 0) < 0)
687                 ErrPrint("Remove shm: %s\n", strerror(errno));
688
689         info->buffer = NULL;
690
691         DbgFree(info->id);
692         info->id = new_id;
693         return LB_STATUS_SUCCESS;
694 }
695
696 static inline int unload_pixmap_buffer(struct buffer_info *info)
697 {
698         int id;
699         char *new_id;
700
701         new_id = strdup(SCHEMA_PIXMAP "0");
702         if (!new_id) {
703                 ErrPrint("Heap: %s\n", strerror(errno));
704                 return LB_STATUS_ERROR_MEMORY;
705         }
706
707         if (sscanf(info->id, SCHEMA_PIXMAP "%d", &id) != 1) {
708                 ErrPrint("Invalid ID (%s)\n", info->id);
709                 DbgFree(new_id);
710                 return LB_STATUS_ERROR_INVALID;
711         }
712
713         if (id == 0) {
714                 ErrPrint("(%s) Invalid id: %d\n", info->id, id);
715                 DbgFree(new_id);
716                 return LB_STATUS_ERROR_INVALID;
717         }
718
719         /*!
720          * Decrease the reference counter.
721          */
722         buffer_handler_pixmap_unref(info->buffer);
723
724         /*!
725          * \note
726          * Just clear the info->buffer.
727          * It will be reallocated again.
728          */
729         info->buffer = NULL;
730
731         DbgFree(info->id);
732         info->id = new_id;
733         return LB_STATUS_SUCCESS;
734 }
735
736 HAPI int buffer_handler_unload(struct buffer_info *info)
737 {
738         int ret;
739
740         if (!info) {
741                 DbgPrint("buffer handler is nil\n");
742                 return LB_STATUS_ERROR_INVALID;
743         }
744
745         if (!info->is_loaded) {
746                 ErrPrint("Buffer is not loaded\n");
747                 return LB_STATUS_ERROR_INVALID;
748         }
749
750         switch (info->type) {
751         case BUFFER_TYPE_FILE:
752                 ret = unload_file_buffer(info);
753                 break;
754         case BUFFER_TYPE_SHM:
755                 ret = unload_shm_buffer(info);
756                 break;
757         case BUFFER_TYPE_PIXMAP:
758                 ret = unload_pixmap_buffer(info);
759                 break;
760         default:
761                 ErrPrint("Invalid buffer\n");
762                 ret = LB_STATUS_ERROR_INVALID;
763                 break;
764         }
765
766         if (ret == 0)
767                 info->is_loaded = 0;
768
769         return ret;
770 }
771
772 HAPI int buffer_handler_destroy(struct buffer_info *info)
773 {
774         Eina_List *l;
775         struct buffer *buffer;
776
777         if (!info) {
778                 DbgPrint("Buffer is not created yet. info is nil\n");
779                 return LB_STATUS_SUCCESS;
780         }
781
782         EINA_LIST_FOREACH(s_info.pixmap_list, l, buffer) {
783                 if (buffer->info == info)
784                         buffer->info = NULL;
785         }
786
787         buffer_handler_unload(info);
788         DbgFree(info->id);
789         DbgFree(info);
790         return LB_STATUS_SUCCESS;
791 }
792
793 HAPI const char *buffer_handler_id(const struct buffer_info *info)
794 {
795         return info ? info->id : "";
796 }
797
798 HAPI enum buffer_type buffer_handler_type(const struct buffer_info *info)
799 {
800         return info ? info->type : BUFFER_TYPE_ERROR;
801 }
802
803 HAPI void *buffer_handler_fb(struct buffer_info *info)
804 {
805         struct buffer *buffer;
806
807         if (!info)
808                 return NULL;
809
810         buffer = info->buffer;
811
812         if (info->type == BUFFER_TYPE_PIXMAP) {
813                 void *canvas;
814                 int ret;
815
816                 /*!
817                  */
818                 canvas = buffer_handler_pixmap_acquire_buffer(info);
819                 ret = buffer_handler_pixmap_release_buffer(canvas);
820                 DbgPrint("Canvas %p(%d) (released but still in use)\n", canvas, ret);
821                 return canvas;
822         }
823
824         return buffer->data;
825 }
826
827 HAPI int buffer_handler_pixmap(const struct buffer_info *info)
828 {
829         struct buffer *buf;
830         struct gem_data *gem;
831
832         if (!info) {
833                 ErrPrint("Inavlid buffer handler\n");
834                 return 0;
835         }
836
837         if (info->type != BUFFER_TYPE_PIXMAP) {
838                 ErrPrint("Invalid buffer type\n");
839                 return 0;
840         }
841
842         buf = (struct buffer *)info->buffer;
843         if (!buf) {
844                 ErrPrint("Invalid buffer data\n");
845                 return 0;
846         }
847
848         gem = (struct gem_data *)buf->data;
849         return gem->pixmap;
850 }
851
852 HAPI void *buffer_handler_pixmap_acquire_buffer(struct buffer_info *info)
853 {
854         struct buffer *buffer;
855
856         if (!info || !info->is_loaded) {
857                 ErrPrint("Buffer is not loaded\n");
858                 return NULL;
859         }
860
861         buffer = buffer_handler_pixmap_ref(info);
862         if (!buffer)
863                 return NULL;
864
865         return acquire_gem(buffer);
866 }
867
868 HAPI void *buffer_handler_pixmap_buffer(struct buffer_info *info)
869 {
870         struct buffer *buffer;
871         struct gem_data *gem;
872
873         if (!info)
874                 return NULL;
875
876         if (!info->is_loaded) {
877                 ErrPrint("Buffer is not loaded\n");
878                 return NULL;
879         }
880
881         buffer = info->buffer;
882         if (!buffer)
883                 return NULL;
884
885         gem = (struct gem_data *)buffer->data;
886         return gem->compensate_data ? gem->compensate_data : gem->data;
887 }
888
889 /*!
890  * \return "buffer" object (Not the buffer_info)
891  */
892 HAPI void *buffer_handler_pixmap_ref(struct buffer_info *info)
893 {
894         struct buffer *buffer;
895
896         if (!info->is_loaded) {
897                 ErrPrint("Buffer is not loaded\n");
898                 return NULL;
899         }
900
901         if (info->type != BUFFER_TYPE_PIXMAP) {
902                 ErrPrint("Buffer type is not matched\n");
903                 return NULL;
904         }
905
906         buffer = info->buffer;
907         if (!buffer) {
908                 int need_gem = 1;
909
910                 buffer = create_pixmap(info);
911                 if (!buffer) {
912                         DbgPrint("Failed to create a pixmap\n");
913                         return NULL;
914                 }
915
916                 info->buffer = buffer;
917
918                 if (info->inst) {
919                         struct pkg_info *pkg;
920
921                         if (instance_lb_buffer(info->inst) == info) {
922                                 pkg = instance_package(info->inst);
923                                 if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
924                                         DbgPrint("Doesn't need to create gem for LB\n");
925                                         need_gem = 0;
926                                 }
927                         } else if (instance_pd_buffer(info->inst) == info) {
928                                 pkg = instance_package(info->inst);
929                                 if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
930                                         DbgPrint("Doesn't need to create gem for PD\n");
931                                         need_gem = 0;
932                                 }
933                         }
934                 }
935
936                 if (need_gem)
937                         create_gem(buffer);
938
939         } else if (buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
940                 ErrPrint("Invalid buffer\n");
941                 return NULL;
942         } else if (buffer->refcnt > 0) {
943                 buffer->refcnt++;
944                 return buffer;
945         }
946
947         s_info.pixmap_list = eina_list_append(s_info.pixmap_list, buffer);
948         return buffer;
949 }
950
951 /*!
952  * \return "buffer"
953  */
954 HAPI void *buffer_handler_pixmap_find(int pixmap)
955 {
956         struct buffer *buffer;
957         struct gem_data *gem;
958         Eina_List *l;
959         Eina_List *n;
960
961         if (pixmap == 0)
962                 return NULL;
963
964         EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
965                 if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
966                         s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
967                         DbgPrint("Invalid buffer (List Removed: %p)\n", buffer);
968                         continue;
969                 }
970
971                 gem = (struct gem_data *)buffer->data;
972                 if (gem->pixmap == pixmap)
973                         return buffer;
974         }
975
976         return NULL;
977 }
978
979 HAPI int buffer_handler_pixmap_release_buffer(void *canvas)
980 {
981         struct buffer *buffer;
982         struct gem_data *gem;
983         Eina_List *l;
984         Eina_List *n;
985         void *_ptr;
986
987         if (!canvas)
988                 return LB_STATUS_ERROR_INVALID;
989
990         EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
991                 if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
992                         s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
993                         continue;
994                 }
995
996                 gem = (struct gem_data *)buffer->data;
997                 _ptr = gem->compensate_data ? gem->compensate_data : gem->data;
998
999                 if (!_ptr)
1000                         continue;
1001
1002                 if (_ptr == canvas) {
1003                         release_gem(buffer);
1004                         buffer_handler_pixmap_unref(buffer);
1005                         return LB_STATUS_SUCCESS;
1006                 }
1007         }
1008
1009         return LB_STATUS_ERROR_NOT_EXIST;
1010 }
1011
1012 /*!
1013  * \note
1014  *
1015  * \return Return NULL if the buffer is in still uses.
1016  *         Return buffer_ptr if it needs to destroy
1017  */
1018 HAPI int buffer_handler_pixmap_unref(void *buffer_ptr)
1019 {
1020         struct buffer *buffer = buffer_ptr;
1021         struct buffer_info *info;
1022
1023         buffer->refcnt--;
1024         if (buffer->refcnt > 0)
1025                 return LB_STATUS_SUCCESS; /* Return NULL means, gem buffer still in use */
1026
1027         s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
1028
1029         info = buffer->info;
1030
1031         if (destroy_gem(buffer) < 0)
1032                 ErrPrint("Failed to destroy gem buffer\n");
1033
1034         if (destroy_pixmap(buffer) < 0)
1035                 ErrPrint("Failed to destroy pixmap\n");
1036
1037         if (info && info->buffer == buffer)
1038                 info->buffer = NULL;
1039
1040         return LB_STATUS_SUCCESS;
1041 }
1042
1043 HAPI int buffer_handler_is_loaded(const struct buffer_info *info)
1044 {
1045         return info ? info->is_loaded : 0;
1046 }
1047
1048 HAPI void buffer_handler_update_size(struct buffer_info *info, int w, int h)
1049 {
1050         if (!info)
1051                 return;
1052
1053         info->w = w;
1054         info->h = h;
1055 }
1056
1057 HAPI int buffer_handler_resize(struct buffer_info *info, int w, int h)
1058 {
1059         int ret;
1060
1061         if (!info) {
1062                 ErrPrint("Invalid handler\n");
1063                 return LB_STATUS_ERROR_INVALID;
1064         }
1065
1066         if (info->w == w && info->h == h) {
1067                 DbgPrint("No changes\n");
1068                 return LB_STATUS_SUCCESS;
1069         }
1070
1071         buffer_handler_update_size(info, w, h);
1072
1073         if (!info->is_loaded) {
1074                 DbgPrint("Not yet loaded, just update the size [%dx%d]\n", w, h);
1075                 return LB_STATUS_SUCCESS;
1076         }
1077
1078         ret = buffer_handler_unload(info);
1079         if (ret < 0)
1080                 ErrPrint("Unload: %d\n", ret);
1081
1082         ret = buffer_handler_load(info);
1083         if (ret < 0)
1084                 ErrPrint("Load: %d\n", ret);
1085
1086         return LB_STATUS_SUCCESS;
1087 }
1088
1089 HAPI int buffer_handler_get_size(struct buffer_info *info, int *w, int *h)
1090 {
1091         if (!info)
1092                 return LB_STATUS_ERROR_INVALID;
1093
1094         if (w)
1095                 *w = info->w;
1096         if (h)
1097                 *h = info->h;
1098
1099         return LB_STATUS_SUCCESS;
1100 }
1101
1102 HAPI struct inst_info *buffer_handler_instance(struct buffer_info *info)
1103 {
1104         return info->inst;
1105 }
1106
1107 /*!
1108  * \note
1109  * Only for used S/W Backend
1110  */
1111 static inline int sync_for_pixmap(struct buffer *buffer)
1112 {
1113         XShmSegmentInfo si;
1114         XImage *xim;
1115         GC gc;
1116         Display *disp;
1117         struct gem_data *gem;
1118         Screen *screen;
1119         Visual *visual;
1120
1121         if (buffer->state != CREATED) {
1122                 ErrPrint("Invalid state of a FB\n");
1123                 return LB_STATUS_ERROR_INVALID;
1124         }
1125
1126         if (buffer->type != BUFFER_TYPE_PIXMAP) {
1127                 DbgPrint("Invalid buffer\n");
1128                 return LB_STATUS_SUCCESS;
1129         }
1130
1131         disp = ecore_x_display_get();
1132         if (!disp) {
1133                 ErrPrint("Failed to get a display\n");
1134                 return LB_STATUS_ERROR_FAULT;
1135         }
1136
1137         gem = (struct gem_data *)buffer->data;
1138         if (gem->w == 0 || gem->h == 0) {
1139                 DbgPrint("Nothing can be sync\n");
1140                 return LB_STATUS_SUCCESS;
1141         }
1142
1143         si.shmid = shmget(IPC_PRIVATE, gem->w * gem->h * gem->depth, IPC_CREAT | 0666);
1144         if (si.shmid < 0) {
1145                 ErrPrint("shmget: %s\n", strerror(errno));
1146                 return LB_STATUS_ERROR_FAULT;
1147         }
1148
1149         si.readOnly = False;
1150         si.shmaddr = shmat(si.shmid, NULL, 0);
1151         if (si.shmaddr == (void *)-1) {
1152                 if (shmctl(si.shmid, IPC_RMID, 0) < 0)
1153                         ErrPrint("shmctl: %s\n", strerror(errno));
1154                 return LB_STATUS_ERROR_FAULT;
1155         }
1156
1157         screen = DefaultScreenOfDisplay(disp);
1158         visual = DefaultVisualOfScreen(screen);
1159         /*!
1160          * \NOTE
1161          * XCreatePixmap can only uses 24 bits depth only.
1162          */
1163         xim = XShmCreateImage(disp, visual, (gem->depth << 3), ZPixmap, NULL, &si, gem->w, gem->h);
1164         if (xim == NULL) {
1165                 if (shmdt(si.shmaddr) < 0)
1166                         ErrPrint("shmdt: %s\n", strerror(errno));
1167
1168                 if (shmctl(si.shmid, IPC_RMID, 0) < 0)
1169                         ErrPrint("shmctl: %s\n", strerror(errno));
1170                 return LB_STATUS_ERROR_FAULT;
1171         }
1172
1173         xim->data = si.shmaddr;
1174         XShmAttach(disp, &si);
1175         XSync(disp, False);
1176
1177         gc = XCreateGC(disp, gem->pixmap, 0, NULL);
1178         if (!gc) {
1179                 XShmDetach(disp, &si);
1180                 XDestroyImage(xim);
1181
1182                 if (shmdt(si.shmaddr) < 0)
1183                         ErrPrint("shmdt: %s\n", strerror(errno));
1184
1185                 if (shmctl(si.shmid, IPC_RMID, 0) < 0)
1186                         ErrPrint("shmctl: %s\n", strerror(errno));
1187
1188                 return LB_STATUS_ERROR_FAULT;
1189         }
1190
1191         memcpy(xim->data, gem->data, gem->w * gem->h * gem->depth);
1192
1193         /*!
1194          * \note Do not send the event.
1195          *       Instead of X event, master will send the updated event to the viewer
1196          */
1197         XShmPutImage(disp, gem->pixmap, gc, xim, 0, 0, 0, 0, gem->w, gem->h, False);
1198         XSync(disp, False);
1199
1200         XFreeGC(disp, gc);
1201         XShmDetach(disp, &si);
1202         XDestroyImage(xim);
1203
1204         if (shmdt(si.shmaddr) < 0)
1205                 ErrPrint("shmdt: %s\n", strerror(errno));
1206
1207         if (shmctl(si.shmid, IPC_RMID, 0) < 0)
1208                 ErrPrint("shmctl: %s\n", strerror(errno));
1209
1210         return LB_STATUS_SUCCESS;
1211 }
1212
1213 HAPI void buffer_handler_flush(struct buffer_info *info)
1214 {
1215         int fd;
1216         int size;
1217         struct buffer *buffer;
1218
1219         if (!info || !info->buffer)
1220                 return;
1221
1222         buffer = info->buffer;
1223
1224         if (buffer->type == BUFFER_TYPE_PIXMAP) {
1225                 if (s_info.fd > 0) {
1226                         XRectangle rect;
1227                         XserverRegion region;
1228
1229                         rect.x = 0;
1230                         rect.y = 0;
1231                         rect.width = info->w;
1232                         rect.height = info->h;
1233
1234                         region = XFixesCreateRegion(ecore_x_display_get(), &rect, 1);
1235                         XDamageAdd(ecore_x_display_get(), buffer_handler_pixmap(info), region);
1236                         XFixesDestroyRegion(ecore_x_display_get(), region);
1237                         XFlush(ecore_x_display_get());
1238                 } else {
1239                         if (sync_for_pixmap(buffer) < 0)
1240                                 ErrPrint("Failed to sync via S/W Backend\n");
1241                 }
1242         } else if (buffer->type == BUFFER_TYPE_FILE) {
1243                 fd = open(util_uri_to_path(info->id), O_WRONLY | O_CREAT, 0644);
1244                 if (fd < 0) {
1245                         ErrPrint("%s open falied: %s\n", util_uri_to_path(info->id), strerror(errno));
1246                         return;
1247                 }
1248
1249                 size = info->w * info->h * info->pixel_size;
1250                 if (write(fd, info->buffer, size) != size)
1251                         ErrPrint("Write is not completed: %s\n", strerror(errno));
1252
1253                 close(fd);
1254         } else {
1255                 DbgPrint("Flush nothing\n");
1256         }
1257 }
1258
1259 HAPI int buffer_handler_init(void)
1260 {
1261         int dri2Major, dri2Minor;
1262         char *driverName, *deviceName;
1263         drm_magic_t magic;
1264
1265         if (!DRI2QueryExtension(ecore_x_display_get(), &s_info.evt_base, &s_info.err_base)) {
1266                 DbgPrint("DRI2 is not supported\n");
1267                 return LB_STATUS_SUCCESS;
1268         }
1269
1270         if (!DRI2QueryVersion(ecore_x_display_get(), &dri2Major, &dri2Minor)) {
1271                 DbgPrint("DRI2 is not supported\n");
1272                 s_info.evt_base = 0;
1273                 s_info.err_base = 0;
1274                 return LB_STATUS_SUCCESS;
1275         }
1276
1277         if (!DRI2Connect(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), &driverName, &deviceName)) {
1278                 DbgPrint("DRI2 is not supported\n");
1279                 s_info.evt_base = 0;
1280                 s_info.err_base = 0;
1281                 return LB_STATUS_SUCCESS;
1282         }
1283
1284         DbgPrint("Open: %s (driver: %s)", deviceName, driverName);
1285
1286         if (USE_SW_BACKEND) {
1287                 DbgPrint("Fallback to the S/W Backend\n");
1288                 s_info.evt_base = 0;
1289                 s_info.err_base = 0;
1290                 DbgFree(deviceName);
1291                 DbgFree(driverName);
1292                 return LB_STATUS_SUCCESS;
1293         }
1294
1295         s_info.fd = open(deviceName, O_RDWR);
1296         DbgFree(deviceName);
1297         DbgFree(driverName);
1298         if (s_info.fd < 0) {
1299                 DbgPrint("Failed to open a drm device: (%s)\n", strerror(errno));
1300                 s_info.evt_base = 0;
1301                 s_info.err_base = 0;
1302                 return LB_STATUS_SUCCESS;
1303         }
1304
1305         drmGetMagic(s_info.fd, &magic);
1306         DbgPrint("DRM Magic: 0x%X\n", magic);
1307         if (!DRI2Authenticate(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), (unsigned int)magic)) {
1308                 DbgPrint("Failed to do authenticate for DRI2\n");
1309                 close(s_info.fd);
1310                 s_info.fd = -1;
1311                 s_info.evt_base = 0;
1312                 s_info.err_base = 0;
1313                 return LB_STATUS_SUCCESS;
1314         }
1315
1316         s_info.slp_bufmgr = tbm_bufmgr_init(s_info.fd);
1317         if (!s_info.slp_bufmgr) {
1318                 DbgPrint("Failed to init bufmgr\n");
1319                 close(s_info.fd);
1320                 s_info.fd = -1;
1321                 s_info.evt_base = 0;
1322                 s_info.err_base = 0;
1323                 return LB_STATUS_SUCCESS;
1324         }
1325
1326         return LB_STATUS_SUCCESS;
1327 }
1328
1329 HAPI int buffer_handler_fini(void)
1330 {
1331         if (s_info.fd >= 0) {
1332                 close(s_info.fd);
1333                 s_info.fd = -1;
1334         }
1335
1336         if (s_info.slp_bufmgr) {
1337                 tbm_bufmgr_deinit(s_info.slp_bufmgr);
1338                 s_info.slp_bufmgr = NULL;
1339         }
1340
1341         return LB_STATUS_SUCCESS;
1342 }
1343
1344 /* End of a file */