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