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