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"
59 DESTROYED = 0x00dead00
61 enum buffer_type type;
68 * \brief Allocate this in the buffer->data.
71 DRI2Buffer *dri2_buffer;
72 unsigned int attachments[1];
80 void *data; /* Gem layer */
83 void *compensate_data; /* Check the pitch value, copy this to data */
91 enum buffer_type type;
98 struct inst_info *inst;
102 tbm_bufmgr slp_bufmgr;
106 Eina_List *pixmap_list;
115 HAPI struct buffer_info *buffer_handler_create(struct inst_info *inst, enum buffer_type type, int w, int h, int pixel_size)
117 struct buffer_info *info;
119 info = malloc(sizeof(*info));
121 ErrPrint("Heap: %s\n", strerror(errno));
126 case BUFFER_TYPE_SHM:
127 info->id = strdup(SCHEMA_SHM "-1");
129 ErrPrint("Heap: %s\n", strerror(errno));
134 case BUFFER_TYPE_FILE:
135 info->id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
137 ErrPrint("Heap: %s\n", strerror(errno));
142 case BUFFER_TYPE_PIXMAP:
143 info->id = strdup(SCHEMA_PIXMAP "0");
145 ErrPrint("Heap: %s\n", strerror(errno));
151 ErrPrint("Invalid type\n");
158 info->pixel_size = pixel_size;
167 static inline struct buffer *create_pixmap(struct buffer_info *info)
169 struct gem_data *gem;
170 struct buffer *buffer;
176 disp = ecore_x_display_get();
180 parent = DefaultRootWindow(disp);
182 buffer = calloc(1, sizeof(*buffer) + sizeof(*gem));
184 ErrPrint("Heap: %s\n", strerror(errno));
188 gem = (struct gem_data *)buffer->data;
190 buffer->type = BUFFER_TYPE_PIXMAP;
192 buffer->state = CREATED;
194 gem->attachments[0] = DRI2BufferFrontLeft;
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;
202 * 32 Bits is not supported for video playing.
203 * But for the transparent background, use the 32 bits, and give up video.
205 gem->pixmap = XCreatePixmap(disp, parent, info->w, info->h, (info->pixel_size << 3));
206 if (gem->pixmap == (Pixmap)0) {
207 ErrPrint("Failed to create a pixmap\n");
216 memset(&gcv, 0, sizeof(gcv));
217 gc = XCreateGC(disp, gem->pixmap, GCForeground, &gcv);
219 XFillRectangle(disp, gem->pixmap, gc, 0, 0, info->w, info->h);
224 ErrPrint("Unable to clear the pixmap\n");
230 static inline int create_gem(struct buffer *buffer)
232 struct gem_data *gem;
235 disp = ecore_x_display_get();
237 ErrPrint("Failed to get display\n");
238 return LB_STATUS_ERROR_IO;
241 gem = (struct gem_data *)buffer->data;
244 gem->data = calloc(1, gem->w * gem->h * gem->depth);
246 ErrPrint("Heap: %s\n", strerror(errno));
247 return LB_STATUS_ERROR_MEMORY;
250 ErrPrint("DRI2(gem) is not supported - Fallback to the S/W Backend\n");
251 return LB_STATUS_SUCCESS;
254 DRI2CreateDrawable(disp, gem->pixmap);
256 gem->dri2_buffer = DRI2GetBuffers(disp, gem->pixmap,
257 &gem->w, &gem->h, gem->attachments, gem->count, &gem->buf_count);
258 if (!gem->dri2_buffer || !gem->dri2_buffer->name) {
259 ErrPrint("Failed to get a gem buffer\n");
260 DRI2DestroyDrawable(disp, gem->pixmap);
261 return LB_STATUS_ERROR_FAULT;
264 * \How can I destroy this?
266 gem->pixmap_bo = tbm_bo_import(s_info.slp_bufmgr, gem->dri2_buffer->name);
267 if (!gem->pixmap_bo) {
268 ErrPrint("Failed to import BO\n");
269 DRI2DestroyDrawable(disp, gem->pixmap);
270 return LB_STATUS_ERROR_FAULT;
273 if (gem->dri2_buffer->pitch != gem->w * gem->depth) {
274 gem->compensate_data = calloc(1, gem->w * gem->h * gem->depth);
275 if (!gem->compensate_data)
276 ErrPrint("Failed to allocate heap\n");
279 DbgPrint("dri2_buffer: %p, name: %p, %dx%d, pitch: %d, buf_count: %d, depth: %d, compensate: %p\n",
280 gem->dri2_buffer, gem->dri2_buffer->name, gem->w, gem->h,
281 gem->dri2_buffer->pitch, gem->buf_count, gem->depth, gem->compensate_data);
283 return LB_STATUS_SUCCESS;
286 static inline void *acquire_gem(struct buffer *buffer)
288 struct gem_data *gem;
293 gem = (struct gem_data *)buffer->data;
295 ErrPrint("GEM is not supported - Use the fake gem buffer\n");
297 if (!gem->pixmap_bo) {
298 ErrPrint("GEM is not created\n");
303 tbm_bo_handle handle;
306 ErrPrint("Already acquired. but the buffer is not valid\n");
310 handle = tbm_bo_map(gem->pixmap_bo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE);
311 gem->data = handle.ptr;
319 * If there is a compensate canvas buffer,
322 return gem->compensate_data ? gem->compensate_data : gem->data;
325 static inline void release_gem(struct buffer *buffer)
327 struct gem_data *gem;
329 gem = (struct gem_data *)buffer->data;
330 if (s_info.fd >= 0 && !gem->pixmap_bo) {
331 ErrPrint("GEM is not created\n");
336 if (gem->refcnt > 0) {
337 ErrPrint("Reference count is not valid %d\n", gem->refcnt);
344 if (gem->refcnt == 0) {
346 DbgPrint("S/W Gem buffer has no reference\n");
350 * Update the gem buffer using compensate data buffer if it is exists
352 if (gem->compensate_data) {
359 pixel = gem->compensate_data;
360 gem_pixel = gem->data;
361 gap = gem->dri2_buffer->pitch - (gem->w * gem->depth);
363 for (y = 0; y < gem->h; y++) {
364 for (x = 0; x < gem->w; x++)
365 *gem_pixel++ = *pixel++;
367 gem_pixel = (int *)(((char *)gem_pixel) + gap);
372 tbm_bo_unmap(gem->pixmap_bo);
376 } else if (gem->refcnt < 0) {
377 ErrPrint("Invalid refcnt: %d (reset)\n", gem->refcnt);
382 static inline int destroy_pixmap(struct buffer *buffer)
384 struct gem_data *gem;
386 gem = (struct gem_data *)buffer->data;
391 disp = ecore_x_display_get();
393 return LB_STATUS_ERROR_IO;
395 DbgPrint("pixmap %lu\n", gem->pixmap);
396 XFreePixmap(disp, gem->pixmap);
399 buffer->state = DESTROYED;
401 return LB_STATUS_SUCCESS;
404 static inline int destroy_gem(struct buffer *buffer)
406 struct gem_data *gem;
409 return LB_STATUS_ERROR_INVALID;
412 * Forcely release the acquire_buffer.
414 gem = (struct gem_data *)buffer->data;
416 return LB_STATUS_ERROR_FAULT;
418 if (s_info.fd >= 0) {
419 if (gem->compensate_data) {
420 DbgPrint("Release compensate buffer %p\n", gem->compensate_data);
421 free(gem->compensate_data);
422 gem->compensate_data = NULL;
425 if (gem->pixmap_bo) {
426 DbgPrint("unref pixmap bo\n");
427 tbm_bo_unref(gem->pixmap_bo);
428 gem->pixmap_bo = NULL;
430 DRI2DestroyDrawable(ecore_x_display_get(), gem->pixmap);
432 } else if (gem->data) {
433 DbgPrint("Release fake gem buffer\n");
438 return LB_STATUS_SUCCESS;
441 static inline int load_file_buffer(struct buffer_info *info)
443 struct buffer *buffer;
449 len = strlen(IMAGE_PATH) + 40;
450 new_id = malloc(len);
452 ErrPrint("Heap: %s\n", strerror(errno));
453 return LB_STATUS_ERROR_MEMORY;
456 timestamp = util_timestamp();
457 snprintf(new_id, len, SCHEMA_FILE "%s%lf", IMAGE_PATH, timestamp);
459 size = sizeof(*buffer) + info->w * info->h * info->pixel_size;
461 ErrPrint("Canvas buffer size is ZERO\n");
463 return LB_STATUS_ERROR_INVALID;
466 buffer = calloc(1, size);
468 ErrPrint("Failed to allocate buffer\n");
470 return LB_STATUS_ERROR_MEMORY;
473 buffer->type = BUFFER_TYPE_FILE;
475 buffer->state = CREATED;
480 info->buffer = buffer;
483 DbgPrint("FILE type %d created\n", size);
484 return LB_STATUS_SUCCESS;
487 static inline int load_shm_buffer(struct buffer_info *info)
491 struct buffer *buffer; /* Just for getting a size */
495 size = info->w * info->h * info->pixel_size;
497 ErrPrint("Invalid buffer size\n");
498 return LB_STATUS_ERROR_INVALID;
501 id = shmget(IPC_PRIVATE, size + sizeof(*buffer), IPC_CREAT | 0666);
503 ErrPrint("shmget: %s\n", strerror(errno));
504 return LB_STATUS_ERROR_FAULT;
507 buffer = shmat(id, NULL, 0);
508 if (buffer == (void *)-1) {
509 ErrPrint("%s shmat: %s\n", info->id, strerror(errno));
511 if (shmctl(id, IPC_RMID, 0) < 0)
512 ErrPrint("%s shmctl: %s\n", info->id, strerror(errno));
514 return LB_STATUS_ERROR_FAULT;
517 buffer->type = BUFFER_TYPE_SHM;
519 buffer->state = CREATED; /*!< Needless */
520 buffer->info = (void *)size; /*!< Use this field to indicates the size of SHM */
522 len = strlen(SCHEMA_SHM) + 30; /* strlen("shm://") + 30 */
524 new_id = malloc(len);
526 ErrPrint("Heap: %s\n", strerror(errno));
527 if (shmdt(buffer) < 0)
528 ErrPrint("shmdt: %s\n", strerror(errno));
530 if (shmctl(id, IPC_RMID, 0) < 0)
531 ErrPrint("shmctl: %s\n", strerror(errno));
533 return LB_STATUS_ERROR_MEMORY;
536 snprintf(new_id, len, SCHEMA_SHM "%d", id);
540 info->buffer = buffer;
542 return LB_STATUS_SUCCESS;
545 static inline int load_pixmap_buffer(struct buffer_info *info)
547 struct buffer *buffer;
548 struct gem_data *gem;
554 * Before call the buffer_handler_pixmap_ref function,
555 * You should make sure that the is_loaded value is toggled (1)
556 * Or the buffer_handler_pixmap_ref function will return NULL
561 DbgPrint("Buffer is already exists, but override it with new one\n");
563 buffer = buffer_handler_pixmap_ref(info);
565 DbgPrint("Failed to make a reference of a pixmap\n");
567 return LB_STATUS_ERROR_FAULT;
570 len = strlen(SCHEMA_PIXMAP) + 30; /* strlen("pixmap://") + 30 */
571 new_id = malloc(len);
573 ErrPrint("Heap: %s\n", strerror(errno));
575 buffer_handler_pixmap_unref(buffer);
576 return LB_STATUS_ERROR_MEMORY;
582 gem = (struct gem_data *)buffer->data;
584 snprintf(info->id, len, SCHEMA_PIXMAP "%d", (int)gem->pixmap);
585 DbgPrint("Loaded pixmap(info->id): %s\n", info->id);
586 return LB_STATUS_SUCCESS;
589 HAPI int buffer_handler_load(struct buffer_info *info)
594 ErrPrint("buffer handler is nil\n");
595 return LB_STATUS_ERROR_INVALID;
598 if (info->is_loaded) {
599 DbgPrint("Buffer is already loaded\n");
600 return LB_STATUS_SUCCESS;
603 switch (info->type) {
604 case BUFFER_TYPE_FILE:
605 ret = load_file_buffer(info);
607 case BUFFER_TYPE_SHM:
608 ret = load_shm_buffer(info);
610 case BUFFER_TYPE_PIXMAP:
611 ret = load_pixmap_buffer(info);
614 ErrPrint("Invalid buffer\n");
615 ret = LB_STATUS_ERROR_INVALID;
622 static inline int unload_file_buffer(struct buffer_info *info)
627 new_id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
629 ErrPrint("Heap: %s\n", strerror(errno));
630 return LB_STATUS_ERROR_MEMORY;
633 DbgFree(info->buffer);
636 path = util_uri_to_path(info->id);
637 if (path && unlink(path) < 0)
638 ErrPrint("unlink: %s\n", strerror(errno));
642 return LB_STATUS_SUCCESS;
645 static inline int unload_shm_buffer(struct buffer_info *info)
650 new_id = strdup(SCHEMA_SHM "-1");
652 ErrPrint("Heap: %s\n", strerror(errno));
653 return LB_STATUS_ERROR_MEMORY;
656 if (sscanf(info->id, SCHEMA_SHM "%d", &id) != 1) {
657 ErrPrint("%s Invalid ID\n", info->id);
659 return LB_STATUS_ERROR_INVALID;
663 ErrPrint("(%s) Invalid id: %d\n", info->id, id);
665 return LB_STATUS_ERROR_INVALID;
668 if (shmdt(info->buffer) < 0)
669 ErrPrint("Detach shm: %s\n", strerror(errno));
671 if (shmctl(id, IPC_RMID, 0) < 0)
672 ErrPrint("Remove shm: %s\n", strerror(errno));
678 return LB_STATUS_SUCCESS;
681 static inline int unload_pixmap_buffer(struct buffer_info *info)
686 new_id = strdup(SCHEMA_PIXMAP "0");
688 ErrPrint("Heap: %s\n", strerror(errno));
689 return LB_STATUS_ERROR_MEMORY;
692 if (sscanf(info->id, SCHEMA_PIXMAP "%d", &id) != 1) {
693 ErrPrint("Invalid ID (%s)\n", info->id);
695 return LB_STATUS_ERROR_INVALID;
699 ErrPrint("(%s) Invalid id: %d\n", info->id, id);
701 return LB_STATUS_ERROR_INVALID;
705 * Decrease the reference counter.
707 buffer_handler_pixmap_unref(info->buffer);
711 * Just clear the info->buffer.
712 * It will be reallocated again.
718 return LB_STATUS_SUCCESS;
721 HAPI int buffer_handler_unload(struct buffer_info *info)
726 ErrPrint("buffer handler is NIL\n");
727 return LB_STATUS_ERROR_INVALID;
730 if (!info->is_loaded) {
731 ErrPrint("Buffer is not loaded\n");
732 return LB_STATUS_ERROR_INVALID;
735 switch (info->type) {
736 case BUFFER_TYPE_FILE:
737 ret = unload_file_buffer(info);
739 case BUFFER_TYPE_SHM:
740 ret = unload_shm_buffer(info);
742 case BUFFER_TYPE_PIXMAP:
743 ret = unload_pixmap_buffer(info);
746 ErrPrint("Invalid buffer\n");
747 ret = LB_STATUS_ERROR_INVALID;
757 HAPI int buffer_handler_destroy(struct buffer_info *info)
760 struct buffer *buffer;
763 DbgPrint("Buffer is not created yet. info is NIL\n");
764 return LB_STATUS_SUCCESS;
767 EINA_LIST_FOREACH(s_info.pixmap_list, l, buffer) {
768 if (buffer->info == info)
772 buffer_handler_unload(info);
775 return LB_STATUS_SUCCESS;
778 HAPI const char *buffer_handler_id(const struct buffer_info *info)
780 return info ? info->id : "";
783 HAPI enum buffer_type buffer_handler_type(const struct buffer_info *info)
785 return info ? info->type : BUFFER_TYPE_ERROR;
788 HAPI void *buffer_handler_fb(struct buffer_info *info)
790 struct buffer *buffer;
795 buffer = info->buffer;
797 if (info->type == BUFFER_TYPE_PIXMAP) {
803 * For getting the buffer address of gem.
805 canvas = buffer_handler_pixmap_acquire_buffer(info);
806 ret = buffer_handler_pixmap_release_buffer(canvas);
808 ErrPrint("Failed to release buffer: %d\n", ret);
815 HAPI int buffer_handler_pixmap(const struct buffer_info *info)
818 struct gem_data *gem;
821 ErrPrint("Inavlid buffer handler\n");
825 if (info->type != BUFFER_TYPE_PIXMAP) {
826 ErrPrint("Invalid buffer type\n");
830 buf = (struct buffer *)info->buffer;
832 ErrPrint("Invalid buffer data\n");
836 gem = (struct gem_data *)buf->data;
840 HAPI void *buffer_handler_pixmap_acquire_buffer(struct buffer_info *info)
842 struct buffer *buffer;
844 if (!info || !info->is_loaded) {
845 ErrPrint("Buffer is not loaded\n");
849 buffer = buffer_handler_pixmap_ref(info);
853 return acquire_gem(buffer);
856 HAPI void *buffer_handler_pixmap_buffer(struct buffer_info *info)
858 struct buffer *buffer;
859 struct gem_data *gem;
864 if (!info->is_loaded) {
865 ErrPrint("Buffer is not loaded\n");
869 buffer = info->buffer;
873 gem = (struct gem_data *)buffer->data;
874 return gem->compensate_data ? gem->compensate_data : gem->data;
878 * \return "buffer" object (Not the buffer_info)
880 HAPI void *buffer_handler_pixmap_ref(struct buffer_info *info)
882 struct buffer *buffer;
884 if (!info->is_loaded) {
885 ErrPrint("Buffer is not loaded\n");
889 if (info->type != BUFFER_TYPE_PIXMAP) {
890 ErrPrint("Buffer type is not matched\n");
894 buffer = info->buffer;
898 buffer = create_pixmap(info);
900 ErrPrint("Failed to create a pixmap\n");
904 info->buffer = buffer;
907 struct pkg_info *pkg;
909 if (instance_lb_buffer(info->inst) == info) {
910 pkg = instance_package(info->inst);
911 if (package_lb_type(pkg) == LB_TYPE_BUFFER)
913 } else if (instance_pd_buffer(info->inst) == info) {
914 pkg = instance_package(info->inst);
915 if (package_pd_type(pkg) == PD_TYPE_BUFFER)
923 } else if (buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
924 ErrPrint("Invalid buffer\n");
926 } else if (buffer->refcnt > 0) {
931 s_info.pixmap_list = eina_list_append(s_info.pixmap_list, buffer);
938 HAPI void *buffer_handler_pixmap_find(int pixmap)
940 struct buffer *buffer;
941 struct gem_data *gem;
948 EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
949 if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
950 s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
951 DbgPrint("Invalid buffer (List Removed: %p)\n", buffer);
955 gem = (struct gem_data *)buffer->data;
956 if (gem->pixmap == pixmap)
963 HAPI int buffer_handler_pixmap_release_buffer(void *canvas)
965 struct buffer *buffer;
966 struct gem_data *gem;
972 return LB_STATUS_ERROR_INVALID;
974 EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
975 if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
976 s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
980 gem = (struct gem_data *)buffer->data;
981 _ptr = gem->compensate_data ? gem->compensate_data : gem->data;
986 if (_ptr == canvas) {
988 buffer_handler_pixmap_unref(buffer);
989 return LB_STATUS_SUCCESS;
993 return LB_STATUS_ERROR_NOT_EXIST;
999 * \return Return NULL if the buffer is in still uses.
1000 * Return buffer_ptr if it needs to destroy
1002 HAPI int buffer_handler_pixmap_unref(void *buffer_ptr)
1004 struct buffer *buffer = buffer_ptr;
1005 struct buffer_info *info;
1008 if (buffer->refcnt > 0)
1009 return LB_STATUS_SUCCESS; /* Return NULL means, gem buffer still in use */
1011 s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
1013 info = buffer->info;
1015 if (destroy_gem(buffer) < 0)
1016 ErrPrint("Failed to destroy gem buffer\n");
1018 if (destroy_pixmap(buffer) < 0)
1019 ErrPrint("Failed to destroy pixmap\n");
1021 if (info && info->buffer == buffer)
1022 info->buffer = NULL;
1024 return LB_STATUS_SUCCESS;
1027 HAPI int buffer_handler_is_loaded(const struct buffer_info *info)
1029 return info ? info->is_loaded : 0;
1032 HAPI void buffer_handler_update_size(struct buffer_info *info, int w, int h)
1041 HAPI int buffer_handler_resize(struct buffer_info *info, int w, int h)
1046 ErrPrint("Invalid handler\n");
1047 return LB_STATUS_ERROR_INVALID;
1050 if (info->w == w && info->h == h) {
1051 DbgPrint("No changes\n");
1052 return LB_STATUS_SUCCESS;
1055 buffer_handler_update_size(info, w, h);
1057 if (!info->is_loaded) {
1058 DbgPrint("Buffer size is updated[%dx%d]\n", w, h);
1059 return LB_STATUS_SUCCESS;
1062 ret = buffer_handler_unload(info);
1064 ErrPrint("Unload: %d\n", ret);
1066 ret = buffer_handler_load(info);
1068 ErrPrint("Load: %d\n", ret);
1070 return LB_STATUS_SUCCESS;
1073 HAPI int buffer_handler_get_size(struct buffer_info *info, int *w, int *h)
1076 return LB_STATUS_ERROR_INVALID;
1083 return LB_STATUS_SUCCESS;
1086 HAPI struct inst_info *buffer_handler_instance(struct buffer_info *info)
1093 * Only for used S/W Backend
1095 static inline int sync_for_pixmap(struct buffer *buffer)
1101 struct gem_data *gem;
1105 if (buffer->state != CREATED) {
1106 ErrPrint("Invalid state of a FB\n");
1107 return LB_STATUS_ERROR_INVALID;
1110 if (buffer->type != BUFFER_TYPE_PIXMAP) {
1111 ErrPrint("Invalid buffer\n");
1112 return LB_STATUS_SUCCESS;
1115 disp = ecore_x_display_get();
1117 ErrPrint("Failed to get a display\n");
1118 return LB_STATUS_ERROR_FAULT;
1121 gem = (struct gem_data *)buffer->data;
1122 if (gem->w == 0 || gem->h == 0) {
1123 DbgPrint("Nothing can be sync\n");
1124 return LB_STATUS_SUCCESS;
1127 si.shmid = shmget(IPC_PRIVATE, gem->w * gem->h * gem->depth, IPC_CREAT | 0666);
1129 ErrPrint("shmget: %s\n", strerror(errno));
1130 return LB_STATUS_ERROR_FAULT;
1133 si.readOnly = False;
1134 si.shmaddr = shmat(si.shmid, NULL, 0);
1135 if (si.shmaddr == (void *)-1) {
1136 if (shmctl(si.shmid, IPC_RMID, 0) < 0)
1137 ErrPrint("shmctl: %s\n", strerror(errno));
1138 return LB_STATUS_ERROR_FAULT;
1141 screen = DefaultScreenOfDisplay(disp);
1142 visual = DefaultVisualOfScreen(screen);
1145 * XCreatePixmap can only uses 24 bits depth only.
1147 xim = XShmCreateImage(disp, visual, (gem->depth << 3), ZPixmap, NULL, &si, gem->w, gem->h);
1149 if (shmdt(si.shmaddr) < 0)
1150 ErrPrint("shmdt: %s\n", strerror(errno));
1152 if (shmctl(si.shmid, IPC_RMID, 0) < 0)
1153 ErrPrint("shmctl: %s\n", strerror(errno));
1154 return LB_STATUS_ERROR_FAULT;
1157 xim->data = si.shmaddr;
1158 XShmAttach(disp, &si);
1161 gc = XCreateGC(disp, gem->pixmap, 0, NULL);
1163 XShmDetach(disp, &si);
1166 if (shmdt(si.shmaddr) < 0)
1167 ErrPrint("shmdt: %s\n", strerror(errno));
1169 if (shmctl(si.shmid, IPC_RMID, 0) < 0)
1170 ErrPrint("shmctl: %s\n", strerror(errno));
1172 return LB_STATUS_ERROR_FAULT;
1175 memcpy(xim->data, gem->data, gem->w * gem->h * gem->depth);
1178 * \note Do not send the event.
1179 * Instead of X event, master will send the updated event to the viewer
1181 XShmPutImage(disp, gem->pixmap, gc, xim, 0, 0, 0, 0, gem->w, gem->h, False);
1185 XShmDetach(disp, &si);
1188 if (shmdt(si.shmaddr) < 0)
1189 ErrPrint("shmdt: %s\n", strerror(errno));
1191 if (shmctl(si.shmid, IPC_RMID, 0) < 0)
1192 ErrPrint("shmctl: %s\n", strerror(errno));
1194 return LB_STATUS_SUCCESS;
1197 HAPI void buffer_handler_flush(struct buffer_info *info)
1201 struct buffer *buffer;
1203 if (!info || !info->buffer)
1206 buffer = info->buffer;
1208 if (buffer->type == BUFFER_TYPE_PIXMAP) {
1209 if (s_info.fd > 0) {
1211 XserverRegion region;
1215 rect.width = info->w;
1216 rect.height = info->h;
1218 region = XFixesCreateRegion(ecore_x_display_get(), &rect, 1);
1219 XDamageAdd(ecore_x_display_get(), buffer_handler_pixmap(info), region);
1220 XFixesDestroyRegion(ecore_x_display_get(), region);
1221 XFlush(ecore_x_display_get());
1223 if (sync_for_pixmap(buffer) < 0)
1224 ErrPrint("Failed to sync via S/W Backend\n");
1226 } else if (buffer->type == BUFFER_TYPE_FILE) {
1227 fd = open(util_uri_to_path(info->id), O_WRONLY | O_CREAT, 0644);
1229 ErrPrint("%s open falied: %s\n", util_uri_to_path(info->id), strerror(errno));
1233 size = info->w * info->h * info->pixel_size;
1234 if (write(fd, info->buffer, size) != size)
1235 ErrPrint("Write is not completed: %s\n", strerror(errno));
1238 ErrPrint("close: %s\n", strerror(errno));
1240 DbgPrint("Flush nothing\n");
1244 HAPI int buffer_handler_init(void)
1246 int dri2Major, dri2Minor;
1247 char *driverName, *deviceName;
1250 if (!DRI2QueryExtension(ecore_x_display_get(), &s_info.evt_base, &s_info.err_base)) {
1251 ErrPrint("DRI2 is not supported\n");
1252 return LB_STATUS_SUCCESS;
1255 if (!DRI2QueryVersion(ecore_x_display_get(), &dri2Major, &dri2Minor)) {
1256 ErrPrint("DRI2 is not supported\n");
1257 s_info.evt_base = 0;
1258 s_info.err_base = 0;
1259 return LB_STATUS_SUCCESS;
1262 if (!DRI2Connect(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), &driverName, &deviceName)) {
1263 ErrPrint("DRI2 is not supported\n");
1264 s_info.evt_base = 0;
1265 s_info.err_base = 0;
1266 return LB_STATUS_SUCCESS;
1269 if (USE_SW_BACKEND) {
1270 DbgPrint("Fallback to the S/W Backend\n");
1271 s_info.evt_base = 0;
1272 s_info.err_base = 0;
1273 DbgFree(deviceName);
1274 DbgFree(driverName);
1275 return LB_STATUS_SUCCESS;
1278 s_info.fd = open(deviceName, O_RDWR);
1279 DbgFree(deviceName);
1280 DbgFree(driverName);
1281 if (s_info.fd < 0) {
1282 ErrPrint("Failed to open a drm device: (%s)\n", strerror(errno));
1283 s_info.evt_base = 0;
1284 s_info.err_base = 0;
1285 return LB_STATUS_SUCCESS;
1288 drmGetMagic(s_info.fd, &magic);
1289 DbgPrint("DRM Magic: 0x%X\n", magic);
1290 if (!DRI2Authenticate(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), (unsigned int)magic)) {
1291 ErrPrint("Failed to do authenticate for DRI2\n");
1292 if (close(s_info.fd) < 0)
1293 ErrPrint("close: %s\n", strerror(errno));
1295 s_info.evt_base = 0;
1296 s_info.err_base = 0;
1297 return LB_STATUS_SUCCESS;
1300 s_info.slp_bufmgr = tbm_bufmgr_init(s_info.fd);
1301 if (!s_info.slp_bufmgr) {
1302 ErrPrint("Failed to init bufmgr\n");
1303 if (close(s_info.fd) < 0)
1304 ErrPrint("close: %s\n", strerror(errno));
1306 s_info.evt_base = 0;
1307 s_info.err_base = 0;
1308 return LB_STATUS_SUCCESS;
1311 return LB_STATUS_SUCCESS;
1314 HAPI int buffer_handler_fini(void)
1316 if (s_info.fd >= 0) {
1317 if (close(s_info.fd) < 0)
1318 ErrPrint("close: %s\n", strerror(errno));
1322 if (s_info.slp_bufmgr) {
1323 tbm_bufmgr_deinit(s_info.slp_bufmgr);
1324 s_info.slp_bufmgr = NULL;
1327 return LB_STATUS_SUCCESS;
1330 static inline struct buffer *raw_open_file(const char *filename)
1332 struct buffer *buffer;
1336 fd = open(filename, O_RDONLY);
1338 ErrPrint("open: %s\n", strerror(errno));
1342 off = lseek(fd, 0L, SEEK_END);
1343 if (off == (off_t)-1) {
1344 ErrPrint("lseek: %s\n", strerror(errno));
1347 ErrPrint("close: %s\n", strerror(errno));
1352 if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
1353 ErrPrint("lseek: %s\n", strerror(errno));
1356 ErrPrint("close: %s\n", strerror(errno));
1361 buffer = calloc(1, sizeof(*buffer) + off);
1363 ErrPrint("Heap: %s\n", strerror(errno));
1366 ErrPrint("close: %s\n", strerror(errno));
1371 buffer->state = CREATED;
1372 buffer->type = BUFFER_TYPE_FILE;
1374 buffer->info = (void *)off;
1376 if (read(fd, buffer->data, off) < 0) {
1377 ErrPrint("read: %s\n", strerror(errno));
1381 ErrPrint("close: %s\n", strerror(errno));
1387 ErrPrint("close: %s\n", strerror(errno));
1392 static inline int raw_close_file(struct buffer *buffer)
1398 static inline struct buffer *raw_open_shm(int shm)
1400 struct buffer *buffer;
1402 buffer = (struct buffer *)shmat(shm, NULL, SHM_RDONLY);
1403 if (buffer == (struct buffer *)-1) {
1404 ErrPrint("shmat: %s\n", strerror(errno));
1411 static inline int raw_close_shm(struct buffer *buffer)
1415 ret = shmdt(buffer);
1417 ErrPrint("shmdt: %s\n", strerror(errno));
1422 static inline struct buffer *raw_open_pixmap(unsigned int pixmap)
1424 struct buffer *buffer;
1426 buffer = calloc(1, sizeof(*buffer) + sizeof(int));
1428 ErrPrint("Heap: %s\n", strerror(errno));
1432 buffer->state = CREATED;
1433 buffer->type = BUFFER_TYPE_PIXMAP;
1438 static inline int raw_close_pixmap(struct buffer *buffer)
1444 HAPI void *buffer_handler_raw_data(struct buffer *buffer)
1446 if (!buffer || buffer->state != CREATED)
1449 return buffer->data;
1452 HAPI int buffer_handler_raw_size(struct buffer *buffer)
1454 if (!buffer || buffer->state != CREATED)
1457 return (int)buffer->info;
1460 HAPI struct buffer *buffer_handler_raw_open(enum buffer_type buffer_type, void *resource)
1462 struct buffer *handle;
1464 switch (buffer_type) {
1465 case BUFFER_TYPE_SHM:
1466 handle = raw_open_shm((int)resource);
1468 case BUFFER_TYPE_FILE:
1469 handle = raw_open_file(resource);
1471 case BUFFER_TYPE_PIXMAP:
1472 handle = raw_open_pixmap((unsigned int)resource);
1482 HAPI int buffer_handler_raw_close(struct buffer *buffer)
1486 switch (buffer->type) {
1487 case BUFFER_TYPE_SHM:
1488 ret = raw_close_shm(buffer);
1490 case BUFFER_TYPE_FILE:
1491 ret = raw_close_file(buffer);
1493 case BUFFER_TYPE_PIXMAP:
1494 ret = raw_close_pixmap(buffer);