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