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;
164 DbgPrint("%dx%d size buffer is created\n", w, h);
168 static inline struct buffer *create_pixmap(struct buffer_info *info)
170 struct gem_data *gem;
171 struct buffer *buffer;
177 disp = ecore_x_display_get();
181 parent = DefaultRootWindow(disp);
183 buffer = calloc(1, sizeof(*buffer) + sizeof(*gem));
185 ErrPrint("Heap: %s\n", strerror(errno));
189 gem = (struct gem_data *)buffer->data;
191 buffer->type = BUFFER_TYPE_PIXMAP;
193 buffer->state = CREATED;
195 DbgPrint("Canvas %dx%d - %d is created\n", info->w, info->h, info->pixel_size);
197 gem->attachments[0] = DRI2BufferFrontLeft;
199 gem->w = info->w; /*!< This can be changed by DRI2GetBuffers */
200 gem->h = info->h; /*!< This can be changed by DRI2GetBuffers */
201 gem->depth = info->pixel_size;
205 * 32 Bits is not supported for video playing.
206 * But for the transparent background, use the 32 bits, and give up video.
208 gem->pixmap = XCreatePixmap(disp, parent, info->w, info->h, (info->pixel_size << 3));
209 if (gem->pixmap == (Pixmap)0) {
210 ErrPrint("Failed to create a pixmap\n");
219 memset(&gcv, 0, sizeof(gcv));
220 gc = XCreateGC(disp, gem->pixmap, GCForeground, &gcv);
222 XFillRectangle(disp, gem->pixmap, gc, 0, 0, info->w, info->h);
227 ErrPrint("Unable to clear the pixmap\n");
230 DbgPrint("Pixmap:0x%X is created\n", gem->pixmap);
234 static inline int create_gem(struct buffer *buffer)
236 struct gem_data *gem;
239 disp = ecore_x_display_get();
241 ErrPrint("Failed to get display\n");
242 return LB_STATUS_ERROR_IO;
245 gem = (struct gem_data *)buffer->data;
248 gem->data = calloc(1, gem->w * gem->h * gem->depth);
250 ErrPrint("Heap: %s\n", strerror(errno));
251 return LB_STATUS_ERROR_MEMORY;
254 DbgPrint("DRI2(gem) is not supported - Fallback to the S/W Backend\n");
255 return LB_STATUS_SUCCESS;
258 DRI2CreateDrawable(disp, gem->pixmap);
259 DbgPrint("DRI2CreateDrawable is done\n");
261 gem->dri2_buffer = DRI2GetBuffers(disp, gem->pixmap,
262 &gem->w, &gem->h, gem->attachments, gem->count, &gem->buf_count);
263 if (!gem->dri2_buffer || !gem->dri2_buffer->name) {
264 ErrPrint("Failed to get a gem buffer\n");
265 DRI2DestroyDrawable(disp, gem->pixmap);
266 return LB_STATUS_ERROR_FAULT;
268 DbgPrint("dri2_buffer: %p, name: %p, %dx%d\n",
269 gem->dri2_buffer, gem->dri2_buffer->name, gem->w, gem->h);
270 DbgPrint("dri2_buffer->pitch : %d, buf_count: %d\n",
271 gem->dri2_buffer->pitch, gem->buf_count);
274 * \How can I destroy this?
276 gem->pixmap_bo = tbm_bo_import(s_info.slp_bufmgr, gem->dri2_buffer->name);
277 if (!gem->pixmap_bo) {
278 ErrPrint("Failed to import BO\n");
279 DRI2DestroyDrawable(disp, gem->pixmap);
280 return LB_STATUS_ERROR_FAULT;
283 if (gem->dri2_buffer->pitch != gem->w * gem->depth) {
284 gem->compensate_data = calloc(1, gem->w * gem->h * gem->depth);
285 if (!gem->compensate_data) {
286 ErrPrint("Failed to allocate heap\n");
288 DbgPrint("Allocate compensate buffer %p(%dx%d %d)\n",
289 gem->compensate_data,
290 gem->w, gem->h, gem->depth);
294 return LB_STATUS_SUCCESS;
297 static inline void *acquire_gem(struct buffer *buffer)
299 struct gem_data *gem;
304 gem = (struct gem_data *)buffer->data;
306 DbgPrint("GEM is not supported - Use the fake gem buffer\n");
308 if (!gem->pixmap_bo) {
309 DbgPrint("GEM is not created\n");
314 tbm_bo_handle handle;
317 ErrPrint("Already acquired. but the buffer is not valid\n");
321 handle = tbm_bo_map(gem->pixmap_bo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE);
322 gem->data = handle.ptr;
330 * If there is a compensate canvas buffer,
333 return gem->compensate_data ? gem->compensate_data : gem->data;
336 static inline void release_gem(struct buffer *buffer)
338 struct gem_data *gem;
340 gem = (struct gem_data *)buffer->data;
341 if (s_info.fd >= 0 && !gem->pixmap_bo) {
342 DbgPrint("GEM is not created\n");
347 if (gem->refcnt > 0) {
348 ErrPrint("Reference count is not valid %d\n", gem->refcnt);
355 if (gem->refcnt == 0) {
357 DbgPrint("S/W Gem buffer has no reference\n");
361 * Update the gem buffer using compensate data buffer if it is exists
363 if (gem->compensate_data) {
370 pixel = gem->compensate_data;
371 gem_pixel = gem->data;
372 gap = gem->dri2_buffer->pitch - (gem->w * gem->depth);
374 for (y = 0; y < gem->h; y++) {
375 for (x = 0; x < gem->w; x++)
376 *gem_pixel++ = *pixel++;
378 gem_pixel = (int *)(((char *)gem_pixel) + gap);
383 tbm_bo_unmap(gem->pixmap_bo);
387 } else if (gem->refcnt < 0) {
388 DbgPrint("Invalid refcnt: %d (reset)\n", gem->refcnt);
393 static inline int destroy_pixmap(struct buffer *buffer)
395 struct gem_data *gem;
397 gem = (struct gem_data *)buffer->data;
402 disp = ecore_x_display_get();
404 return LB_STATUS_ERROR_IO;
406 DbgPrint("Free pixmap 0x%X\n", gem->pixmap);
407 XFreePixmap(disp, gem->pixmap);
410 buffer->state = DESTROYED;
412 return LB_STATUS_SUCCESS;
415 static inline int destroy_gem(struct buffer *buffer)
417 struct gem_data *gem;
420 return LB_STATUS_ERROR_INVALID;
423 * Forcely release the acquire_buffer.
425 gem = (struct gem_data *)buffer->data;
427 return LB_STATUS_ERROR_FAULT;
429 if (s_info.fd >= 0) {
430 if (gem->compensate_data) {
431 DbgPrint("Release compensate buffer %p\n", gem->compensate_data);
432 free(gem->compensate_data);
433 gem->compensate_data = NULL;
436 if (gem->pixmap_bo) {
437 DbgPrint("unref pixmap bo\n");
438 tbm_bo_unref(gem->pixmap_bo);
439 gem->pixmap_bo = NULL;
441 DbgPrint("DRI2DestroyDrawable\n");
442 DRI2DestroyDrawable(ecore_x_display_get(), gem->pixmap);
444 } else if (gem->data) {
445 DbgPrint("Release fake gem buffer\n");
450 return LB_STATUS_SUCCESS;
453 static inline int load_file_buffer(struct buffer_info *info)
455 struct buffer *buffer;
461 len = strlen(IMAGE_PATH) + 40;
462 new_id = malloc(len);
464 ErrPrint("Heap: %s\n", strerror(errno));
465 return LB_STATUS_ERROR_MEMORY;
468 timestamp = util_timestamp();
469 snprintf(new_id, len, SCHEMA_FILE "%s%lf", IMAGE_PATH, timestamp);
471 size = sizeof(*buffer) + info->w * info->h * info->pixel_size;
473 ErrPrint("Canvas buffer size is ZERO\n");
475 return LB_STATUS_ERROR_INVALID;
478 buffer = calloc(1, size);
480 ErrPrint("Failed to allocate buffer\n");
482 return LB_STATUS_ERROR_MEMORY;
485 buffer->type = BUFFER_TYPE_FILE;
487 buffer->state = CREATED;
492 info->buffer = buffer;
495 DbgPrint("FILE type %d created\n", size);
496 return LB_STATUS_SUCCESS;
499 static inline int load_shm_buffer(struct buffer_info *info)
503 struct buffer *buffer; /* Just for getting a size */
507 size = info->w * info->h * info->pixel_size;
509 ErrPrint("Invalid buffer size\n");
510 return LB_STATUS_ERROR_INVALID;
513 id = shmget(IPC_PRIVATE, size + sizeof(*buffer), IPC_CREAT | 0666);
515 ErrPrint("shmget: %s\n", strerror(errno));
516 return LB_STATUS_ERROR_FAULT;
519 buffer = shmat(id, NULL, 0);
520 if (buffer == (void *)-1) {
521 ErrPrint("%s shmat: %s\n", info->id, strerror(errno));
523 if (shmctl(id, IPC_RMID, 0) < 0)
524 ErrPrint("%s shmctl: %s\n", info->id, strerror(errno));
526 return LB_STATUS_ERROR_FAULT;
529 buffer->type = BUFFER_TYPE_SHM;
531 buffer->state = CREATED; /*!< Needless */
532 buffer->info = NULL; /*!< This has not to be used, every process will see this. So, don't try to save anything on here */
534 len = strlen(SCHEMA_SHM) + 30; /* strlen("shm://") + 30 */
536 new_id = malloc(len);
538 ErrPrint("Heap: %s\n", strerror(errno));
539 if (shmdt(buffer) < 0)
540 ErrPrint("shmdt: %s\n", strerror(errno));
542 if (shmctl(id, IPC_RMID, 0) < 0)
543 ErrPrint("shmctl: %s\n", strerror(errno));
545 return LB_STATUS_ERROR_MEMORY;
548 snprintf(new_id, len, SCHEMA_SHM "%d", id);
552 info->buffer = buffer;
554 return LB_STATUS_SUCCESS;
557 static inline int load_pixmap_buffer(struct buffer_info *info)
559 struct buffer *buffer;
560 struct gem_data *gem;
566 * Before call the buffer_handler_pixmap_ref function,
567 * You should make sure that the is_loaded value is toggled (1)
568 * Or the buffer_handler_pixmap_ref function will return NULL
573 DbgPrint("Buffer is already exists, but override it with new one\n");
575 buffer = buffer_handler_pixmap_ref(info);
577 DbgPrint("Failed to make a reference of a pixmap\n");
579 return LB_STATUS_ERROR_FAULT;
582 len = strlen(SCHEMA_PIXMAP) + 30; /* strlen("pixmap://") + 30 */
583 new_id = malloc(len);
586 ErrPrint("Heap: %s\n", strerror(errno));
587 buffer_handler_pixmap_unref(buffer);
588 return LB_STATUS_ERROR_MEMORY;
591 DbgPrint("Releaseo old id (%s)\n", info->id);
595 gem = (struct gem_data *)buffer->data;
596 DbgPrint("gem pointer: %p\n", gem);
598 snprintf(info->id, len, SCHEMA_PIXMAP "%d", (int)gem->pixmap);
599 DbgPrint("info->id: %s\n", info->id);
601 return LB_STATUS_SUCCESS;
604 HAPI int buffer_handler_load(struct buffer_info *info)
609 DbgPrint("buffer handler is nil\n");
610 return LB_STATUS_ERROR_INVALID;
613 if (info->is_loaded) {
614 DbgPrint("Buffer is already loaded\n");
615 return LB_STATUS_SUCCESS;
618 switch (info->type) {
619 case BUFFER_TYPE_FILE:
620 ret = load_file_buffer(info);
622 case BUFFER_TYPE_SHM:
623 ret = load_shm_buffer(info);
625 case BUFFER_TYPE_PIXMAP:
626 ret = load_pixmap_buffer(info);
629 ErrPrint("Invalid buffer\n");
630 ret = LB_STATUS_ERROR_INVALID;
637 static inline int unload_file_buffer(struct buffer_info *info)
642 new_id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
644 ErrPrint("Heap: %s\n", strerror(errno));
645 return LB_STATUS_ERROR_MEMORY;
648 DbgFree(info->buffer);
651 path = util_uri_to_path(info->id);
652 if (path && unlink(path) < 0)
653 ErrPrint("unlink: %s\n", strerror(errno));
657 return LB_STATUS_SUCCESS;
660 static inline int unload_shm_buffer(struct buffer_info *info)
665 new_id = strdup(SCHEMA_SHM "-1");
667 ErrPrint("Heap: %s\n", strerror(errno));
668 return LB_STATUS_ERROR_MEMORY;
671 if (sscanf(info->id, SCHEMA_SHM "%d", &id) != 1) {
672 ErrPrint("%s Invalid ID\n", info->id);
674 return LB_STATUS_ERROR_INVALID;
678 ErrPrint("(%s) Invalid id: %d\n", info->id, id);
680 return LB_STATUS_ERROR_INVALID;
683 if (shmdt(info->buffer) < 0)
684 ErrPrint("Detach shm: %s\n", strerror(errno));
686 if (shmctl(id, IPC_RMID, 0) < 0)
687 ErrPrint("Remove shm: %s\n", strerror(errno));
693 return LB_STATUS_SUCCESS;
696 static inline int unload_pixmap_buffer(struct buffer_info *info)
701 new_id = strdup(SCHEMA_PIXMAP "0");
703 ErrPrint("Heap: %s\n", strerror(errno));
704 return LB_STATUS_ERROR_MEMORY;
707 if (sscanf(info->id, SCHEMA_PIXMAP "%d", &id) != 1) {
708 ErrPrint("Invalid ID (%s)\n", info->id);
710 return LB_STATUS_ERROR_INVALID;
714 ErrPrint("(%s) Invalid id: %d\n", info->id, id);
716 return LB_STATUS_ERROR_INVALID;
720 * Decrease the reference counter.
722 buffer_handler_pixmap_unref(info->buffer);
726 * Just clear the info->buffer.
727 * It will be reallocated again.
733 return LB_STATUS_SUCCESS;
736 HAPI int buffer_handler_unload(struct buffer_info *info)
741 DbgPrint("buffer handler is nil\n");
742 return LB_STATUS_ERROR_INVALID;
745 if (!info->is_loaded) {
746 ErrPrint("Buffer is not loaded\n");
747 return LB_STATUS_ERROR_INVALID;
750 switch (info->type) {
751 case BUFFER_TYPE_FILE:
752 ret = unload_file_buffer(info);
754 case BUFFER_TYPE_SHM:
755 ret = unload_shm_buffer(info);
757 case BUFFER_TYPE_PIXMAP:
758 ret = unload_pixmap_buffer(info);
761 ErrPrint("Invalid buffer\n");
762 ret = LB_STATUS_ERROR_INVALID;
772 HAPI int buffer_handler_destroy(struct buffer_info *info)
775 struct buffer *buffer;
778 DbgPrint("Buffer is not created yet. info is nil\n");
779 return LB_STATUS_SUCCESS;
782 EINA_LIST_FOREACH(s_info.pixmap_list, l, buffer) {
783 if (buffer->info == info)
787 buffer_handler_unload(info);
790 return LB_STATUS_SUCCESS;
793 HAPI const char *buffer_handler_id(const struct buffer_info *info)
795 return info ? info->id : "";
798 HAPI enum buffer_type buffer_handler_type(const struct buffer_info *info)
800 return info ? info->type : BUFFER_TYPE_ERROR;
803 HAPI void *buffer_handler_fb(struct buffer_info *info)
805 struct buffer *buffer;
810 buffer = info->buffer;
812 if (info->type == BUFFER_TYPE_PIXMAP) {
818 canvas = buffer_handler_pixmap_acquire_buffer(info);
819 ret = buffer_handler_pixmap_release_buffer(canvas);
820 DbgPrint("Canvas %p(%d) (released but still in use)\n", canvas, ret);
827 HAPI int buffer_handler_pixmap(const struct buffer_info *info)
830 struct gem_data *gem;
833 ErrPrint("Inavlid buffer handler\n");
837 if (info->type != BUFFER_TYPE_PIXMAP) {
838 ErrPrint("Invalid buffer type\n");
842 buf = (struct buffer *)info->buffer;
844 ErrPrint("Invalid buffer data\n");
848 gem = (struct gem_data *)buf->data;
852 HAPI void *buffer_handler_pixmap_acquire_buffer(struct buffer_info *info)
854 struct buffer *buffer;
856 if (!info || !info->is_loaded) {
857 ErrPrint("Buffer is not loaded\n");
861 buffer = buffer_handler_pixmap_ref(info);
865 return acquire_gem(buffer);
868 HAPI void *buffer_handler_pixmap_buffer(struct buffer_info *info)
870 struct buffer *buffer;
871 struct gem_data *gem;
876 if (!info->is_loaded) {
877 ErrPrint("Buffer is not loaded\n");
881 buffer = info->buffer;
885 gem = (struct gem_data *)buffer->data;
886 return gem->compensate_data ? gem->compensate_data : gem->data;
890 * \return "buffer" object (Not the buffer_info)
892 HAPI void *buffer_handler_pixmap_ref(struct buffer_info *info)
894 struct buffer *buffer;
896 if (!info->is_loaded) {
897 ErrPrint("Buffer is not loaded\n");
901 if (info->type != BUFFER_TYPE_PIXMAP) {
902 ErrPrint("Buffer type is not matched\n");
906 buffer = info->buffer;
910 buffer = create_pixmap(info);
912 DbgPrint("Failed to create a pixmap\n");
916 info->buffer = buffer;
919 struct pkg_info *pkg;
921 if (instance_lb_buffer(info->inst) == info) {
922 pkg = instance_package(info->inst);
923 if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
924 DbgPrint("Doesn't need to create gem for LB\n");
927 } else if (instance_pd_buffer(info->inst) == info) {
928 pkg = instance_package(info->inst);
929 if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
930 DbgPrint("Doesn't need to create gem for PD\n");
939 } else if (buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
940 ErrPrint("Invalid buffer\n");
942 } else if (buffer->refcnt > 0) {
947 s_info.pixmap_list = eina_list_append(s_info.pixmap_list, buffer);
954 HAPI void *buffer_handler_pixmap_find(int pixmap)
956 struct buffer *buffer;
957 struct gem_data *gem;
964 EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
965 if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
966 s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
967 DbgPrint("Invalid buffer (List Removed: %p)\n", buffer);
971 gem = (struct gem_data *)buffer->data;
972 if (gem->pixmap == pixmap)
979 HAPI int buffer_handler_pixmap_release_buffer(void *canvas)
981 struct buffer *buffer;
982 struct gem_data *gem;
988 return LB_STATUS_ERROR_INVALID;
990 EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
991 if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
992 s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
996 gem = (struct gem_data *)buffer->data;
997 _ptr = gem->compensate_data ? gem->compensate_data : gem->data;
1002 if (_ptr == canvas) {
1003 release_gem(buffer);
1004 buffer_handler_pixmap_unref(buffer);
1005 return LB_STATUS_SUCCESS;
1009 return LB_STATUS_ERROR_NOT_EXIST;
1015 * \return Return NULL if the buffer is in still uses.
1016 * Return buffer_ptr if it needs to destroy
1018 HAPI int buffer_handler_pixmap_unref(void *buffer_ptr)
1020 struct buffer *buffer = buffer_ptr;
1021 struct buffer_info *info;
1024 if (buffer->refcnt > 0)
1025 return LB_STATUS_SUCCESS; /* Return NULL means, gem buffer still in use */
1027 s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
1029 info = buffer->info;
1031 if (destroy_gem(buffer) < 0)
1032 ErrPrint("Failed to destroy gem buffer\n");
1034 if (destroy_pixmap(buffer) < 0)
1035 ErrPrint("Failed to destroy pixmap\n");
1037 if (info && info->buffer == buffer)
1038 info->buffer = NULL;
1040 return LB_STATUS_SUCCESS;
1043 HAPI int buffer_handler_is_loaded(const struct buffer_info *info)
1045 return info ? info->is_loaded : 0;
1048 HAPI void buffer_handler_update_size(struct buffer_info *info, int w, int h)
1057 HAPI int buffer_handler_resize(struct buffer_info *info, int w, int h)
1062 ErrPrint("Invalid handler\n");
1063 return LB_STATUS_ERROR_INVALID;
1066 if (info->w == w && info->h == h) {
1067 DbgPrint("No changes\n");
1068 return LB_STATUS_SUCCESS;
1071 buffer_handler_update_size(info, w, h);
1073 if (!info->is_loaded) {
1074 DbgPrint("Not yet loaded, just update the size [%dx%d]\n", w, h);
1075 return LB_STATUS_SUCCESS;
1078 ret = buffer_handler_unload(info);
1080 ErrPrint("Unload: %d\n", ret);
1082 ret = buffer_handler_load(info);
1084 ErrPrint("Load: %d\n", ret);
1086 return LB_STATUS_SUCCESS;
1089 HAPI int buffer_handler_get_size(struct buffer_info *info, int *w, int *h)
1092 return LB_STATUS_ERROR_INVALID;
1099 return LB_STATUS_SUCCESS;
1102 HAPI struct inst_info *buffer_handler_instance(struct buffer_info *info)
1109 * Only for used S/W Backend
1111 static inline int sync_for_pixmap(struct buffer *buffer)
1117 struct gem_data *gem;
1121 if (buffer->state != CREATED) {
1122 ErrPrint("Invalid state of a FB\n");
1123 return LB_STATUS_ERROR_INVALID;
1126 if (buffer->type != BUFFER_TYPE_PIXMAP) {
1127 DbgPrint("Invalid buffer\n");
1128 return LB_STATUS_SUCCESS;
1131 disp = ecore_x_display_get();
1133 ErrPrint("Failed to get a display\n");
1134 return LB_STATUS_ERROR_FAULT;
1137 gem = (struct gem_data *)buffer->data;
1138 if (gem->w == 0 || gem->h == 0) {
1139 DbgPrint("Nothing can be sync\n");
1140 return LB_STATUS_SUCCESS;
1143 si.shmid = shmget(IPC_PRIVATE, gem->w * gem->h * gem->depth, IPC_CREAT | 0666);
1145 ErrPrint("shmget: %s\n", strerror(errno));
1146 return LB_STATUS_ERROR_FAULT;
1149 si.readOnly = False;
1150 si.shmaddr = shmat(si.shmid, NULL, 0);
1151 if (si.shmaddr == (void *)-1) {
1152 if (shmctl(si.shmid, IPC_RMID, 0) < 0)
1153 ErrPrint("shmctl: %s\n", strerror(errno));
1154 return LB_STATUS_ERROR_FAULT;
1157 screen = DefaultScreenOfDisplay(disp);
1158 visual = DefaultVisualOfScreen(screen);
1161 * XCreatePixmap can only uses 24 bits depth only.
1163 xim = XShmCreateImage(disp, visual, (gem->depth << 3), ZPixmap, NULL, &si, gem->w, gem->h);
1165 if (shmdt(si.shmaddr) < 0)
1166 ErrPrint("shmdt: %s\n", strerror(errno));
1168 if (shmctl(si.shmid, IPC_RMID, 0) < 0)
1169 ErrPrint("shmctl: %s\n", strerror(errno));
1170 return LB_STATUS_ERROR_FAULT;
1173 xim->data = si.shmaddr;
1174 XShmAttach(disp, &si);
1177 gc = XCreateGC(disp, gem->pixmap, 0, NULL);
1179 XShmDetach(disp, &si);
1182 if (shmdt(si.shmaddr) < 0)
1183 ErrPrint("shmdt: %s\n", strerror(errno));
1185 if (shmctl(si.shmid, IPC_RMID, 0) < 0)
1186 ErrPrint("shmctl: %s\n", strerror(errno));
1188 return LB_STATUS_ERROR_FAULT;
1191 memcpy(xim->data, gem->data, gem->w * gem->h * gem->depth);
1194 * \note Do not send the event.
1195 * Instead of X event, master will send the updated event to the viewer
1197 XShmPutImage(disp, gem->pixmap, gc, xim, 0, 0, 0, 0, gem->w, gem->h, False);
1201 XShmDetach(disp, &si);
1204 if (shmdt(si.shmaddr) < 0)
1205 ErrPrint("shmdt: %s\n", strerror(errno));
1207 if (shmctl(si.shmid, IPC_RMID, 0) < 0)
1208 ErrPrint("shmctl: %s\n", strerror(errno));
1210 return LB_STATUS_SUCCESS;
1213 HAPI void buffer_handler_flush(struct buffer_info *info)
1217 struct buffer *buffer;
1219 if (!info || !info->buffer)
1222 buffer = info->buffer;
1224 if (buffer->type == BUFFER_TYPE_PIXMAP) {
1225 if (s_info.fd > 0) {
1227 XserverRegion region;
1231 rect.width = info->w;
1232 rect.height = info->h;
1234 region = XFixesCreateRegion(ecore_x_display_get(), &rect, 1);
1235 XDamageAdd(ecore_x_display_get(), buffer_handler_pixmap(info), region);
1236 XFixesDestroyRegion(ecore_x_display_get(), region);
1237 XFlush(ecore_x_display_get());
1239 if (sync_for_pixmap(buffer) < 0)
1240 ErrPrint("Failed to sync via S/W Backend\n");
1242 } else if (buffer->type == BUFFER_TYPE_FILE) {
1243 fd = open(util_uri_to_path(info->id), O_WRONLY | O_CREAT, 0644);
1245 ErrPrint("%s open falied: %s\n", util_uri_to_path(info->id), strerror(errno));
1249 size = info->w * info->h * info->pixel_size;
1250 if (write(fd, info->buffer, size) != size)
1251 ErrPrint("Write is not completed: %s\n", strerror(errno));
1255 DbgPrint("Flush nothing\n");
1259 HAPI int buffer_handler_init(void)
1261 int dri2Major, dri2Minor;
1262 char *driverName, *deviceName;
1265 if (!DRI2QueryExtension(ecore_x_display_get(), &s_info.evt_base, &s_info.err_base)) {
1266 DbgPrint("DRI2 is not supported\n");
1267 return LB_STATUS_SUCCESS;
1270 if (!DRI2QueryVersion(ecore_x_display_get(), &dri2Major, &dri2Minor)) {
1271 DbgPrint("DRI2 is not supported\n");
1272 s_info.evt_base = 0;
1273 s_info.err_base = 0;
1274 return LB_STATUS_SUCCESS;
1277 if (!DRI2Connect(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), &driverName, &deviceName)) {
1278 DbgPrint("DRI2 is not supported\n");
1279 s_info.evt_base = 0;
1280 s_info.err_base = 0;
1281 return LB_STATUS_SUCCESS;
1284 DbgPrint("Open: %s (driver: %s)", deviceName, driverName);
1286 if (USE_SW_BACKEND) {
1287 DbgPrint("Fallback to the S/W Backend\n");
1288 s_info.evt_base = 0;
1289 s_info.err_base = 0;
1290 DbgFree(deviceName);
1291 DbgFree(driverName);
1292 return LB_STATUS_SUCCESS;
1295 s_info.fd = open(deviceName, O_RDWR);
1296 DbgFree(deviceName);
1297 DbgFree(driverName);
1298 if (s_info.fd < 0) {
1299 DbgPrint("Failed to open a drm device: (%s)\n", strerror(errno));
1300 s_info.evt_base = 0;
1301 s_info.err_base = 0;
1302 return LB_STATUS_SUCCESS;
1305 drmGetMagic(s_info.fd, &magic);
1306 DbgPrint("DRM Magic: 0x%X\n", magic);
1307 if (!DRI2Authenticate(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), (unsigned int)magic)) {
1308 DbgPrint("Failed to do authenticate for DRI2\n");
1311 s_info.evt_base = 0;
1312 s_info.err_base = 0;
1313 return LB_STATUS_SUCCESS;
1316 s_info.slp_bufmgr = tbm_bufmgr_init(s_info.fd);
1317 if (!s_info.slp_bufmgr) {
1318 DbgPrint("Failed to init bufmgr\n");
1321 s_info.evt_base = 0;
1322 s_info.err_base = 0;
1323 return LB_STATUS_SUCCESS;
1326 return LB_STATUS_SUCCESS;
1329 HAPI int buffer_handler_fini(void)
1331 if (s_info.fd >= 0) {
1336 if (s_info.slp_bufmgr) {
1337 tbm_bufmgr_deinit(s_info.slp_bufmgr);
1338 s_info.slp_bufmgr = NULL;
1341 return LB_STATUS_SUCCESS;