2 * Copyright 2013 Samsung Electronics Co., Ltd
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
8 * http://floralicense.org/license/
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.
18 #include <unistd.h> /* access */
21 #include <sys/types.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>
40 #include <xf86drmMode.h>
41 #include <tbm_bufmgr.h>
45 #include <livebox-errno.h>
52 #include "client_life.h"
53 #include "client_rpc.h"
54 #include "buffer_handler.h"
55 #include "script_handler.h" // Reverse dependency. must has to be broken
60 DESTROYED = 0x00dead00
62 enum buffer_type type;
69 * \brief Allocate this in the buffer->data.
72 DRI2Buffer *dri2_buffer;
73 unsigned int attachments[1];
81 void *data; /* Gem layer */
84 void *compensate_data; /* Check the pitch value, copy this to data */
94 enum buffer_type type;
101 struct inst_info *inst;
106 tbm_bufmgr slp_bufmgr;
110 Eina_List *pixmap_list;
119 static int destroy_lock_file(struct buffer_info *info)
122 return LB_STATUS_ERROR_INVALID;
126 return LB_STATUS_ERROR_INVALID;
129 if (close(info->lock_fd) < 0) {
130 ErrPrint("close: %s\n", strerror(errno));
134 if (unlink(info->lock) < 0) {
135 ErrPrint("unlink: %s\n", strerror(errno));
140 return LB_STATUS_SUCCESS;
143 static int create_lock_file(struct buffer_info *info)
148 char target[3] = "pd";
151 return LB_STATUS_ERROR_INVALID;
154 id = instance_id(info->inst);
156 return LB_STATUS_ERROR_INVALID;
160 file = malloc(len + 20);
162 ErrPrint("Heap: %s\n", strerror(errno));
163 return LB_STATUS_ERROR_MEMORY;
166 if (script_handler_buffer_info(instance_pd_script(info->inst)) != info && instance_pd_buffer(info->inst) != info) {
169 /* target[2] = '\0'; // We already have this ;) */
172 snprintf(file, len + 20, "%s.%s.lck", util_uri_to_path(id), target);
173 info->lock_fd = open(file, O_WRONLY|O_CREAT, 0644);
174 if (info->lock_fd < 0) {
175 ErrPrint("open: %s\n", strerror(errno));
177 return LB_STATUS_ERROR_IO;
181 return LB_STATUS_SUCCESS;
184 static int do_buffer_lock(struct buffer_info *buffer)
189 if (buffer->lock_fd < 0) {
190 return LB_STATUS_SUCCESS;
193 flock.l_type = F_WRLCK;
194 flock.l_whence = SEEK_SET;
197 flock.l_pid = getpid();
200 ret = fcntl(buffer->lock_fd, F_SETLKW, &flock);
203 ErrPrint("fcntl: %s\n", strerror(errno));
205 } while (ret == EINTR);
207 return LB_STATUS_SUCCESS;
210 static int do_buffer_unlock(struct buffer_info *buffer)
215 if (buffer->lock_fd < 0) {
216 return LB_STATUS_SUCCESS;
219 flock.l_type = F_UNLCK;
220 flock.l_whence = SEEK_SET;
223 flock.l_pid = getpid();
226 ret = fcntl(buffer->lock_fd, F_SETLKW, &flock);
229 ErrPrint("fcntl: %s\n", strerror(errno));
231 } while (ret == EINTR);
233 return LB_STATUS_SUCCESS;
236 static inline struct buffer *create_pixmap(struct buffer_info *info)
238 struct gem_data *gem;
239 struct buffer *buffer;
245 disp = ecore_x_display_get();
250 parent = DefaultRootWindow(disp);
252 buffer = calloc(1, sizeof(*buffer) + sizeof(*gem));
254 ErrPrint("Heap: %s\n", strerror(errno));
258 gem = (struct gem_data *)buffer->data;
260 buffer->type = BUFFER_TYPE_PIXMAP;
262 buffer->state = CREATED;
264 gem->attachments[0] = DRI2BufferFrontLeft;
266 gem->w = info->w; /*!< This can be changed by DRI2GetBuffers */
267 gem->h = info->h; /*!< This can be changed by DRI2GetBuffers */
268 gem->depth = info->pixel_size;
272 * 32 Bits is not supported for video playing.
273 * But for the transparent background, use the 32 bits, and give up video.
275 gem->pixmap = XCreatePixmap(disp, parent, info->w, info->h, (info->pixel_size << 3));
276 if (gem->pixmap == (Pixmap)0) {
277 ErrPrint("Failed to create a pixmap\n");
286 memset(&gcv, 0, sizeof(gcv));
287 gc = XCreateGC(disp, gem->pixmap, GCForeground, &gcv);
289 XFillRectangle(disp, gem->pixmap, gc, 0, 0, info->w, info->h);
294 ErrPrint("Unable to clear the pixmap\n");
300 static inline int create_gem(struct buffer *buffer)
302 struct gem_data *gem;
305 disp = ecore_x_display_get();
307 ErrPrint("Failed to get display\n");
308 return LB_STATUS_ERROR_IO;
311 gem = (struct gem_data *)buffer->data;
314 gem->data = calloc(1, gem->w * gem->h * gem->depth);
316 ErrPrint("Heap: %s\n", strerror(errno));
317 return LB_STATUS_ERROR_MEMORY;
320 ErrPrint("DRI2(gem) is not supported - Fallback to the S/W Backend\n");
321 return LB_STATUS_SUCCESS;
324 DRI2CreateDrawable(disp, gem->pixmap);
326 gem->dri2_buffer = DRI2GetBuffers(disp, gem->pixmap,
327 &gem->w, &gem->h, gem->attachments, gem->count, &gem->buf_count);
328 if (!gem->dri2_buffer || !gem->dri2_buffer->name) {
329 ErrPrint("Failed to get a gem buffer\n");
330 DRI2DestroyDrawable(disp, gem->pixmap);
331 return LB_STATUS_ERROR_FAULT;
334 * \How can I destroy this?
336 gem->pixmap_bo = tbm_bo_import(s_info.slp_bufmgr, gem->dri2_buffer->name);
337 if (!gem->pixmap_bo) {
338 ErrPrint("Failed to import BO\n");
339 DRI2DestroyDrawable(disp, gem->pixmap);
340 return LB_STATUS_ERROR_FAULT;
343 if (gem->dri2_buffer->pitch != gem->w * gem->depth) {
344 gem->compensate_data = calloc(1, gem->w * gem->h * gem->depth);
345 if (!gem->compensate_data) {
346 ErrPrint("Failed to allocate heap\n");
350 DbgPrint("dri2_buffer: %p, name: %p, %dx%d, pitch: %d, buf_count: %d, depth: %d, compensate: %p\n",
351 gem->dri2_buffer, gem->dri2_buffer->name, gem->w, gem->h,
352 gem->dri2_buffer->pitch, gem->buf_count, gem->depth, gem->compensate_data);
354 return LB_STATUS_SUCCESS;
357 static inline void *acquire_gem(struct buffer *buffer)
359 struct gem_data *gem;
365 gem = (struct gem_data *)buffer->data;
367 ErrPrint("GEM is not supported - Use the fake gem buffer\n");
369 if (!gem->pixmap_bo) {
370 ErrPrint("GEM is not created\n");
375 tbm_bo_handle handle;
378 ErrPrint("Already acquired. but the buffer is not valid\n");
382 handle = tbm_bo_map(gem->pixmap_bo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE);
383 gem->data = handle.ptr;
391 * If there is a compensate canvas buffer,
394 return gem->compensate_data ? gem->compensate_data : gem->data;
397 static inline void release_gem(struct buffer *buffer)
399 struct gem_data *gem;
401 gem = (struct gem_data *)buffer->data;
402 if (s_info.fd >= 0 && !gem->pixmap_bo) {
403 ErrPrint("GEM is not created\n");
408 if (gem->refcnt > 0) {
409 ErrPrint("Reference count is not valid %d\n", gem->refcnt);
416 if (gem->refcnt == 0) {
418 DbgPrint("S/W Gem buffer has no reference\n");
422 * Update the gem buffer using compensate data buffer if it is exists
424 if (gem->compensate_data) {
431 pixel = gem->compensate_data;
432 gem_pixel = gem->data;
433 gap = gem->dri2_buffer->pitch - (gem->w * gem->depth);
435 for (y = 0; y < gem->h; y++) {
436 for (x = 0; x < gem->w; x++) {
437 *gem_pixel++ = *pixel++;
440 gem_pixel = (int *)(((char *)gem_pixel) + gap);
444 if (gem->pixmap_bo) {
445 tbm_bo_unmap(gem->pixmap_bo);
450 } else if (gem->refcnt < 0) {
451 ErrPrint("Invalid refcnt: %d (reset)\n", gem->refcnt);
456 static inline int destroy_pixmap(struct buffer *buffer)
458 struct gem_data *gem;
460 gem = (struct gem_data *)buffer->data;
465 disp = ecore_x_display_get();
467 return LB_STATUS_ERROR_IO;
470 DbgPrint("pixmap %lu\n", gem->pixmap);
471 XFreePixmap(disp, gem->pixmap);
474 buffer->state = DESTROYED;
476 return LB_STATUS_SUCCESS;
479 static inline int destroy_gem(struct buffer *buffer)
481 struct gem_data *gem;
484 return LB_STATUS_ERROR_INVALID;
488 * Forcely release the acquire_buffer.
490 gem = (struct gem_data *)buffer->data;
492 return LB_STATUS_ERROR_FAULT;
495 if (s_info.fd >= 0) {
496 if (gem->compensate_data) {
497 DbgPrint("Release compensate buffer %p\n", gem->compensate_data);
498 DbgFree(gem->compensate_data);
499 gem->compensate_data = NULL;
502 if (gem->pixmap_bo) {
503 DbgPrint("unref pixmap bo\n");
504 tbm_bo_unref(gem->pixmap_bo);
505 gem->pixmap_bo = NULL;
507 DRI2DestroyDrawable(ecore_x_display_get(), gem->pixmap);
509 } else if (gem->data) {
510 DbgPrint("Release fake gem buffer\n");
515 return LB_STATUS_SUCCESS;
518 static inline int load_file_buffer(struct buffer_info *info)
520 struct buffer *buffer;
526 len = strlen(IMAGE_PATH) + 40;
527 new_id = malloc(len);
529 ErrPrint("Heap: %s\n", strerror(errno));
530 return LB_STATUS_ERROR_MEMORY;
533 timestamp = util_timestamp();
534 snprintf(new_id, len, SCHEMA_FILE "%s%lf", IMAGE_PATH, timestamp);
536 size = sizeof(*buffer) + info->w * info->h * info->pixel_size;
538 ErrPrint("Canvas buffer size is ZERO\n");
540 return LB_STATUS_ERROR_INVALID;
543 buffer = calloc(1, size);
545 ErrPrint("Failed to allocate buffer\n");
547 return LB_STATUS_ERROR_MEMORY;
550 buffer->type = BUFFER_TYPE_FILE;
552 buffer->state = CREATED;
557 info->buffer = buffer;
560 DbgPrint("FILE type %d created\n", size);
561 return LB_STATUS_SUCCESS;
564 static inline int load_shm_buffer(struct buffer_info *info)
568 struct buffer *buffer; /* Just for getting a size */
572 size = info->w * info->h * info->pixel_size;
574 ErrPrint("Invalid buffer size\n");
575 return LB_STATUS_ERROR_INVALID;
578 id = shmget(IPC_PRIVATE, size + sizeof(*buffer), IPC_CREAT | 0666);
580 ErrPrint("shmget: %s\n", strerror(errno));
581 return LB_STATUS_ERROR_FAULT;
584 buffer = shmat(id, NULL, 0);
585 if (buffer == (void *)-1) {
586 ErrPrint("%s shmat: %s\n", info->id, strerror(errno));
588 if (shmctl(id, IPC_RMID, 0) < 0) {
589 ErrPrint("%s shmctl: %s\n", info->id, strerror(errno));
592 return LB_STATUS_ERROR_FAULT;
595 buffer->type = BUFFER_TYPE_SHM;
597 buffer->state = CREATED; /*!< Needless */
598 buffer->info = (void *)size; /*!< Use this field to indicates the size of SHM */
600 len = strlen(SCHEMA_SHM) + 30; /* strlen("shm://") + 30 */
602 new_id = malloc(len);
604 ErrPrint("Heap: %s\n", strerror(errno));
605 if (shmdt(buffer) < 0) {
606 ErrPrint("shmdt: %s\n", strerror(errno));
609 if (shmctl(id, IPC_RMID, 0) < 0) {
610 ErrPrint("shmctl: %s\n", strerror(errno));
613 return LB_STATUS_ERROR_MEMORY;
616 snprintf(new_id, len, SCHEMA_SHM "%d", id);
620 info->buffer = buffer;
622 return LB_STATUS_SUCCESS;
625 static inline int load_pixmap_buffer(struct buffer_info *info)
627 struct buffer *buffer;
628 struct gem_data *gem;
634 * Before call the buffer_handler_pixmap_ref function,
635 * You should make sure that the is_loaded value is toggled (1)
636 * Or the buffer_handler_pixmap_ref function will return NULL
641 DbgPrint("Buffer is already exists, but override it with new one\n");
644 buffer = buffer_handler_pixmap_ref(info);
646 DbgPrint("Failed to make a reference of a pixmap\n");
648 return LB_STATUS_ERROR_FAULT;
651 len = strlen(SCHEMA_PIXMAP) + 30; /* strlen("pixmap://") + 30 */
652 new_id = malloc(len);
654 ErrPrint("Heap: %s\n", strerror(errno));
656 buffer_handler_pixmap_unref(buffer);
657 return LB_STATUS_ERROR_MEMORY;
663 gem = (struct gem_data *)buffer->data;
665 snprintf(info->id, len, SCHEMA_PIXMAP "%d:%d", (int)gem->pixmap, info->pixel_size);
666 DbgPrint("Loaded pixmap(info->id): %s\n", info->id);
667 return LB_STATUS_SUCCESS;
670 EAPI int buffer_handler_load(struct buffer_info *info)
675 ErrPrint("buffer handler is nil\n");
676 return LB_STATUS_ERROR_INVALID;
679 if (info->is_loaded) {
680 DbgPrint("Buffer is already loaded\n");
681 return LB_STATUS_SUCCESS;
684 switch (info->type) {
685 case BUFFER_TYPE_FILE:
686 ret = load_file_buffer(info);
687 (void)create_lock_file(info);
689 case BUFFER_TYPE_SHM:
690 ret = load_shm_buffer(info);
691 (void)create_lock_file(info);
693 case BUFFER_TYPE_PIXMAP:
694 ret = load_pixmap_buffer(info);
697 ErrPrint("Invalid buffer\n");
698 ret = LB_STATUS_ERROR_INVALID;
705 static inline int unload_file_buffer(struct buffer_info *info)
710 new_id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
712 ErrPrint("Heap: %s\n", strerror(errno));
713 return LB_STATUS_ERROR_MEMORY;
716 DbgFree(info->buffer);
719 path = util_uri_to_path(info->id);
720 if (path && unlink(path) < 0) {
721 ErrPrint("unlink: %s\n", strerror(errno));
726 return LB_STATUS_SUCCESS;
729 static inline int unload_shm_buffer(struct buffer_info *info)
734 new_id = strdup(SCHEMA_SHM "-1");
736 ErrPrint("Heap: %s\n", strerror(errno));
737 return LB_STATUS_ERROR_MEMORY;
740 if (sscanf(info->id, SCHEMA_SHM "%d", &id) != 1) {
741 ErrPrint("%s Invalid ID\n", info->id);
743 return LB_STATUS_ERROR_INVALID;
747 ErrPrint("(%s) Invalid id: %d\n", info->id, id);
749 return LB_STATUS_ERROR_INVALID;
752 if (shmdt(info->buffer) < 0) {
753 ErrPrint("Detach shm: %s\n", strerror(errno));
756 if (shmctl(id, IPC_RMID, 0) < 0) {
757 ErrPrint("Remove shm: %s\n", strerror(errno));
764 return LB_STATUS_SUCCESS;
767 static inline int unload_pixmap_buffer(struct buffer_info *info)
773 new_id = strdup(SCHEMA_PIXMAP "0:0");
775 ErrPrint("Heap: %s\n", strerror(errno));
776 return LB_STATUS_ERROR_MEMORY;
779 if (sscanf(info->id, SCHEMA_PIXMAP "%d:%d", &id, &pixels) != 2) {
780 ErrPrint("Invalid ID (%s)\n", info->id);
782 return LB_STATUS_ERROR_INVALID;
786 ErrPrint("(%s) Invalid id: %d\n", info->id, id);
788 return LB_STATUS_ERROR_INVALID;
792 * Decrease the reference counter.
794 buffer_handler_pixmap_unref(info->buffer);
798 * Just clear the info->buffer.
799 * It will be reallocated again.
805 return LB_STATUS_SUCCESS;
808 EAPI int buffer_handler_unload(struct buffer_info *info)
813 ErrPrint("buffer handler is NIL\n");
814 return LB_STATUS_ERROR_INVALID;
817 if (!info->is_loaded) {
818 ErrPrint("Buffer is not loaded\n");
819 return LB_STATUS_ERROR_INVALID;
822 switch (info->type) {
823 case BUFFER_TYPE_FILE:
824 (void)destroy_lock_file(info);
825 ret = unload_file_buffer(info);
827 case BUFFER_TYPE_SHM:
828 (void)destroy_lock_file(info);
829 ret = unload_shm_buffer(info);
831 case BUFFER_TYPE_PIXMAP:
832 ret = unload_pixmap_buffer(info);
835 ErrPrint("Invalid buffer\n");
836 ret = LB_STATUS_ERROR_INVALID;
847 EAPI const char *buffer_handler_id(const struct buffer_info *info)
849 return info ? info->id : "";
852 EAPI enum buffer_type buffer_handler_type(const struct buffer_info *info)
854 return info ? info->type : BUFFER_TYPE_ERROR;
857 EAPI void *buffer_handler_fb(struct buffer_info *info)
859 struct buffer *buffer;
865 buffer = info->buffer;
867 if (info->type == BUFFER_TYPE_PIXMAP) {
873 * For getting the buffer address of gem.
875 canvas = buffer_handler_pixmap_acquire_buffer(info);
876 ret = buffer_handler_pixmap_release_buffer(canvas);
878 ErrPrint("Failed to release buffer: %d\n", ret);
886 EAPI int buffer_handler_pixmap(const struct buffer_info *info)
889 struct gem_data *gem;
892 ErrPrint("Inavlid buffer handler\n");
896 if (info->type != BUFFER_TYPE_PIXMAP) {
897 ErrPrint("Invalid buffer type\n");
901 buf = (struct buffer *)info->buffer;
903 ErrPrint("Invalid buffer data\n");
907 gem = (struct gem_data *)buf->data;
911 EAPI void *buffer_handler_pixmap_acquire_buffer(struct buffer_info *info)
913 struct buffer *buffer;
915 if (!info || !info->is_loaded) {
916 ErrPrint("Buffer is not loaded\n");
920 buffer = buffer_handler_pixmap_ref(info);
925 return acquire_gem(buffer);
928 EAPI void *buffer_handler_pixmap_buffer(struct buffer_info *info)
930 struct buffer *buffer;
931 struct gem_data *gem;
937 if (!info->is_loaded) {
938 ErrPrint("Buffer is not loaded\n");
942 buffer = info->buffer;
947 gem = (struct gem_data *)buffer->data;
948 return gem->compensate_data ? gem->compensate_data : gem->data;
952 * \return "buffer" object (Not the buffer_info)
954 EAPI void *buffer_handler_pixmap_ref(struct buffer_info *info)
956 struct buffer *buffer;
958 if (!info->is_loaded) {
959 ErrPrint("Buffer is not loaded\n");
963 if (info->type != BUFFER_TYPE_PIXMAP) {
964 ErrPrint("Buffer type is not matched\n");
968 buffer = info->buffer;
972 buffer = create_pixmap(info);
974 ErrPrint("Failed to create a pixmap\n");
978 info->buffer = buffer;
981 struct pkg_info *pkg;
983 if (instance_lb_buffer(info->inst) == info) {
984 pkg = instance_package(info->inst);
985 if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
988 } else if (instance_pd_buffer(info->inst) == info) {
989 pkg = instance_package(info->inst);
990 if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
1000 } else if (buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
1001 ErrPrint("Invalid buffer\n");
1003 } else if (buffer->refcnt > 0) {
1008 s_info.pixmap_list = eina_list_append(s_info.pixmap_list, buffer);
1015 EAPI void *buffer_handler_pixmap_find(int pixmap)
1017 struct buffer *buffer;
1018 struct gem_data *gem;
1026 EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
1027 if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
1028 s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
1029 DbgPrint("Invalid buffer (List Removed: %p)\n", buffer);
1033 gem = (struct gem_data *)buffer->data;
1034 if (gem->pixmap == pixmap) {
1042 EAPI int buffer_handler_pixmap_release_buffer(void *canvas)
1044 struct buffer *buffer;
1045 struct gem_data *gem;
1051 return LB_STATUS_ERROR_INVALID;
1054 EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
1055 if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
1056 s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
1060 gem = (struct gem_data *)buffer->data;
1061 _ptr = gem->compensate_data ? gem->compensate_data : gem->data;
1067 if (_ptr == canvas) {
1068 release_gem(buffer);
1069 buffer_handler_pixmap_unref(buffer);
1070 return LB_STATUS_SUCCESS;
1074 return LB_STATUS_ERROR_NOT_EXIST;
1080 * \return Return NULL if the buffer is in still uses.
1081 * Return buffer_ptr if it needs to destroy
1083 EAPI int buffer_handler_pixmap_unref(void *buffer_ptr)
1085 struct buffer *buffer = buffer_ptr;
1086 struct buffer_info *info;
1089 if (buffer->refcnt > 0) {
1090 return LB_STATUS_SUCCESS; /* Return NULL means, gem buffer still in use */
1093 s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
1095 info = buffer->info;
1097 if (destroy_gem(buffer) < 0) {
1098 ErrPrint("Failed to destroy gem buffer\n");
1101 if (destroy_pixmap(buffer) < 0) {
1102 ErrPrint("Failed to destroy pixmap\n");
1105 if (info && info->buffer == buffer) {
1106 info->buffer = NULL;
1109 return LB_STATUS_SUCCESS;
1112 EAPI int buffer_handler_is_loaded(const struct buffer_info *info)
1114 return info ? info->is_loaded : 0;
1117 EAPI void buffer_handler_update_size(struct buffer_info *info, int w, int h)
1127 EAPI int buffer_handler_resize(struct buffer_info *info, int w, int h)
1132 ErrPrint("Invalid handler\n");
1133 return LB_STATUS_ERROR_INVALID;
1136 if (info->w == w && info->h == h) {
1137 DbgPrint("No changes\n");
1138 return LB_STATUS_SUCCESS;
1141 buffer_handler_update_size(info, w, h);
1143 if (!info->is_loaded) {
1144 DbgPrint("Buffer size is updated[%dx%d]\n", w, h);
1145 return LB_STATUS_SUCCESS;
1148 ret = buffer_handler_unload(info);
1150 ErrPrint("Unload: %d\n", ret);
1153 ret = buffer_handler_load(info);
1155 ErrPrint("Load: %d\n", ret);
1158 return LB_STATUS_SUCCESS;
1161 EAPI int buffer_handler_get_size(struct buffer_info *info, int *w, int *h)
1164 return LB_STATUS_ERROR_INVALID;
1174 return LB_STATUS_SUCCESS;
1177 EAPI struct inst_info *buffer_handler_instance(struct buffer_info *info)
1184 * Only for used S/W Backend
1186 static inline int sync_for_pixmap(struct buffer *buffer)
1192 struct gem_data *gem;
1196 if (buffer->state != CREATED) {
1197 ErrPrint("Invalid state of a FB\n");
1198 return LB_STATUS_ERROR_INVALID;
1201 if (buffer->type != BUFFER_TYPE_PIXMAP) {
1202 ErrPrint("Invalid buffer\n");
1203 return LB_STATUS_SUCCESS;
1206 disp = ecore_x_display_get();
1208 ErrPrint("Failed to get a display\n");
1209 return LB_STATUS_ERROR_FAULT;
1212 gem = (struct gem_data *)buffer->data;
1213 if (gem->w == 0 || gem->h == 0) {
1214 DbgPrint("Nothing can be sync\n");
1215 return LB_STATUS_SUCCESS;
1218 si.shmid = shmget(IPC_PRIVATE, gem->w * gem->h * gem->depth, IPC_CREAT | 0666);
1220 ErrPrint("shmget: %s\n", strerror(errno));
1221 return LB_STATUS_ERROR_FAULT;
1224 si.readOnly = False;
1225 si.shmaddr = shmat(si.shmid, NULL, 0);
1226 if (si.shmaddr == (void *)-1) {
1227 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
1228 ErrPrint("shmctl: %s\n", strerror(errno));
1230 return LB_STATUS_ERROR_FAULT;
1233 screen = DefaultScreenOfDisplay(disp);
1234 visual = DefaultVisualOfScreen(screen);
1237 * XCreatePixmap can only uses 24 bits depth only.
1239 xim = XShmCreateImage(disp, visual, (gem->depth << 3), ZPixmap, NULL, &si, gem->w, gem->h);
1241 if (shmdt(si.shmaddr) < 0) {
1242 ErrPrint("shmdt: %s\n", strerror(errno));
1245 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
1246 ErrPrint("shmctl: %s\n", strerror(errno));
1248 return LB_STATUS_ERROR_FAULT;
1251 xim->data = si.shmaddr;
1252 XShmAttach(disp, &si);
1255 gc = XCreateGC(disp, gem->pixmap, 0, NULL);
1257 XShmDetach(disp, &si);
1260 if (shmdt(si.shmaddr) < 0) {
1261 ErrPrint("shmdt: %s\n", strerror(errno));
1264 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
1265 ErrPrint("shmctl: %s\n", strerror(errno));
1268 return LB_STATUS_ERROR_FAULT;
1271 memcpy(xim->data, gem->data, gem->w * gem->h * gem->depth);
1274 * \note Do not send the event.
1275 * Instead of X event, master will send the updated event to the viewer
1277 XShmPutImage(disp, gem->pixmap, gc, xim, 0, 0, 0, 0, gem->w, gem->h, False);
1281 XShmDetach(disp, &si);
1284 if (shmdt(si.shmaddr) < 0) {
1285 ErrPrint("shmdt: %s\n", strerror(errno));
1288 if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
1289 ErrPrint("shmctl: %s\n", strerror(errno));
1292 return LB_STATUS_SUCCESS;
1295 EAPI void buffer_handler_flush(struct buffer_info *info)
1299 struct buffer *buffer;
1301 if (!info || !info->buffer) {
1305 buffer = info->buffer;
1307 if (buffer->type == BUFFER_TYPE_PIXMAP) {
1308 if (s_info.fd > 0) {
1313 XserverRegion region;
1317 rect.width = info->w;
1318 rect.height = info->h;
1320 region = XFixesCreateRegion(ecore_x_display_get(), &rect, 1);
1321 XDamageAdd(ecore_x_display_get(), buffer_handler_pixmap(info), region);
1322 XFixesDestroyRegion(ecore_x_display_get(), region);
1323 XFlush(ecore_x_display_get());
1324 //PERF_MARK("XFlush");
1326 if (sync_for_pixmap(buffer) < 0) {
1327 ErrPrint("Failed to sync via S/W Backend\n");
1330 } else if (buffer->type == BUFFER_TYPE_FILE) {
1331 fd = open(util_uri_to_path(info->id), O_WRONLY | O_CREAT, 0644);
1333 ErrPrint("%s open falied: %s\n", util_uri_to_path(info->id), strerror(errno));
1337 size = info->w * info->h * info->pixel_size;
1338 do_buffer_lock(info);
1339 if (write(fd, info->buffer, size) != size) {
1340 ErrPrint("Write is not completed: %s\n", strerror(errno));
1342 do_buffer_unlock(info);
1344 if (close(fd) < 0) {
1345 ErrPrint("close: %s\n", strerror(errno));
1348 DbgPrint("Flush nothing\n");
1352 HAPI int buffer_handler_init(void)
1354 int dri2Major, dri2Minor;
1355 char *driverName, *deviceName;
1358 if (!DRI2QueryExtension(ecore_x_display_get(), &s_info.evt_base, &s_info.err_base)) {
1359 ErrPrint("DRI2 is not supported\n");
1360 return LB_STATUS_SUCCESS;
1363 if (!DRI2QueryVersion(ecore_x_display_get(), &dri2Major, &dri2Minor)) {
1364 ErrPrint("DRI2 is not supported\n");
1365 s_info.evt_base = 0;
1366 s_info.err_base = 0;
1367 return LB_STATUS_SUCCESS;
1370 if (!DRI2Connect(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), &driverName, &deviceName)) {
1371 ErrPrint("DRI2 is not supported\n");
1372 s_info.evt_base = 0;
1373 s_info.err_base = 0;
1374 return LB_STATUS_SUCCESS;
1377 if (USE_SW_BACKEND) {
1378 DbgPrint("Fallback to the S/W Backend\n");
1379 s_info.evt_base = 0;
1380 s_info.err_base = 0;
1381 DbgFree(deviceName);
1382 DbgFree(driverName);
1383 return LB_STATUS_SUCCESS;
1386 s_info.fd = open(deviceName, O_RDWR);
1387 DbgFree(deviceName);
1388 DbgFree(driverName);
1389 if (s_info.fd < 0) {
1390 ErrPrint("Failed to open a drm device: (%s)\n", strerror(errno));
1391 s_info.evt_base = 0;
1392 s_info.err_base = 0;
1393 return LB_STATUS_SUCCESS;
1396 drmGetMagic(s_info.fd, &magic);
1397 DbgPrint("DRM Magic: 0x%X\n", magic);
1398 if (!DRI2Authenticate(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), (unsigned int)magic)) {
1399 ErrPrint("Failed to do authenticate for DRI2\n");
1400 if (close(s_info.fd) < 0) {
1401 ErrPrint("close: %s\n", strerror(errno));
1404 s_info.evt_base = 0;
1405 s_info.err_base = 0;
1406 return LB_STATUS_SUCCESS;
1409 s_info.slp_bufmgr = tbm_bufmgr_init(s_info.fd);
1410 if (!s_info.slp_bufmgr) {
1411 ErrPrint("Failed to init bufmgr\n");
1412 if (close(s_info.fd) < 0) {
1413 ErrPrint("close: %s\n", strerror(errno));
1416 s_info.evt_base = 0;
1417 s_info.err_base = 0;
1418 return LB_STATUS_SUCCESS;
1421 return LB_STATUS_SUCCESS;
1424 HAPI int buffer_handler_fini(void)
1426 if (s_info.fd >= 0) {
1427 if (close(s_info.fd) < 0) {
1428 ErrPrint("close: %s\n", strerror(errno));
1433 if (s_info.slp_bufmgr) {
1434 tbm_bufmgr_deinit(s_info.slp_bufmgr);
1435 s_info.slp_bufmgr = NULL;
1438 return LB_STATUS_SUCCESS;
1441 static inline struct buffer *raw_open_file(const char *filename)
1443 struct buffer *buffer;
1448 fd = open(filename, O_RDONLY);
1450 ErrPrint("open: %s\n", strerror(errno));
1454 off = lseek(fd, 0L, SEEK_END);
1455 if (off == (off_t)-1) {
1456 ErrPrint("lseek: %s\n", strerror(errno));
1458 if (close(fd) < 0) {
1459 ErrPrint("close: %s\n", strerror(errno));
1465 if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
1466 ErrPrint("lseek: %s\n", strerror(errno));
1468 if (close(fd) < 0) {
1469 ErrPrint("close: %s\n", strerror(errno));
1475 buffer = calloc(1, sizeof(*buffer) + off);
1477 ErrPrint("Heap: %s\n", strerror(errno));
1479 if (close(fd) < 0) {
1480 ErrPrint("close: %s\n", strerror(errno));
1486 buffer->state = CREATED;
1487 buffer->type = BUFFER_TYPE_FILE;
1489 buffer->info = (void *)off;
1491 ret = read(fd, buffer->data, off);
1493 ErrPrint("read: %s\n", strerror(errno));
1496 if (close(fd) < 0) {
1497 ErrPrint("close: %s\n", strerror(errno));
1503 if (close(fd) < 0) {
1504 ErrPrint("close: %s\n", strerror(errno));
1510 static inline int raw_close_file(struct buffer *buffer)
1516 static inline struct buffer *raw_open_shm(int shm)
1518 struct buffer *buffer;
1520 buffer = (struct buffer *)shmat(shm, NULL, SHM_RDONLY);
1521 if (buffer == (struct buffer *)-1) {
1522 ErrPrint("shmat: %s\n", strerror(errno));
1529 static inline int raw_close_shm(struct buffer *buffer)
1533 ret = shmdt(buffer);
1535 ErrPrint("shmdt: %s\n", strerror(errno));
1541 static inline struct buffer *raw_open_pixmap(unsigned int pixmap)
1543 struct buffer *buffer;
1545 buffer = calloc(1, sizeof(*buffer) + DEFAULT_PIXELS);
1547 ErrPrint("Heap: %s\n", strerror(errno));
1551 buffer->state = CREATED;
1552 buffer->type = BUFFER_TYPE_PIXMAP;
1557 static inline int raw_close_pixmap(struct buffer *buffer)
1563 EAPI void *buffer_handler_raw_data(struct buffer *buffer)
1565 if (!buffer || buffer->state != CREATED) {
1569 return buffer->data;
1572 EAPI int buffer_handler_raw_size(struct buffer *buffer)
1574 if (!buffer || buffer->state != CREATED) {
1575 return LB_STATUS_ERROR_INVALID;
1578 return (int)buffer->info;
1581 EAPI struct buffer *buffer_handler_raw_open(enum buffer_type buffer_type, void *resource)
1583 struct buffer *handle;
1585 switch (buffer_type) {
1586 case BUFFER_TYPE_SHM:
1587 handle = raw_open_shm((int)resource);
1589 case BUFFER_TYPE_FILE:
1590 handle = raw_open_file(resource);
1592 case BUFFER_TYPE_PIXMAP:
1593 handle = raw_open_pixmap((unsigned int)resource);
1603 EAPI int buffer_handler_raw_close(struct buffer *buffer)
1607 switch (buffer->type) {
1608 case BUFFER_TYPE_SHM:
1609 ret = raw_close_shm(buffer);
1611 case BUFFER_TYPE_FILE:
1612 ret = raw_close_file(buffer);
1614 case BUFFER_TYPE_PIXMAP:
1615 ret = raw_close_pixmap(buffer);
1618 ret = LB_STATUS_ERROR_INVALID;
1625 EAPI int buffer_handler_lock(struct buffer_info *buffer)
1627 if (buffer->type == BUFFER_TYPE_PIXMAP) {
1628 return LB_STATUS_SUCCESS;
1631 if (buffer->type == BUFFER_TYPE_FILE) {
1632 return LB_STATUS_SUCCESS;
1635 return do_buffer_lock(buffer);
1638 EAPI int buffer_handler_unlock(struct buffer_info *buffer)
1640 if (buffer->type == BUFFER_TYPE_PIXMAP) {
1641 return LB_STATUS_SUCCESS;
1644 if (buffer->type == BUFFER_TYPE_FILE) {
1645 return LB_STATUS_SUCCESS;
1648 return do_buffer_unlock(buffer);
1653 * Only can be used by master.
1654 * Plugin cannot access the user data
1657 HAPI int buffer_handler_set_data(struct buffer_info *buffer, void *data)
1660 ErrPrint("Invalid handle\n");
1661 return LB_STATUS_ERROR_INVALID;
1664 buffer->data = data;
1665 return LB_STATUS_SUCCESS;
1668 HAPI void *buffer_handler_data(struct buffer_info *buffer)
1671 ErrPrint("Invalid handle\n");
1675 return buffer->data;
1678 HAPI int buffer_handler_destroy(struct buffer_info *info)
1681 struct buffer *buffer;
1684 DbgPrint("Buffer is not created yet. info is NIL\n");
1685 return LB_STATUS_SUCCESS;
1688 EINA_LIST_FOREACH(s_info.pixmap_list, l, buffer) {
1689 if (buffer->info == info) {
1690 buffer->info = NULL;
1694 buffer_handler_unload(info);
1697 return LB_STATUS_SUCCESS;
1700 HAPI struct buffer_info *buffer_handler_create(struct inst_info *inst, enum buffer_type type, int w, int h, int pixel_size)
1702 struct buffer_info *info;
1704 info = malloc(sizeof(*info));
1706 ErrPrint("Heap: %s\n", strerror(errno));
1711 case BUFFER_TYPE_SHM:
1712 if (pixel_size != DEFAULT_PIXELS) {
1713 DbgPrint("SHM only supportes %d bytes pixels (requested: %d)\n", DEFAULT_PIXELS, pixel_size);
1714 pixel_size = DEFAULT_PIXELS;
1717 info->id = strdup(SCHEMA_SHM "-1");
1719 ErrPrint("Heap: %s\n", strerror(errno));
1724 case BUFFER_TYPE_FILE:
1725 if (pixel_size != DEFAULT_PIXELS) {
1726 DbgPrint("FILE only supportes %d bytes pixels (requested: %d)\n", DEFAULT_PIXELS, pixel_size);
1727 pixel_size = DEFAULT_PIXELS;
1730 info->id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
1732 ErrPrint("Heap: %s\n", strerror(errno));
1737 case BUFFER_TYPE_PIXMAP:
1738 info->id = strdup(SCHEMA_PIXMAP "0:0");
1740 ErrPrint("Heap: %s\n", strerror(errno));
1746 ErrPrint("Invalid type\n");
1755 info->pixel_size = pixel_size;
1757 info->is_loaded = 0;
1759 info->buffer = NULL;